diff options
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/Kconfig | 2 | ||||
-rw-r--r-- | drivers/scsi/libsas/Makefile | 2 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 181 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_discover.c | 26 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_event.c | 134 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 117 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_host_smp.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 82 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 16 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_phy.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_port.c | 79 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 374 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_task.c | 18 |
13 files changed, 719 insertions, 316 deletions
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig index 5c6a5eff2f8e..c640535d1ac0 100644 --- a/drivers/scsi/libsas/Kconfig +++ b/drivers/scsi/libsas/Kconfig @@ -10,7 +10,6 @@ config SCSI_SAS_LIBSAS tristate "SAS Domain Transport Attributes" depends on SCSI select SCSI_SAS_ATTRS - select BLK_DEV_BSGLIB help This provides transport specific helpers for SAS drivers which use the domain device construct (like the aic94xxx). @@ -19,6 +18,7 @@ config SCSI_SAS_ATA bool "ATA support for libsas (requires libata)" depends on SCSI_SAS_LIBSAS depends on ATA = y || ATA = SCSI_SAS_LIBSAS + select SATA_HOST help Builds in ATA support into libsas. Will necessitate the loading of libata along with libsas. diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile index e63a54f5ab8c..9dc32736cf21 100644 --- a/drivers/scsi/libsas/Makefile +++ b/drivers/scsi/libsas/Makefile @@ -18,4 +18,4 @@ libsas-y += sas_init.o \ libsas-$(CONFIG_SCSI_SAS_ATA) += sas_ata.o libsas-$(CONFIG_SCSI_SAS_HOST_SMP) += sas_host_smp.o -ccflags-y := -DDEBUG +ccflags-y := -DDEBUG -I$(srctree)/drivers/scsi diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index c5a828a041e0..d35c9296f738 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -20,8 +20,8 @@ #include <scsi/scsi.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_sas.h> -#include "../scsi_sas_internal.h" -#include "../scsi_transport_api.h" +#include "scsi_sas_internal.h" +#include "scsi_transport_api.h" #include <scsi/scsi_eh.h> static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts) @@ -35,46 +35,38 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts) /* ts->resp == SAS_TASK_COMPLETE */ /* task delivered, what happened afterwards? */ switch (ts->stat) { - case SAS_DEV_NO_RESPONSE: - return AC_ERR_TIMEOUT; - - case SAS_INTERRUPTED: - case SAS_PHY_DOWN: - case SAS_NAK_R_ERR: - return AC_ERR_ATA_BUS; - - - case SAS_DATA_UNDERRUN: - /* - * Some programs that use the taskfile interface - * (smartctl in particular) can cause underrun - * problems. Ignore these errors, perhaps at our - * peril. - */ - return 0; - - case SAS_DATA_OVERRUN: - case SAS_QUEUE_FULL: - case SAS_DEVICE_UNKNOWN: - case SAS_SG_ERR: - return AC_ERR_INVALID; - - case SAS_OPEN_TO: - case SAS_OPEN_REJECT: - pr_warn("%s: Saw error %d. What to do?\n", - __func__, ts->stat); - return AC_ERR_OTHER; - - case SAM_STAT_CHECK_CONDITION: - case SAS_ABORTED_TASK: - return AC_ERR_DEV; - - case SAS_PROTO_RESPONSE: - /* This means the ending_fis has the error - * value; return 0 here to collect it */ - return 0; - default: - return 0; + case SAS_DEV_NO_RESPONSE: + return AC_ERR_TIMEOUT; + case SAS_INTERRUPTED: + case SAS_PHY_DOWN: + case SAS_NAK_R_ERR: + return AC_ERR_ATA_BUS; + case SAS_DATA_UNDERRUN: + /* + * Some programs that use the taskfile interface + * (smartctl in particular) can cause underrun + * problems. Ignore these errors, perhaps at our + * peril. + */ + return 0; + case SAS_DATA_OVERRUN: + case SAS_QUEUE_FULL: + case SAS_DEVICE_UNKNOWN: + case SAS_OPEN_TO: + case SAS_OPEN_REJECT: + pr_warn("%s: Saw error %d. What to do?\n", + __func__, ts->stat); + return AC_ERR_OTHER; + case SAM_STAT_CHECK_CONDITION: + case SAS_ABORTED_TASK: + return AC_ERR_DEV; + case SAS_PROTO_RESPONSE: + /* This means the ending_fis has the error + * value; return 0 here to collect it + */ + return 0; + default: + return 0; } } @@ -122,9 +114,10 @@ static void sas_ata_task_done(struct sas_task *task) } } - if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || - ((stat->stat == SAM_STAT_CHECK_CONDITION && - dev->sata_dev.class == ATA_DEV_ATAPI))) { + if (stat->stat == SAS_PROTO_RESPONSE || + stat->stat == SAS_SAM_STAT_GOOD || + (stat->stat == SAS_SAM_STAT_CHECK_CONDITION && + dev->sata_dev.class == ATA_DEV_ATAPI)) { memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE); if (!link->sactive) { @@ -160,6 +153,7 @@ qc_already_gone: } static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) + __must_hold(ap->lock) { struct sas_task *task; struct scatterlist *sg; @@ -185,14 +179,9 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) task->task_proto = SAS_PROTOCOL_STP; task->task_done = sas_ata_task_done; - if (qc->tf.command == ATA_CMD_FPDMA_WRITE || - qc->tf.command == ATA_CMD_FPDMA_READ || - qc->tf.command == ATA_CMD_FPDMA_RECV || - qc->tf.command == ATA_CMD_FPDMA_SEND || - qc->tf.command == ATA_CMD_NCQ_NON_DATA) { - /* Need to zero out the tag libata assigned us */ + /* For NCQ commands, zero out the tag libata assigned us */ + if (ata_is_ncq(qc->tf.protocol)) qc->tf.nsect = 0; - } ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, (u8 *)&task->ata_task.fis); task->uldd_task = qc; @@ -200,18 +189,19 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len); task->total_xfer_len = qc->nbytes; task->num_scatter = qc->n_elem; + task->data_dir = qc->dma_dir; + } else if (!ata_is_data(qc->tf.protocol)) { + task->data_dir = DMA_NONE; } else { for_each_sg(qc->sg, sg, qc->n_elem, si) xfer += sg_dma_len(sg); task->total_xfer_len = xfer; task->num_scatter = si; + task->data_dir = qc->dma_dir; } - - task->data_dir = qc->dma_dir; task->scatter = qc->sg; task->ata_task.retry_count = 1; - task->task_state_flags = SAS_TASK_STATE_PENDING; qc->lldd_task = task; task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol); @@ -323,7 +313,7 @@ static int smp_ata_check_ready(struct ata_link *link) case SAS_END_DEVICE: if (ex_phy->attached_sata_dev) return sas_ata_clear_pending(dev, ex_phy); - /* fall through */ + fallthrough; default: return -ENODEV; } @@ -368,22 +358,14 @@ static int sas_ata_printk(const char *level, const struct domain_device *ddev, return r; } -static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class, - unsigned long deadline) +int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline) { - int ret = 0, res; - struct sas_phy *phy; - struct ata_port *ap = link->ap; + struct sata_device *sata_dev = &dev->sata_dev; int (*check_ready)(struct ata_link *link); - struct domain_device *dev = ap->private_data; - struct sas_internal *i = dev_to_sas_internal(dev); - - res = i->dft->lldd_I_T_nexus_reset(dev); - if (res == -ENODEV) - return res; - - if (res != TMF_RESP_FUNC_COMPLETE) - sas_ata_printk(KERN_DEBUG, dev, "Unable to reset ata device?\n"); + struct ata_port *ap = sata_dev->ap; + struct ata_link *link = &ap->link; + struct sas_phy *phy; + int ret; phy = sas_get_local_phy(dev); if (scsi_is_sas_phy_local(phy)) @@ -396,6 +378,27 @@ static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class, if (ret && ret != -EAGAIN) sas_ata_printk(KERN_ERR, dev, "reset failed (errno=%d)\n", ret); + return ret; +} +EXPORT_SYMBOL_GPL(sas_ata_wait_after_reset); + +static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct domain_device *dev = ap->private_data; + struct sas_internal *i = dev_to_sas_internal(dev); + int ret; + + ret = i->dft->lldd_I_T_nexus_reset(dev); + if (ret == -ENODEV) + return ret; + + if (ret != TMF_RESP_FUNC_COMPLETE) + sas_ata_printk(KERN_DEBUG, dev, "Unable to reset ata device?\n"); + + ret = sas_ata_wait_after_reset(dev, deadline); + *class = dev->sata_dev.class; ap->cbl = ATA_CBL_SATA; @@ -506,10 +509,23 @@ void sas_ata_end_eh(struct ata_port *ap) spin_unlock_irqrestore(&ha->lock, flags); } +static int sas_ata_prereset(struct ata_link *link, unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct domain_device *dev = ap->private_data; + struct sas_phy *local_phy = sas_get_local_phy(dev); + int res = 0; + + if (!local_phy->enabled || test_bit(SAS_DEV_GONE, &dev->state)) + res = -ENOENT; + sas_put_local_phy(local_phy); + + return res; +} + static struct ata_port_operations sas_sata_ops = { - .prereset = ata_std_prereset, + .prereset = sas_ata_prereset, .hardreset = sas_ata_hard_reset, - .postreset = ata_std_postreset, .error_handler = ata_std_error_handler, .post_internal_cmd = sas_ata_post_internal, .qc_defer = ata_std_qc_defer, @@ -585,7 +601,7 @@ void sas_ata_task_abort(struct sas_task *task) /* Bounce SCSI-initiated commands to the SCSI EH */ if (qc->scsicmd) { - blk_abort_request(qc->scsicmd->request); + blk_abort_request(scsi_cmd_to_rq(qc->scsicmd)); return; } @@ -709,19 +725,13 @@ void sas_resume_sata(struct asd_sas_port *port) */ int sas_discover_sata(struct domain_device *dev) { - int res; - if (dev->dev_type == SAS_SATA_PM) return -ENODEV; dev->sata_dev.class = sas_get_ata_command_set(dev); sas_fill_in_rphy(dev, dev->rphy); - res = sas_notify_lldd_dev_found(dev); - if (res) - return res; - - return 0; + return sas_notify_lldd_dev_found(dev); } static void async_sas_ata_eh(void *data, async_cookie_t cookie) @@ -778,8 +788,7 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost) sas_enable_revalidation(sas_ha); } -void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, - struct list_head *done_q) +void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q) { struct scsi_cmnd *cmd, *n; struct domain_device *eh_dev; @@ -851,3 +860,11 @@ void sas_ata_wait_eh(struct domain_device *dev) ap = dev->sata_dev.ap; ata_port_wait_eh(ap); } + +int sas_execute_ata_cmd(struct domain_device *device, u8 *fis, int force_phy_id) +{ + struct sas_tmf_task tmf_task = {}; + return sas_execute_tmf(device, fis, sizeof(struct host_to_dev_fis), + force_phy_id, &tmf_task); +} +EXPORT_SYMBOL_GPL(sas_execute_ata_cmd); diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index daf951b0b3f5..d5bc1314c341 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -8,7 +8,6 @@ #include <linux/scatterlist.h> #include <linux/slab.h> -#include <linux/async.h> #include <scsi/scsi_host.h> #include <scsi/scsi_eh.h> #include "sas_internal.h" @@ -16,7 +15,7 @@ #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_sas.h> #include <scsi/sas_ata.h> -#include "../scsi_sas_internal.h" +#include "scsi_sas_internal.h" /* ---------- Basic task processing for discovery purposes ---------- */ @@ -75,7 +74,7 @@ static int sas_get_port_device(struct asd_sas_port *port) struct dev_to_host_fis *fis = (struct dev_to_host_fis *) dev->frame_rcvd; if (fis->interrupt_reason == 1 && fis->lbal == 1 && - fis->byte_count_low==0x69 && fis->byte_count_high == 0x96 + fis->byte_count_low == 0x69 && fis->byte_count_high == 0x96 && (fis->device & ~0x10) == 0) dev->dev_type = SAS_SATA_PM; else @@ -108,7 +107,7 @@ static int sas_get_port_device(struct asd_sas_port *port) rphy = NULL; break; } - /* fall through */ + fallthrough; case SAS_END_DEVICE: rphy = sas_end_device_alloc(port->port); break; @@ -182,10 +181,11 @@ int sas_notify_lldd_dev_found(struct domain_device *dev) pr_warn("driver on host %s cannot handle device %016llx, error:%d\n", dev_name(sas_ha->dev), SAS_ADDR(dev->sas_addr), res); + return res; } set_bit(SAS_DEV_FOUND, &dev->state); kref_get(&dev->kref); - return res; + return 0; } @@ -277,13 +277,7 @@ static void sas_resume_devices(struct work_struct *work) */ int sas_discover_end_dev(struct domain_device *dev) { - int res; - - res = sas_notify_lldd_dev_found(dev); - if (res) - return res; - - return 0; + return sas_notify_lldd_dev_found(dev); } /* ---------- Device registration and unregistration ---------- */ @@ -466,7 +460,7 @@ static void sas_discover_domain(struct work_struct *work) break; #else pr_notice("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n"); - /* Fall through */ + fallthrough; #endif /* Fall through - only for the #else condition above. */ default: @@ -551,19 +545,17 @@ static void sas_chain_event(int event, unsigned long *pending, } } -int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) +void sas_discover_event(struct asd_sas_port *port, enum discover_event ev) { struct sas_discovery *disc; if (!port) - return 0; + return; disc = &port->disc; BUG_ON(ev >= DISC_NUM_EVENTS); sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha); - - return 0; } /** diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index a1852f6c042b..f3a17191a4fe 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -10,29 +10,26 @@ #include <scsi/scsi_host.h> #include "sas_internal.h" -int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) +bool sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) { - /* it's added to the defer_q when draining so return succeed */ - int rc = 1; - if (!test_bit(SAS_HA_REGISTERED, &ha->state)) - return 0; + return false; if (test_bit(SAS_HA_DRAINING, &ha->state)) { /* add it to the defer list, if not already pending */ if (list_empty(&sw->drain_node)) list_add_tail(&sw->drain_node, &ha->defer_q); - } else - rc = queue_work(ha->event_q, &sw->work); + return true; + } - return rc; + return queue_work(ha->event_q, &sw->work); } -static int sas_queue_event(int event, struct sas_work *work, +static bool sas_queue_event(int event, struct sas_work *work, struct sas_ha_struct *ha) { unsigned long flags; - int rc; + bool rc; spin_lock_irqsave(&ha->lock, flags); rc = sas_queue_work(ha, work); @@ -41,12 +38,24 @@ static int sas_queue_event(int event, struct sas_work *work, return rc; } - -void __sas_drain_work(struct sas_ha_struct *ha) +void sas_queue_deferred_work(struct sas_ha_struct *ha) { struct sas_work *sw, *_sw; - int ret; + spin_lock_irq(&ha->lock); + list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { + list_del_init(&sw->drain_node); + + if (!sas_queue_work(ha, sw)) { + pm_runtime_put(ha->dev); + sas_free_event(to_asd_sas_event(&sw->work)); + } + } + spin_unlock_irq(&ha->lock); +} + +void __sas_drain_work(struct sas_ha_struct *ha) +{ set_bit(SAS_HA_DRAINING, &ha->state); /* flush submitters */ spin_lock_irq(&ha->lock); @@ -55,16 +64,8 @@ void __sas_drain_work(struct sas_ha_struct *ha) drain_workqueue(ha->event_q); drain_workqueue(ha->disco_q); - spin_lock_irq(&ha->lock); clear_bit(SAS_HA_DRAINING, &ha->state); - list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { - list_del_init(&sw->drain_node); - ret = sas_queue_work(ha, sw); - if (ret != 1) - sas_free_event(to_asd_sas_event(&sw->work)); - - } - spin_unlock_irq(&ha->lock); + sas_queue_deferred_work(ha); } int sas_drain_work(struct sas_ha_struct *ha) @@ -104,12 +105,17 @@ void sas_enable_revalidation(struct sas_ha_struct *ha) if (!test_and_clear_bit(ev, &d->pending)) continue; - if (list_empty(&port->phy_list)) + spin_lock(&port->phy_list_lock); + if (list_empty(&port->phy_list)) { + spin_unlock(&port->phy_list_lock); continue; + } sas_phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el); - ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); + spin_unlock(&port->phy_list_lock); + sas_notify_port_event(sas_phy, + PORTE_BROADCAST_RCVD, GFP_KERNEL); } mutex_unlock(&ha->disco_mutex); } @@ -118,65 +124,93 @@ void sas_enable_revalidation(struct sas_ha_struct *ha) static void sas_port_event_worker(struct work_struct *work) { struct asd_sas_event *ev = to_asd_sas_event(work); + struct asd_sas_phy *phy = ev->phy; + struct sas_ha_struct *ha = phy->ha; sas_port_event_fns[ev->event](work); + pm_runtime_put(ha->dev); sas_free_event(ev); } static void sas_phy_event_worker(struct work_struct *work) { struct asd_sas_event *ev = to_asd_sas_event(work); + struct asd_sas_phy *phy = ev->phy; + struct sas_ha_struct *ha = phy->ha; sas_phy_event_fns[ev->event](work); + pm_runtime_put(ha->dev); sas_free_event(ev); } -static int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event) +/* defer works of new phys during suspend */ +static bool sas_defer_event(struct asd_sas_phy *phy, struct asd_sas_event *ev) { - struct asd_sas_event *ev; struct sas_ha_struct *ha = phy->ha; - int ret; + unsigned long flags; + bool deferred = false; + + spin_lock_irqsave(&ha->lock, flags); + if (test_bit(SAS_HA_RESUMING, &ha->state) && !phy->suspended) { + struct sas_work *sw = &ev->work; + + list_add_tail(&sw->drain_node, &ha->defer_q); + deferred = true; + } + spin_unlock_irqrestore(&ha->lock, flags); + return deferred; +} + +void sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event, + gfp_t gfp_flags) +{ + struct sas_ha_struct *ha = phy->ha; + struct asd_sas_event *ev; BUG_ON(event >= PORT_NUM_EVENTS); - ev = sas_alloc_event(phy); + ev = sas_alloc_event(phy, gfp_flags); if (!ev) - return -ENOMEM; + return; + + /* Call pm_runtime_put() with pairs in sas_port_event_worker() */ + pm_runtime_get_noresume(ha->dev); INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event); - ret = sas_queue_event(event, &ev->work, ha); - if (ret != 1) - sas_free_event(ev); + if (sas_defer_event(phy, ev)) + return; - return ret; + if (!sas_queue_event(event, &ev->work, ha)) { + pm_runtime_put(ha->dev); + sas_free_event(ev); + } } +EXPORT_SYMBOL_GPL(sas_notify_port_event); -int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) +void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event, + gfp_t gfp_flags) { - struct asd_sas_event *ev; struct sas_ha_struct *ha = phy->ha; - int ret; + struct asd_sas_event *ev; BUG_ON(event >= PHY_NUM_EVENTS); - ev = sas_alloc_event(phy); + ev = sas_alloc_event(phy, gfp_flags); if (!ev) - return -ENOMEM; + return; - INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event); - - ret = sas_queue_event(event, &ev->work, ha); - if (ret != 1) - sas_free_event(ev); + /* Call pm_runtime_put() with pairs in sas_phy_event_worker() */ + pm_runtime_get_noresume(ha->dev); - return ret; -} + INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event); -int sas_init_events(struct sas_ha_struct *sas_ha) -{ - sas_ha->notify_port_event = sas_notify_port_event; - sas_ha->notify_phy_event = sas_notify_phy_event; + if (sas_defer_event(phy, ev)) + return; - return 0; + if (!sas_queue_event(event, &ev->work, ha)) { + pm_runtime_put(ha->dev); + sas_free_event(ev); + } } +EXPORT_SYMBOL_GPL(sas_notify_phy_event); diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index ab671cdd4cfb..5ce251830104 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -18,7 +18,7 @@ #include <scsi/sas_ata.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_sas.h> -#include "../scsi_sas_internal.h" +#include "scsi_sas_internal.h" static int sas_discover_expander(struct domain_device *dev); static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr); @@ -28,26 +28,6 @@ static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr); /* ---------- SMP task management ---------- */ -static void smp_task_timedout(struct timer_list *t) -{ - struct sas_task_slow *slow = from_timer(slow, t, timer); - struct sas_task *task = slow->task; - unsigned long flags; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - complete(&task->slow_task->completion); - } - spin_unlock_irqrestore(&task->task_state_lock, flags); -} - -static void smp_task_done(struct sas_task *task) -{ - del_timer(&task->slow_task->timer); - complete(&task->slow_task->completion); -} - /* Give it some long enough timeout. In seconds. */ #define SMP_TIMEOUT 10 @@ -58,7 +38,9 @@ static int smp_execute_task_sg(struct domain_device *dev, struct sas_task *task = NULL; struct sas_internal *i = to_sas_internal(dev->port->ha->core.shost->transportt); + struct sas_ha_struct *ha = dev->port->ha; + pm_runtime_get_sync(ha->dev); mutex_lock(&dev->ex_dev.cmd_mutex); for (retry = 0; retry < 3; retry++) { if (test_bit(SAS_DEV_GONE, &dev->state)) { @@ -76,16 +58,16 @@ static int smp_execute_task_sg(struct domain_device *dev, task->smp_task.smp_req = *req; task->smp_task.smp_resp = *resp; - task->task_done = smp_task_done; + task->task_done = sas_task_internal_done; - task->slow_task->timer.function = smp_task_timedout; + task->slow_task->timer.function = sas_task_internal_timedout; task->slow_task->timer.expires = jiffies + SMP_TIMEOUT*HZ; add_timer(&task->slow_task->timer); res = i->dft->lldd_execute_task(task, GFP_KERNEL); if (res) { - del_timer(&task->slow_task->timer); + del_timer_sync(&task->slow_task->timer); pr_notice("executing SMP task failed:%d\n", res); break; } @@ -101,7 +83,7 @@ static int smp_execute_task_sg(struct domain_device *dev, } } if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_STAT_GOOD) { + task->task_status.stat == SAS_SAM_STAT_GOOD) { res = 0; break; } @@ -131,6 +113,7 @@ static int smp_execute_task_sg(struct domain_device *dev, } } mutex_unlock(&dev->ex_dev.cmd_mutex); + pm_runtime_put_sync(ha->dev); BUG_ON(retry == 3 && task != NULL); sas_free_task(task); @@ -192,13 +175,13 @@ static enum sas_device_type to_dev_type(struct discover_resp *dr) return dr->attached_dev_type; } -static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) +static void sas_set_ex_phy(struct domain_device *dev, int phy_id, + struct smp_disc_resp *disc_resp) { enum sas_device_type dev_type; enum sas_linkrate linkrate; u8 sas_addr[SAS_ADDR_SIZE]; - struct smp_resp *resp = rsp; - struct discover_resp *dr = &resp->disc; + struct discover_resp *dr = &disc_resp->disc; struct sas_ha_struct *ha = dev->port->ha; struct expander_device *ex = &dev->ex_dev; struct ex_phy *phy = &ex->ex_phy[phy_id]; @@ -215,7 +198,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) BUG_ON(!phy->phy); } - switch (resp->result) { + switch (disc_resp->result) { case SMP_RESP_PHY_VACANT: phy->phy_state = PHY_VACANT; break; @@ -364,12 +347,13 @@ struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id) } #define DISCOVER_REQ_SIZE 16 -#define DISCOVER_RESP_SIZE 56 +#define DISCOVER_RESP_SIZE sizeof(struct smp_disc_resp) static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, - u8 *disc_resp, int single) + struct smp_disc_resp *disc_resp, + int single) { - struct discover_resp *dr; + struct discover_resp *dr = &disc_resp->disc; int res; disc_req[9] = single; @@ -378,7 +362,6 @@ static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, disc_resp, DISCOVER_RESP_SIZE); if (res) return res; - dr = &((struct smp_resp *)disc_resp)->disc; if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) { pr_notice("Found loopback topology, just ignore it!\n"); return 0; @@ -392,7 +375,7 @@ int sas_ex_phy_discover(struct domain_device *dev, int single) struct expander_device *ex = &dev->ex_dev; int res = 0; u8 *disc_req; - u8 *disc_resp; + struct smp_disc_resp *disc_resp; disc_req = alloc_smp_req(DISCOVER_REQ_SIZE); if (!disc_req) @@ -427,7 +410,7 @@ out_err: static int sas_expander_discover(struct domain_device *dev) { struct expander_device *ex = &dev->ex_dev; - int res = -ENOMEM; + int res; ex->ex_phy = kcalloc(ex->num_phys, sizeof(*ex->ex_phy), GFP_KERNEL); if (!ex->ex_phy) @@ -446,27 +429,14 @@ static int sas_expander_discover(struct domain_device *dev) #define MAX_EXPANDER_PHYS 128 -static void ex_assign_report_general(struct domain_device *dev, - struct smp_resp *resp) -{ - struct report_general_resp *rg = &resp->rg; - - dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count); - dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes); - dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS); - dev->ex_dev.t2t_supp = rg->t2t_supp; - dev->ex_dev.conf_route_table = rg->conf_route_table; - dev->ex_dev.configuring = rg->configuring; - memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8); -} - #define RG_REQ_SIZE 8 -#define RG_RESP_SIZE 32 +#define RG_RESP_SIZE sizeof(struct smp_rg_resp) static int sas_ex_general(struct domain_device *dev) { u8 *rg_req; - struct smp_resp *rg_resp; + struct smp_rg_resp *rg_resp; + struct report_general_resp *rg; int res; int i; @@ -497,7 +467,15 @@ static int sas_ex_general(struct domain_device *dev) goto out; } - ex_assign_report_general(dev, rg_resp); + rg = &rg_resp->rg; + dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count); + dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes); + dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS); + dev->ex_dev.t2t_supp = rg->t2t_supp; + dev->ex_dev.conf_route_table = rg->conf_route_table; + dev->ex_dev.configuring = rg->configuring; + memcpy(dev->ex_dev.enclosure_logical_id, + rg->enclosure_logical_id, 8); if (dev->ex_dev.configuring) { pr_debug("RG: ex %016llx self-configuring...\n", @@ -553,7 +531,7 @@ static int sas_ex_manuf_info(struct domain_device *dev) mi_req[1] = SMP_REPORT_MANUF_INFO; - res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp,MI_RESP_SIZE); + res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp, MI_RESP_SIZE); if (res) { pr_notice("MI: ex %016llx failed:0x%x\n", SAS_ADDR(dev->sas_addr), res); @@ -594,13 +572,13 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id, pc_req[1] = SMP_PHY_CONTROL; pc_req[9] = phy_id; - pc_req[10]= phy_func; + pc_req[10] = phy_func; if (rates) { pc_req[32] = rates->minimum_linkrate << 4; pc_req[33] = rates->maximum_linkrate << 4; } - res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE); + res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp, PC_RESP_SIZE); if (res) { pr_err("ex %016llx phy%02d PHY control failed: %d\n", SAS_ADDR(dev->sas_addr), phy_id, res); @@ -678,7 +656,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) req[9] = phy->number; res = smp_execute_task(dev, req, RPEL_REQ_SIZE, - resp, RPEL_RESP_SIZE); + resp, RPEL_RESP_SIZE); if (res) goto out; @@ -698,10 +676,10 @@ int sas_smp_get_phy_events(struct sas_phy *phy) #ifdef CONFIG_SCSI_SAS_ATA #define RPS_REQ_SIZE 16 -#define RPS_RESP_SIZE 60 +#define RPS_RESP_SIZE sizeof(struct smp_rps_resp) int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, - struct smp_resp *rps_resp) + struct smp_rps_resp *rps_resp) { int res; u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE); @@ -714,7 +692,7 @@ int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, rps_req[9] = phy_id; res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE, - rps_resp, RPS_RESP_SIZE); + rps_resp, RPS_RESP_SIZE); /* 0x34 is the FIS type for the D2H fis. There's a potential * standards cockup here. sas-2 explicitly specifies the FIS @@ -1096,7 +1074,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) } else memcpy(dev->port->disc.fanout_sas_addr, ex_phy->attached_sas_addr, SAS_ADDR_SIZE); - /* fallthrough */ + fallthrough; case SAS_EDGE_EXPANDER_DEVICE: child = sas_ex_discover_expander(dev, phy_id); break; @@ -1506,7 +1484,8 @@ static int sas_configure_phy(struct domain_device *dev, int phy_id, if (res) return res; if (include ^ present) - return sas_configure_set(dev, phy_id, sas_addr, index,include); + return sas_configure_set(dev, phy_id, sas_addr, index, + include); return res; } @@ -1673,7 +1652,7 @@ out_err: /* ---------- Domain revalidation ---------- */ static int sas_get_phy_discover(struct domain_device *dev, - int phy_id, struct smp_resp *disc_resp) + int phy_id, struct smp_disc_resp *disc_resp) { int res; u8 *disc_req; @@ -1689,10 +1668,8 @@ static int sas_get_phy_discover(struct domain_device *dev, disc_resp, DISCOVER_RESP_SIZE); if (res) goto out; - else if (disc_resp->result != SMP_RESP_FUNC_ACC) { + if (disc_resp->result != SMP_RESP_FUNC_ACC) res = disc_resp->result; - goto out; - } out: kfree(disc_req); return res; @@ -1702,7 +1679,7 @@ static int sas_get_phy_change_count(struct domain_device *dev, int phy_id, int *pcc) { int res; - struct smp_resp *disc_resp; + struct smp_disc_resp *disc_resp; disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); if (!disc_resp) @@ -1720,19 +1697,17 @@ static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, u8 *sas_addr, enum sas_device_type *type) { int res; - struct smp_resp *disc_resp; - struct discover_resp *dr; + struct smp_disc_resp *disc_resp; disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); if (!disc_resp) return -ENOMEM; - dr = &disc_resp->disc; res = sas_get_phy_discover(dev, phy_id, disc_resp); if (res == 0) { memcpy(sas_addr, disc_resp->disc.attached_sas_addr, SAS_ADDR_SIZE); - *type = to_dev_type(dr); + *type = to_dev_type(&disc_resp->disc); if (*type == 0) memset(sas_addr, 0, SAS_ADDR_SIZE); } @@ -1776,7 +1751,7 @@ static int sas_get_ex_change_count(struct domain_device *dev, int *ecc) { int res; u8 *rg_req; - struct smp_resp *rg_resp; + struct smp_rg_resp *rg_resp; rg_req = alloc_smp_req(RG_REQ_SIZE); if (!rg_req) diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index eca2a6bf3601..32cdc969b736 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -14,7 +14,7 @@ #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_sas.h> -#include "../scsi_sas_internal.h" +#include "scsi_sas_internal.h" static void sas_host_smp_discover(struct sas_ha_struct *sas_ha, u8 *resp_data, u8 phy_id) diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 21c43b18d5d5..e4f77072a58d 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -19,7 +19,7 @@ #include "sas_internal.h" -#include "../scsi_sas_internal.h" +#include "scsi_sas_internal.h" static struct kmem_cache *sas_task_cache; static struct kmem_cache *sas_event_cache; @@ -123,12 +123,6 @@ int sas_register_ha(struct sas_ha_struct *sas_ha) goto Undo_phys; } - error = sas_init_events(sas_ha); - if (error) { - pr_notice("couldn't start event thread:%d\n", error); - goto Undo_ports; - } - error = -ENOMEM; snprintf(name, sizeof(name), "%s_event_q", dev_name(sas_ha->dev)); sas_ha->event_q = create_singlethread_workqueue(name); @@ -153,6 +147,7 @@ Undo_phys: return error; } +EXPORT_SYMBOL_GPL(sas_register_ha); static void sas_disable_events(struct sas_ha_struct *sas_ha) { @@ -182,6 +177,7 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha) return 0; } +EXPORT_SYMBOL_GPL(sas_unregister_ha); static int sas_get_linkerrors(struct sas_phy *phy) { @@ -258,7 +254,7 @@ static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset) } } -static int sas_phy_enable(struct sas_phy *phy, int enable) +int sas_phy_enable(struct sas_phy *phy, int enable) { int ret; enum phy_func cmd; @@ -290,6 +286,7 @@ static int sas_phy_enable(struct sas_phy *phy, int enable) } return ret; } +EXPORT_SYMBOL_GPL(sas_phy_enable); int sas_phy_reset(struct sas_phy *phy, int hard_reset) { @@ -319,6 +316,7 @@ int sas_phy_reset(struct sas_phy *phy, int hard_reset) } return ret; } +EXPORT_SYMBOL_GPL(sas_phy_reset); int sas_set_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) @@ -364,6 +362,7 @@ void sas_prep_resume_ha(struct sas_ha_struct *ha) int i; set_bit(SAS_HA_REGISTERED, &ha->state); + set_bit(SAS_HA_RESUMING, &ha->state); /* clear out any stale link events/data from the suspension path */ for (i = 0; i < ha->num_phys; i++) { @@ -389,7 +388,31 @@ static int phys_suspended(struct sas_ha_struct *ha) return rc; } -void sas_resume_ha(struct sas_ha_struct *ha) +static void sas_resume_insert_broadcast_ha(struct sas_ha_struct *ha) +{ + int i; + + for (i = 0; i < ha->num_phys; i++) { + struct asd_sas_port *port = ha->sas_port[i]; + struct domain_device *dev = port->port_dev; + + if (dev && dev_is_expander(dev->dev_type)) { + struct asd_sas_phy *first_phy; + + spin_lock(&port->phy_list_lock); + first_phy = list_first_entry_or_null( + &port->phy_list, struct asd_sas_phy, + port_phy_el); + spin_unlock(&port->phy_list_lock); + + if (first_phy) + sas_notify_port_event(first_phy, + PORTE_BROADCAST_RCVD, GFP_KERNEL); + } + } +} + +static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) { const unsigned long tmo = msecs_to_jiffies(25000); int i; @@ -410,7 +433,8 @@ void sas_resume_ha(struct sas_ha_struct *ha) if (phy->suspended) { dev_warn(&phy->phy->dev, "resume timeout\n"); - sas_notify_phy_event(phy, PHYE_RESUME_TIMEOUT); + sas_notify_phy_event(phy, PHYE_RESUME_TIMEOUT, + GFP_KERNEL); } } @@ -418,10 +442,30 @@ void sas_resume_ha(struct sas_ha_struct *ha) * flush out disks that did not return */ scsi_unblock_requests(ha->core.shost); - sas_drain_work(ha); + if (drain) + sas_drain_work(ha); + clear_bit(SAS_HA_RESUMING, &ha->state); + + sas_queue_deferred_work(ha); + /* send event PORTE_BROADCAST_RCVD to identify some new inserted + * disks for expander + */ + sas_resume_insert_broadcast_ha(ha); +} + +void sas_resume_ha(struct sas_ha_struct *ha) +{ + _sas_resume_ha(ha, true); } EXPORT_SYMBOL(sas_resume_ha); +/* A no-sync variant, which does not call sas_drain_ha(). */ +void sas_resume_ha_no_sync(struct sas_ha_struct *ha) +{ + _sas_resume_ha(ha, false); +} +EXPORT_SYMBOL(sas_resume_ha_no_sync); + void sas_suspend_ha(struct sas_ha_struct *ha) { int i; @@ -487,6 +531,7 @@ static int queue_phy_reset(struct sas_phy *phy, int hard_reset) if (!d) return -ENOMEM; + pm_runtime_get_sync(ha->dev); /* libsas workqueue coordinates ata-eh reset with discovery */ mutex_lock(&d->event_lock); d->reset_result = 0; @@ -500,6 +545,7 @@ static int queue_phy_reset(struct sas_phy *phy, int hard_reset) if (rc == 0) rc = d->reset_result; mutex_unlock(&d->event_lock); + pm_runtime_put_sync(ha->dev); return rc; } @@ -514,6 +560,7 @@ static int queue_phy_enable(struct sas_phy *phy, int enable) if (!d) return -ENOMEM; + pm_runtime_get_sync(ha->dev); /* libsas workqueue coordinates ata-eh reset with discovery */ mutex_lock(&d->event_lock); d->enable_result = 0; @@ -527,6 +574,7 @@ static int queue_phy_enable(struct sas_phy *phy, int enable) if (rc == 0) rc = d->enable_result; mutex_unlock(&d->event_lock); + pm_runtime_put_sync(ha->dev); return rc; } @@ -590,16 +638,15 @@ sas_domain_attach_transport(struct sas_domain_function_template *dft) } EXPORT_SYMBOL_GPL(sas_domain_attach_transport); - -struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy) +struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, + gfp_t gfp_flags) { struct asd_sas_event *event; - gfp_t flags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; struct sas_ha_struct *sas_ha = phy->ha; struct sas_internal *i = to_sas_internal(sas_ha->core.shost->transportt); - event = kmem_cache_zalloc(sas_event_cache, flags); + event = kmem_cache_zalloc(sas_event_cache, gfp_flags); if (!event) return NULL; @@ -610,7 +657,8 @@ struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy) if (cmpxchg(&phy->in_shutdown, 0, 1) == 0) { pr_notice("The phy%d bursting events, shut it down.\n", phy->id); - sas_notify_phy_event(phy, PHYE_SHUTDOWN); + sas_notify_phy_event(phy, PHYE_SHUTDOWN, + gfp_flags); } } else { /* Do not support PHY control, stop allocating events */ @@ -664,5 +712,3 @@ MODULE_LICENSE("GPL v2"); module_init(sas_class_init); module_exit(sas_class_exit); -EXPORT_SYMBOL_GPL(sas_register_ha); -EXPORT_SYMBOL_GPL(sas_unregister_ha); diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 1f1d01901978..8d0ad3abc7b5 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -14,6 +14,7 @@ #include <scsi/scsi_transport_sas.h> #include <scsi/libsas.h> #include <scsi/sas_ata.h> +#include <linux/pm_runtime.h> #ifdef pr_fmt #undef pr_fmt @@ -48,15 +49,15 @@ int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf); int sas_register_phys(struct sas_ha_struct *sas_ha); void sas_unregister_phys(struct sas_ha_struct *sas_ha); -struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy); +struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags); void sas_free_event(struct asd_sas_event *event); int sas_register_ports(struct sas_ha_struct *sas_ha); void sas_unregister_ports(struct sas_ha_struct *sas_ha); -int sas_init_events(struct sas_ha_struct *sas_ha); void sas_disable_revalidation(struct sas_ha_struct *ha); void sas_enable_revalidation(struct sas_ha_struct *ha); +void sas_queue_deferred_work(struct sas_ha_struct *ha); void __sas_drain_work(struct sas_ha_struct *ha); void sas_deform_port(struct asd_sas_phy *phy, int gone); @@ -66,7 +67,7 @@ void sas_porte_broadcast_rcvd(struct work_struct *work); void sas_porte_link_reset_err(struct work_struct *work); void sas_porte_timer_event(struct work_struct *work); void sas_porte_hard_reset(struct work_struct *work); -int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw); +bool sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw); int sas_notify_lldd_dev_found(struct domain_device *); void sas_notify_lldd_dev_gone(struct domain_device *); @@ -77,13 +78,12 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id, enum phy_func phy_func, struct sas_phy_linkrates *); int sas_smp_get_phy_events(struct sas_phy *phy); -int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event); void sas_device_set_phy(struct domain_device *dev, struct sas_port *port); struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); int sas_ex_phy_discover(struct domain_device *dev, int single); int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, - struct smp_resp *rps_resp); + struct smp_rps_resp *rps_resp); int sas_try_ata_reset(struct asd_sas_phy *phy); void sas_hae_reset(struct work_struct *work); @@ -93,6 +93,12 @@ void sas_destruct_devices(struct asd_sas_port *port); extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS]; extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS]; +void sas_task_internal_done(struct sas_task *task); +void sas_task_internal_timedout(struct timer_list *t); +int sas_execute_tmf(struct domain_device *device, void *parameter, + int para_len, int force_phy_id, + struct sas_tmf_task *tmf); + #ifdef CONFIG_SCSI_SAS_HOST_SMP extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost); #else diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index 4ca4b1f30bd0..a0d592d11dfb 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c @@ -10,7 +10,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_sas.h> -#include "../scsi_sas_internal.h" +#include "scsi_sas_internal.h" /* ---------- Phy events ---------- */ diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 19cf418928fa..11599c0e3fc3 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -10,7 +10,7 @@ #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_sas.h> -#include "../scsi_sas_internal.h" +#include "scsi_sas_internal.h" static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy *phy) { @@ -25,7 +25,7 @@ static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy static void sas_resume_port(struct asd_sas_phy *phy) { - struct domain_device *dev; + struct domain_device *dev, *n; struct asd_sas_port *port = phy->port; struct sas_ha_struct *sas_ha = phy->ha; struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt); @@ -44,7 +44,7 @@ static void sas_resume_port(struct asd_sas_phy *phy) * 1/ presume every device came back * 2/ force the next revalidation to check all expander phys */ - list_for_each_entry(dev, &port->dev_list, dev_list_node) { + list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) { int i, rc; rc = sas_notify_lldd_dev_found(dev); @@ -67,6 +67,34 @@ static void sas_resume_port(struct asd_sas_phy *phy) sas_discover_event(port, DISCE_RESUME); } +static void sas_form_port_add_phy(struct asd_sas_port *port, + struct asd_sas_phy *phy, bool wideport) +{ + list_add_tail(&phy->port_phy_el, &port->phy_list); + sas_phy_set_target(phy, port->port_dev); + phy->port = port; + port->num_phys++; + port->phy_mask |= (1U << phy->id); + + if (wideport) + pr_debug("phy%d matched wide port%d\n", phy->id, + port->id); + else + memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE); + + if (*(u64 *)port->attached_sas_addr == 0) { + port->class = phy->class; + memcpy(port->attached_sas_addr, phy->attached_sas_addr, + SAS_ADDR_SIZE); + port->iproto = phy->iproto; + port->tproto = phy->tproto; + port->oob_mode = phy->oob_mode; + port->linkrate = phy->linkrate; + } else { + port->linkrate = max(port->linkrate, phy->linkrate); + } +} + /** * sas_form_port - add this phy to a port * @phy: the phy of interest @@ -79,7 +107,7 @@ static void sas_form_port(struct asd_sas_phy *phy) int i; struct sas_ha_struct *sas_ha = phy->ha; struct asd_sas_port *port = phy->port; - struct domain_device *port_dev; + struct domain_device *port_dev = NULL; struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt); unsigned long flags; @@ -110,8 +138,9 @@ static void sas_form_port(struct asd_sas_phy *phy) if (*(u64 *) port->sas_addr && phy_is_wideport_member(port, phy) && port->num_phys > 0) { /* wide port */ - pr_debug("phy%d matched wide port%d\n", phy->id, - port->id); + port_dev = port->port_dev; + sas_form_port_add_phy(port, phy, true); + spin_unlock(&port->phy_list_lock); break; } spin_unlock(&port->phy_list_lock); @@ -122,40 +151,22 @@ static void sas_form_port(struct asd_sas_phy *phy) port = sas_ha->sas_port[i]; spin_lock(&port->phy_list_lock); if (*(u64 *)port->sas_addr == 0 - && port->num_phys == 0) { - memcpy(port->sas_addr, phy->sas_addr, - SAS_ADDR_SIZE); + && port->num_phys == 0) { + port_dev = port->port_dev; + sas_form_port_add_phy(port, phy, false); + spin_unlock(&port->phy_list_lock); break; } spin_unlock(&port->phy_list_lock); } - } - if (i >= sas_ha->num_phys) { - pr_err("%s: couldn't find a free port, bug?\n", __func__); - spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); - return; + if (i >= sas_ha->num_phys) { + pr_err("%s: couldn't find a free port, bug?\n", + __func__); + spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); + return; + } } - - /* add the phy to the port */ - port_dev = port->port_dev; - list_add_tail(&phy->port_phy_el, &port->phy_list); - sas_phy_set_target(phy, port_dev); - phy->port = port; - port->num_phys++; - port->phy_mask |= (1U << phy->id); - - if (*(u64 *)port->attached_sas_addr == 0) { - port->class = phy->class; - memcpy(port->attached_sas_addr, phy->attached_sas_addr, - SAS_ADDR_SIZE); - port->iproto = phy->iproto; - port->tproto = phy->tproto; - port->oob_mode = phy->oob_mode; - port->linkrate = phy->linkrate; - } else - port->linkrate = max(port->linkrate, phy->linkrate); - spin_unlock(&port->phy_list_lock); spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); if (!port->port) { diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 9e0975e55c27..a36fa1c128a8 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -22,9 +22,9 @@ #include <scsi/scsi_transport.h> #include <scsi/scsi_transport_sas.h> #include <scsi/sas_ata.h> -#include "../scsi_sas_internal.h" -#include "../scsi_transport_api.h" -#include "../scsi_priv.h" +#include "scsi_sas_internal.h" +#include "scsi_transport_api.h" +#include "scsi_priv.h" #include <linux/err.h> #include <linux/blkdev.h> @@ -37,7 +37,8 @@ static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task) { struct task_status_struct *ts = &task->task_status; - int hs = 0, stat = 0; + enum scsi_host_status hs = DID_OK; + enum exec_status stat = SAS_SAM_STAT_GOOD; if (ts->resp == SAS_TASK_UNDELIVERED) { /* transport error */ @@ -66,9 +67,6 @@ static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task) case SAS_DEVICE_UNKNOWN: hs = DID_BAD_TARGET; break; - case SAS_SG_ERR: - hs = DID_PARITY; - break; case SAS_OPEN_REJECT: if (ts->open_rej_reason == SAS_OREJ_RSVD_RETRY) hs = DID_SOFT_ERROR; /* retry */ @@ -82,10 +80,10 @@ static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task) case SAS_ABORTED_TASK: hs = DID_ABORT; break; - case SAM_STAT_CHECK_CONDITION: + case SAS_SAM_STAT_CHECK_CONDITION: memcpy(sc->sense_buffer, ts->buf, min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); - stat = SAM_STAT_CHECK_CONDITION; + stat = SAS_SAM_STAT_CHECK_CONDITION; break; default: stat = ts->stat; @@ -125,7 +123,7 @@ static void sas_scsi_task_done(struct sas_task *task) } sas_end_task(sc, task); - sc->scsi_done(sc); + scsi_done(sc); } static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, @@ -198,9 +196,10 @@ out_free_task: else cmd->result = DID_ERROR << 16; out_done: - cmd->scsi_done(cmd); + scsi_done(cmd); return 0; } +EXPORT_SYMBOL_GPL(sas_queuecommand); static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) { @@ -314,11 +313,13 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) pr_notice("%s: task 0x%p failed to abort\n", __func__, task); return TASK_ABORT_FAILED; + default: + pr_notice("%s: task 0x%p result code %d not handled\n", + __func__, task, res); } - } } - return res; + return TASK_ABORT_FAILED; } static int sas_recover_lu(struct domain_device *dev, struct scsi_cmnd *cmd) @@ -511,6 +512,7 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) return FAILED; } +EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); int sas_eh_target_reset_handler(struct scsi_cmnd *cmd) { @@ -532,6 +534,7 @@ int sas_eh_target_reset_handler(struct scsi_cmnd *cmd) return FAILED; } +EXPORT_SYMBOL_GPL(sas_eh_target_reset_handler); /* Try to reset a device */ static int try_to_reset_cmd_device(struct scsi_cmnd *cmd) @@ -622,7 +625,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head * sas_scsi_clear_queue_lu(work_q, cmd); goto Again; } - /* fallthrough */ + fallthrough; case TASK_IS_NOT_AT_LU: case TASK_ABORT_FAILED: pr_notice("task 0x%p is not at LU: I_T recover\n", @@ -753,7 +756,7 @@ retry: * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any * command we see here has no sas_task and is thus unknown to the HA. */ - sas_ata_eh(shost, &eh_work_q, &ha->eh_done_q); + sas_ata_eh(shost, &eh_work_q); if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); @@ -790,6 +793,7 @@ int sas_ioctl(struct scsi_device *sdev, unsigned int cmd, void __user *arg) return -EINVAL; } +EXPORT_SYMBOL_GPL(sas_ioctl); struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) { @@ -832,6 +836,7 @@ int sas_target_alloc(struct scsi_target *starget) starget->hostdata = found_dev; return 0; } +EXPORT_SYMBOL_GPL(sas_target_alloc); #define SAS_DEF_QD 256 @@ -860,18 +865,21 @@ int sas_slave_configure(struct scsi_device *scsi_dev) return 0; } +EXPORT_SYMBOL_GPL(sas_slave_configure); int sas_change_queue_depth(struct scsi_device *sdev, int depth) { struct domain_device *dev = sdev_to_domain_dev(sdev); if (dev_is_sata(dev)) - return __ata_change_queue_depth(dev->sata_dev.ap, sdev, depth); + return ata_change_queue_depth(dev->sata_dev.ap, + sas_to_ata_dev(dev), sdev, depth); if (!sdev->tagged_supported) depth = 1; return scsi_change_queue_depth(sdev, depth); } +EXPORT_SYMBOL_GPL(sas_change_queue_depth); int sas_bios_param(struct scsi_device *scsi_dev, struct block_device *bdev, @@ -884,6 +892,316 @@ int sas_bios_param(struct scsi_device *scsi_dev, return 0; } +EXPORT_SYMBOL_GPL(sas_bios_param); + +void sas_task_internal_done(struct sas_task *task) +{ + del_timer(&task->slow_task->timer); + complete(&task->slow_task->completion); +} + +void sas_task_internal_timedout(struct timer_list *t) +{ + struct sas_task_slow *slow = from_timer(slow, t, timer); + struct sas_task *task = slow->task; + bool is_completed = true; + unsigned long flags; + + spin_lock_irqsave(&task->task_state_lock, flags); + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + is_completed = false; + } + spin_unlock_irqrestore(&task->task_state_lock, flags); + + if (!is_completed) + complete(&task->slow_task->completion); +} + +#define TASK_TIMEOUT (20 * HZ) +#define TASK_RETRY 3 + +static int sas_execute_internal_abort(struct domain_device *device, + enum sas_internal_abort type, u16 tag, + unsigned int qid, void *data) +{ + struct sas_ha_struct *ha = device->port->ha; + struct sas_internal *i = to_sas_internal(ha->core.shost->transportt); + struct sas_task *task = NULL; + int res, retry; + + for (retry = 0; retry < TASK_RETRY; retry++) { + task = sas_alloc_slow_task(GFP_KERNEL); + if (!task) + return -ENOMEM; + + task->dev = device; + task->task_proto = SAS_PROTOCOL_INTERNAL_ABORT; + task->task_done = sas_task_internal_done; + task->slow_task->timer.function = sas_task_internal_timedout; + task->slow_task->timer.expires = jiffies + TASK_TIMEOUT; + add_timer(&task->slow_task->timer); + + task->abort_task.tag = tag; + task->abort_task.type = type; + task->abort_task.qid = qid; + + res = i->dft->lldd_execute_task(task, GFP_KERNEL); + if (res) { + del_timer_sync(&task->slow_task->timer); + pr_err("Executing internal abort failed %016llx (%d)\n", + SAS_ADDR(device->sas_addr), res); + break; + } + + wait_for_completion(&task->slow_task->completion); + res = TMF_RESP_FUNC_FAILED; + + /* Even if the internal abort timed out, return direct. */ + if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { + bool quit = true; + + if (i->dft->lldd_abort_timeout) + quit = i->dft->lldd_abort_timeout(task, data); + else + pr_err("Internal abort: timeout %016llx\n", + SAS_ADDR(device->sas_addr)); + res = -EIO; + if (quit) + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_SAM_STAT_GOOD) { + res = TMF_RESP_FUNC_COMPLETE; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == TMF_RESP_FUNC_SUCC) { + res = TMF_RESP_FUNC_SUCC; + break; + } + + pr_err("Internal abort: task to dev %016llx response: 0x%x status 0x%x\n", + SAS_ADDR(device->sas_addr), task->task_status.resp, + task->task_status.stat); + sas_free_task(task); + task = NULL; + } + BUG_ON(retry == TASK_RETRY && task != NULL); + sas_free_task(task); + return res; +} + +int sas_execute_internal_abort_single(struct domain_device *device, u16 tag, + unsigned int qid, void *data) +{ + return sas_execute_internal_abort(device, SAS_INTERNAL_ABORT_SINGLE, + tag, qid, data); +} +EXPORT_SYMBOL_GPL(sas_execute_internal_abort_single); + +int sas_execute_internal_abort_dev(struct domain_device *device, + unsigned int qid, void *data) +{ + return sas_execute_internal_abort(device, SAS_INTERNAL_ABORT_DEV, + SCSI_NO_TAG, qid, data); +} +EXPORT_SYMBOL_GPL(sas_execute_internal_abort_dev); + +int sas_execute_tmf(struct domain_device *device, void *parameter, + int para_len, int force_phy_id, + struct sas_tmf_task *tmf) +{ + struct sas_task *task; + struct sas_internal *i = + to_sas_internal(device->port->ha->core.shost->transportt); + int res, retry; + + for (retry = 0; retry < TASK_RETRY; retry++) { + task = sas_alloc_slow_task(GFP_KERNEL); + if (!task) + return -ENOMEM; + + task->dev = device; + task->task_proto = device->tproto; + + if (dev_is_sata(device)) { + task->ata_task.device_control_reg_update = 1; + if (force_phy_id >= 0) { + task->ata_task.force_phy = true; + task->ata_task.force_phy_id = force_phy_id; + } + memcpy(&task->ata_task.fis, parameter, para_len); + } else { + memcpy(&task->ssp_task, parameter, para_len); + } + + task->task_done = sas_task_internal_done; + task->tmf = tmf; + + task->slow_task->timer.function = sas_task_internal_timedout; + task->slow_task->timer.expires = jiffies + TASK_TIMEOUT; + add_timer(&task->slow_task->timer); + + res = i->dft->lldd_execute_task(task, GFP_KERNEL); + if (res) { + del_timer_sync(&task->slow_task->timer); + pr_err("executing TMF task failed %016llx (%d)\n", + SAS_ADDR(device->sas_addr), res); + break; + } + + wait_for_completion(&task->slow_task->completion); + + if (i->dft->lldd_tmf_exec_complete) + i->dft->lldd_tmf_exec_complete(device); + + res = TMF_RESP_FUNC_FAILED; + + if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + pr_err("TMF task timeout for %016llx and not done\n", + SAS_ADDR(device->sas_addr)); + if (i->dft->lldd_tmf_aborted) + i->dft->lldd_tmf_aborted(task); + break; + } + pr_warn("TMF task timeout for %016llx and done\n", + SAS_ADDR(device->sas_addr)); + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == TMF_RESP_FUNC_COMPLETE) { + res = TMF_RESP_FUNC_COMPLETE; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == TMF_RESP_FUNC_SUCC) { + res = TMF_RESP_FUNC_SUCC; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_DATA_UNDERRUN) { + /* no error, but return the number of bytes of + * underrun + */ + pr_warn("TMF task to dev %016llx resp: 0x%x sts 0x%x underrun\n", + SAS_ADDR(device->sas_addr), + task->task_status.resp, + task->task_status.stat); + res = task->task_status.residual; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_DATA_OVERRUN) { + pr_warn("TMF task blocked task error %016llx\n", + SAS_ADDR(device->sas_addr)); + res = -EMSGSIZE; + break; + } + + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_OPEN_REJECT) { + pr_warn("TMF task open reject failed %016llx\n", + SAS_ADDR(device->sas_addr)); + res = -EIO; + } else { + pr_warn("TMF task to dev %016llx resp: 0x%x status 0x%x\n", + SAS_ADDR(device->sas_addr), + task->task_status.resp, + task->task_status.stat); + } + sas_free_task(task); + task = NULL; + } + + if (retry == TASK_RETRY) + pr_warn("executing TMF for %016llx failed after %d attempts!\n", + SAS_ADDR(device->sas_addr), TASK_RETRY); + sas_free_task(task); + + return res; +} + +static int sas_execute_ssp_tmf(struct domain_device *device, u8 *lun, + struct sas_tmf_task *tmf) +{ + struct sas_ssp_task ssp_task; + + if (!(device->tproto & SAS_PROTOCOL_SSP)) + return TMF_RESP_FUNC_ESUPP; + + memcpy(ssp_task.LUN, lun, 8); + + return sas_execute_tmf(device, &ssp_task, sizeof(ssp_task), -1, tmf); +} + +int sas_abort_task_set(struct domain_device *dev, u8 *lun) +{ + struct sas_tmf_task tmf_task = { + .tmf = TMF_ABORT_TASK_SET, + }; + + return sas_execute_ssp_tmf(dev, lun, &tmf_task); +} +EXPORT_SYMBOL_GPL(sas_abort_task_set); + +int sas_clear_task_set(struct domain_device *dev, u8 *lun) +{ + struct sas_tmf_task tmf_task = { + .tmf = TMF_CLEAR_TASK_SET, + }; + + return sas_execute_ssp_tmf(dev, lun, &tmf_task); +} +EXPORT_SYMBOL_GPL(sas_clear_task_set); + +int sas_lu_reset(struct domain_device *dev, u8 *lun) +{ + struct sas_tmf_task tmf_task = { + .tmf = TMF_LU_RESET, + }; + + return sas_execute_ssp_tmf(dev, lun, &tmf_task); +} +EXPORT_SYMBOL_GPL(sas_lu_reset); + +int sas_query_task(struct sas_task *task, u16 tag) +{ + struct sas_tmf_task tmf_task = { + .tmf = TMF_QUERY_TASK, + .tag_of_task_to_be_managed = tag, + }; + struct scsi_cmnd *cmnd = task->uldd_task; + struct domain_device *dev = task->dev; + struct scsi_lun lun; + + int_to_scsilun(cmnd->device->lun, &lun); + + return sas_execute_ssp_tmf(dev, lun.scsi_lun, &tmf_task); +} +EXPORT_SYMBOL_GPL(sas_query_task); + +int sas_abort_task(struct sas_task *task, u16 tag) +{ + struct sas_tmf_task tmf_task = { + .tmf = TMF_ABORT_TASK, + .tag_of_task_to_be_managed = tag, + }; + struct scsi_cmnd *cmnd = task->uldd_task; + struct domain_device *dev = task->dev; + struct scsi_lun lun; + + int_to_scsilun(cmnd->device->lun, &lun); + + return sas_execute_ssp_tmf(dev, lun.scsi_lun, &tmf_task); +} +EXPORT_SYMBOL_GPL(sas_abort_task); /* * Tell an upper layer that it needs to initiate an abort for a given task. @@ -908,8 +1226,18 @@ void sas_task_abort(struct sas_task *task) if (dev_is_sata(task->dev)) sas_ata_task_abort(task); else - blk_abort_request(sc->request); + blk_abort_request(scsi_cmd_to_rq(sc)); } +EXPORT_SYMBOL_GPL(sas_task_abort); + +int sas_slave_alloc(struct scsi_device *sdev) +{ + if (dev_is_sata(sdev_to_domain_dev(sdev)) && sdev->lun) + return -ENXIO; + + return 0; +} +EXPORT_SYMBOL_GPL(sas_slave_alloc); void sas_target_destroy(struct scsi_target *starget) { @@ -921,6 +1249,7 @@ void sas_target_destroy(struct scsi_target *starget) starget->hostdata = NULL; sas_put_device(found_dev); } +EXPORT_SYMBOL_GPL(sas_target_destroy); #define SAS_STRING_ADDR_SIZE 16 @@ -948,14 +1277,3 @@ out: } EXPORT_SYMBOL_GPL(sas_request_addr); -EXPORT_SYMBOL_GPL(sas_queuecommand); -EXPORT_SYMBOL_GPL(sas_target_alloc); -EXPORT_SYMBOL_GPL(sas_slave_configure); -EXPORT_SYMBOL_GPL(sas_change_queue_depth); -EXPORT_SYMBOL_GPL(sas_bios_param); -EXPORT_SYMBOL_GPL(sas_task_abort); -EXPORT_SYMBOL_GPL(sas_phy_reset); -EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); -EXPORT_SYMBOL_GPL(sas_eh_target_reset_handler); -EXPORT_SYMBOL_GPL(sas_target_destroy); -EXPORT_SYMBOL_GPL(sas_ioctl); diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c index e2d42593ce52..e9d291007817 100644 --- a/drivers/scsi/libsas/sas_task.c +++ b/drivers/scsi/libsas/sas_task.c @@ -15,12 +15,15 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task, tstat->resp = SAS_TASK_COMPLETE; - if (iu->datapres == 0) + switch (iu->datapres) { + case SAS_DATAPRES_NO_DATA: tstat->stat = iu->status; - else if (iu->datapres == 1) + break; + case SAS_DATAPRES_RESPONSE_DATA: tstat->stat = iu->resp_data[3]; - else if (iu->datapres == 2) { - tstat->stat = SAM_STAT_CHECK_CONDITION; + break; + case SAS_DATAPRES_SENSE_DATA: + tstat->stat = SAS_SAM_STAT_CHECK_CONDITION; tstat->buf_valid_size = min_t(int, SAS_STATUS_BUF_SIZE, be32_to_cpu(iu->sense_data_len)); @@ -29,10 +32,11 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task, if (iu->status != SAM_STAT_CHECK_CONDITION) dev_warn(dev, "dev %016llx sent sense data, but stat(0x%x) is not CHECK CONDITION\n", SAS_ADDR(task->dev->sas_addr), iu->status); - } - else + break; + default: /* when datapres contains corrupt/unknown value... */ - tstat->stat = SAM_STAT_CHECK_CONDITION; + tstat->stat = SAS_SAM_STAT_CHECK_CONDITION; + } } EXPORT_SYMBOL_GPL(sas_ssp_task_response); |