X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Flibsas%2Fsas_scsi_host.c;h=1c558d3bce18c4817623078944e86557eb3adb9f;hb=94be9a58d7e683ac3c1df1858a17f09ebade8da0;hp=0dc7c02b38374f0f2d23096b5338794dbcdcd135;hpb=0281e02c5671f50701924465744edd3e2feb5d6f;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 0dc7c02..1c558d3 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -24,6 +24,8 @@ */ #include +#include +#include #include "sas_internal.h" @@ -34,6 +36,7 @@ #include #include #include +#include #include "../scsi_sas_internal.h" #include "../scsi_transport_api.h" #include "../scsi_priv.h" @@ -46,17 +49,18 @@ /* ---------- SCSI Host glue ---------- */ -#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble) -#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0) - static void sas_scsi_task_done(struct sas_task *task) { struct task_status_struct *ts = &task->task_status; struct scsi_cmnd *sc = task->uldd_task; - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(sc->device->host); - unsigned ts_flags = task->task_state_flags; int hs = 0, stat = 0; + if (unlikely(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + /* Aborted tasks will be completed by the error handler */ + SAS_DPRINTK("task done but aborted\n"); + return; + } + if (unlikely(!sc)) { SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n"); list_del_init(&task->list); @@ -110,7 +114,7 @@ static void sas_scsi_task_done(struct sas_task *task) break; case SAM_CHECK_COND: memcpy(sc->sense_buffer, ts->buf, - max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); + min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); stat = SAM_CHECK_COND; break; default: @@ -122,11 +126,7 @@ static void sas_scsi_task_done(struct sas_task *task) sc->result = (hs << 16) | stat; list_del_init(&task->list); sas_free_task(task); - /* This is very ugly but this is how SCSI Core works. */ - if (ts_flags & SAS_TASK_STATE_ABORTED) - scsi_eh_finish_cmd(sc, &sas_ha->eh_done_q); - else - sc->scsi_done(sc); + sc->scsi_done(sc); } static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd) @@ -150,7 +150,6 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, if (!task) return NULL; - *(u32 *)cmd->sense_buffer = 0; task->uldd_task = cmd; ASSIGN_SAS_TASK(cmd, task); @@ -173,7 +172,7 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, return task; } -static int sas_queue_up(struct sas_task *task) +int sas_queue_up(struct sas_task *task) { struct sas_ha_struct *sas_ha = task->dev->port->ha; struct scsi_core *core = &sas_ha->core; @@ -193,11 +192,6 @@ static int sas_queue_up(struct sas_task *task) return 0; } -static inline int dev_is_sata(struct domain_device *dev) -{ - return (dev->rphy->identify.target_port_protocols & SAS_PROTOCOL_SATA); -} - /** * sas_queuecommand -- Enqueue a command for processing * @parameters: See SCSI Core documentation @@ -207,6 +201,10 @@ static inline int dev_is_sata(struct domain_device *dev) */ int sas_queuecommand(struct scsi_cmnd *cmd, void (*scsi_done)(struct scsi_cmnd *)) + __releases(host->host_lock) + __acquires(dev->sata_dev.ap->lock) + __releases(dev->sata_dev.ap->lock) + __acquires(host->host_lock) { int res = 0; struct domain_device *dev = cmd_to_domain_dev(cmd); @@ -220,8 +218,12 @@ int sas_queuecommand(struct scsi_cmnd *cmd, struct sas_task *task; if (dev_is_sata(dev)) { + unsigned long flags; + + spin_lock_irqsave(dev->sata_dev.ap->lock, flags); res = ata_sas_queuecmd(cmd, scsi_done, dev->sata_dev.ap); + spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags); goto out; } @@ -255,13 +257,34 @@ out: return res; } +static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) +{ + struct sas_task *task = TO_SAS_TASK(cmd); + struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host); + + /* remove the aborted task flag to allow the task to be + * completed now. At this point, we only get called following + * an actual abort of the task, so we should be guaranteed not + * to be racing with any completions from the LLD (hence we + * don't need the task state lock to clear the flag) */ + task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; + /* Now call task_done. However, task will be free'd after + * this */ + task->task_done(task); + /* now finish the command and move it on to the error + * handler done list, this also takes it off the + * error handler pending list */ + scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); +} + static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) { struct scsi_cmnd *cmd, *n; list_for_each_entry_safe(cmd, n, error_q, eh_entry) { - if (cmd == my_cmd) - list_del_init(&cmd->eh_entry); + if (cmd->device->sdev_target == my_cmd->device->sdev_target && + cmd->device->lun == my_cmd->device->lun) + sas_eh_finish_cmd(cmd); } } @@ -274,7 +297,7 @@ static void sas_scsi_clear_queue_I_T(struct list_head *error_q, struct domain_device *x = cmd_to_domain_dev(cmd); if (x == dev) - list_del_init(&cmd->eh_entry); + sas_eh_finish_cmd(cmd); } } @@ -288,7 +311,7 @@ static void sas_scsi_clear_queue_port(struct list_head *error_q, struct asd_sas_port *x = dev->port; if (x == port) - list_del_init(&cmd->eh_entry); + sas_eh_finish_cmd(cmd); } } @@ -320,7 +343,7 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) flags); SAS_DPRINTK("%s: task 0x%p aborted from " "task_queue\n", - __FUNCTION__, task); + __func__, task); return TASK_IS_ABORTED; } } @@ -328,13 +351,13 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) } for (i = 0; i < 5; i++) { - SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); + SAS_DPRINTK("%s: aborting task 0x%p\n", __func__, task); res = si->dft->lldd_abort_task(task); spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { spin_unlock_irqrestore(&task->task_state_lock, flags); - SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, + SAS_DPRINTK("%s: task 0x%p is done\n", __func__, task); return TASK_IS_DONE; } @@ -342,24 +365,24 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) if (res == TMF_RESP_FUNC_COMPLETE) { SAS_DPRINTK("%s: task 0x%p is aborted\n", - __FUNCTION__, task); + __func__, task); return TASK_IS_ABORTED; } else if (si->dft->lldd_query_task) { SAS_DPRINTK("%s: querying task 0x%p\n", - __FUNCTION__, task); + __func__, task); res = si->dft->lldd_query_task(task); switch (res) { case TMF_RESP_FUNC_SUCC: SAS_DPRINTK("%s: task 0x%p at LU\n", - __FUNCTION__, task); + __func__, task); return TASK_IS_AT_LU; case TMF_RESP_FUNC_COMPLETE: SAS_DPRINTK("%s: task 0x%p not at LU\n", - __FUNCTION__, task); + __func__, task); return TASK_IS_NOT_AT_LU; case TMF_RESP_FUNC_FAILED: SAS_DPRINTK("%s: task 0x%p failed to abort\n", - __FUNCTION__, task); + __func__, task); return TASK_ABORT_FAILED; } @@ -413,7 +436,7 @@ static int sas_recover_I_T(struct domain_device *dev) } /* Find the sas_phy that's attached to this device */ -struct sas_phy *find_local_sas_phy(struct domain_device *dev) +struct sas_phy *sas_find_local_phy(struct domain_device *dev) { struct domain_device *pdev = dev->parent; struct ex_phy *exphy = NULL; @@ -435,6 +458,7 @@ struct sas_phy *find_local_sas_phy(struct domain_device *dev) BUG_ON(!exphy); return exphy->phy; } +EXPORT_SYMBOL_GPL(sas_find_local_phy); /* Attempt to send a LUN reset message to a device */ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) @@ -461,13 +485,13 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) { struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_phy *phy = find_local_sas_phy(dev); + struct sas_phy *phy = sas_find_local_phy(dev); int res; res = sas_phy_reset(phy, 1); if (res) SAS_DPRINTK("Bus reset of %s failed 0x%x\n", - phy->dev.kobj.k_name, + kobject_name(&phy->dev.kobj), res); if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) return SUCCESS; @@ -476,10 +500,10 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) } /* Try to reset a device */ -static int try_to_reset_cmd_device(struct Scsi_Host *shost, - struct scsi_cmnd *cmd) +static int try_to_reset_cmd_device(struct scsi_cmnd *cmd) { int res; + struct Scsi_Host *shost = cmd->device->host; if (!shost->hostt->eh_device_reset_handler) goto try_bus_reset; @@ -519,6 +543,12 @@ Again: need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; spin_unlock_irqrestore(&task->task_state_lock, flags); + if (need_reset) { + SAS_DPRINTK("%s: task 0x%p requests reset\n", + __func__, task); + goto reset; + } + SAS_DPRINTK("trying to find task 0x%p\n", task); res = sas_scsi_find_task(task); @@ -526,30 +556,25 @@ Again: switch (res) { case TASK_IS_DONE: - SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, + SAS_DPRINTK("%s: task 0x%p is done\n", __func__, task); - task->task_done(task); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); + sas_eh_finish_cmd(cmd); continue; case TASK_IS_ABORTED: SAS_DPRINTK("%s: task 0x%p is aborted\n", - __FUNCTION__, task); - task->task_done(task); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); + __func__, task); + sas_eh_finish_cmd(cmd); continue; case TASK_IS_AT_LU: SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); + reset: tmf_resp = sas_recover_lu(task->dev, cmd); if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { SAS_DPRINTK("dev %016llx LU %x is " "recovered\n", SAS_ADDR(task->dev), cmd->device->lun); - task->task_done(task); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); + sas_eh_finish_cmd(cmd); sas_scsi_clear_queue_lu(work_q, cmd); goto Again; } @@ -560,15 +585,15 @@ Again: task); tmf_resp = sas_recover_I_T(task->dev); if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { + struct domain_device *dev = task->dev; SAS_DPRINTK("I_T %016llx recovered\n", SAS_ADDR(task->dev->sas_addr)); - task->task_done(task); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); - sas_scsi_clear_queue_I_T(work_q, task->dev); + sas_eh_finish_cmd(cmd); + sas_scsi_clear_queue_I_T(work_q, dev); goto Again; } /* Hammer time :-) */ + try_to_reset_cmd_device(cmd); if (i->dft->lldd_clear_nexus_port) { struct asd_sas_port *port = task->dev->port; SAS_DPRINTK("clearing nexus for port:%d\n", @@ -577,9 +602,7 @@ Again: if (res == TMF_RESP_FUNC_COMPLETE) { SAS_DPRINTK("clear nexus port:%d " "succeeded\n", port->id); - task->task_done(task); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); + sas_eh_finish_cmd(cmd); sas_scsi_clear_queue_port(work_q, port); goto Again; @@ -591,10 +614,8 @@ Again: if (res == TMF_RESP_FUNC_COMPLETE) { SAS_DPRINTK("clear nexus ha " "succeeded\n"); - task->task_done(task); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); - goto out; + sas_eh_finish_cmd(cmd); + goto clear_q; } } /* If we are here -- this means that no amount @@ -606,21 +627,16 @@ Again: SAS_ADDR(task->dev->sas_addr), cmd->device->lun); - task->task_done(task); - if (need_reset) - try_to_reset_cmd_device(shost, cmd); + sas_eh_finish_cmd(cmd); goto clear_q; } } -out: return list_empty(work_q); clear_q: - SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); - list_for_each_entry_safe(cmd, n, work_q, eh_entry) { - struct sas_task *task = TO_SAS_TASK(cmd); - list_del_init(&cmd->eh_entry); - task->task_done(task); - } + SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); + list_for_each_entry_safe(cmd, n, work_q, eh_entry) + sas_eh_finish_cmd(cmd); + return list_empty(work_q); } @@ -634,7 +650,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) list_splice_init(&shost->eh_cmd_q, &eh_work_q); spin_unlock_irqrestore(shost->host_lock, flags); - SAS_DPRINTK("Enter %s\n", __FUNCTION__); + SAS_DPRINTK("Enter %s\n", __func__); /* * Deal with commands that still have SAS tasks (i.e. they didn't * complete via the normal sas_task completion mechanism) @@ -653,134 +669,47 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) out: scsi_eh_flush_done_q(&ha->eh_done_q); - SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); + SAS_DPRINTK("--- Exit %s\n", __func__); return; } -enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) +enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) { struct sas_task *task = TO_SAS_TASK(cmd); unsigned long flags; if (!task) { - cmd->timeout_per_command /= 2; + cmd->request->timeout /= 2; SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n", - cmd, task, (cmd->timeout_per_command ? - "EH_RESET_TIMER" : "EH_NOT_HANDLED")); - if (!cmd->timeout_per_command) - return EH_NOT_HANDLED; - return EH_RESET_TIMER; + cmd, task, (cmd->request->timeout ? + "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED")); + if (!cmd->request->timeout) + return BLK_EH_NOT_HANDLED; + return BLK_EH_RESET_TIMER; } spin_lock_irqsave(&task->task_state_lock, flags); BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED); if (task->task_state_flags & SAS_TASK_STATE_DONE) { spin_unlock_irqrestore(&task->task_state_lock, flags); - SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", - cmd, task); - return EH_HANDLED; + SAS_DPRINTK("command 0x%p, task 0x%p, timed out: " + "BLK_EH_HANDLED\n", cmd, task); + return BLK_EH_HANDLED; } if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) { spin_unlock_irqrestore(&task->task_state_lock, flags); SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: " - "EH_RESET_TIMER\n", + "BLK_EH_RESET_TIMER\n", cmd, task); - return EH_RESET_TIMER; + return BLK_EH_RESET_TIMER; } task->task_state_flags |= SAS_TASK_STATE_ABORTED; spin_unlock_irqrestore(&task->task_state_lock, flags); - SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n", + SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n", cmd, task); - return EH_NOT_HANDLED; -} - - -static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts) -{ - /* Cheesy attempt to translate SAS errors into ATA. Hah! */ - - /* transport error */ - if (ts->resp == SAS_TASK_UNDELIVERED) - return AC_ERR_ATA_BUS; - - /* 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 SAM_CHECK_COND: - case SAS_OPEN_TO: - case SAS_OPEN_REJECT: - SAS_DPRINTK("%s: Saw error %d. What to do?\n", - __FUNCTION__, ts->stat); - return AC_ERR_OTHER; - - 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; - } -} - -static void sas_ata_task_done(struct sas_task *task) -{ - struct ata_queued_cmd *qc = task->uldd_task; - struct domain_device *dev = qc->ap->private_data; - struct task_status_struct *stat = &task->task_status; - struct ata_task_resp *resp = (struct ata_task_resp *)stat->buf; - enum ata_completion_errors ac; - - if (stat->stat == SAS_PROTO_RESPONSE) { - ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf); - qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command); - dev->sata_dev.sstatus = resp->sstatus; - dev->sata_dev.serror = resp->serror; - dev->sata_dev.scontrol = resp->scontrol; - dev->sata_dev.ap->sactive = resp->sactive; - } else if (stat->stat != SAM_STAT_GOOD) { - ac = sas_to_ata_err(stat); - if (ac) { - SAS_DPRINTK("%s: SAS error %x\n", __FUNCTION__, - stat->stat); - /* We saw a SAS error. Send a vague error. */ - qc->err_mask = ac; - dev->sata_dev.tf.feature = 0x04; /* status err */ - dev->sata_dev.tf.command = ATA_ERR; - } - } - - ata_qc_complete(qc); - list_del_init(&task->list); - sas_free_task(task); + return BLK_EH_NOT_HANDLED; } int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) @@ -788,205 +717,11 @@ int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) struct domain_device *dev = sdev_to_domain_dev(sdev); if (dev_is_sata(dev)) - return ata_scsi_ioctl(sdev, cmd, arg); + return ata_sas_scsi_ioctl(dev->sata_dev.ap, sdev, cmd, arg); return -EINVAL; } -static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) -{ - int res = -ENOMEM; - struct sas_task *task; - struct domain_device *dev = qc->ap->private_data; - struct sas_ha_struct *sas_ha = dev->port->ha; - struct Scsi_Host *host = sas_ha->core.shost; - struct sas_internal *i = to_sas_internal(host->transportt); - struct scatterlist *sg; - unsigned int num = 0; - unsigned int xfer = 0; - - task = sas_alloc_task(GFP_ATOMIC); - if (!task) - goto out; - task->dev = dev; - 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) { - /* Need to zero out the tag libata assigned us */ - qc->tf.nsect = 0; - } - - ata_tf_to_fis(&qc->tf, (u8*)&task->ata_task.fis, 0); - task->uldd_task = qc; - if (is_atapi_taskfile(&qc->tf)) { - memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len); - task->total_xfer_len = qc->nbytes + qc->pad_len; - task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem; - } else { - ata_for_each_sg(sg, qc) { - num++; - xfer += sg->length; - } - - task->total_xfer_len = xfer; - task->num_scatter = num; - } - - task->data_dir = qc->dma_dir; - task->scatter = qc->__sg; - task->ata_task.retry_count = 1; - task->task_state_flags = SAS_TASK_STATE_PENDING; - - switch (qc->tf.protocol) { - case ATA_PROT_NCQ: - task->ata_task.use_ncq = 1; - /* fall through */ - case ATA_PROT_ATAPI_DMA: - case ATA_PROT_DMA: - task->ata_task.dma_xfer = 1; - break; - } - - if (sas_ha->lldd_max_execute_num < 2) - res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); - else - res = sas_queue_up(task); - - /* Examine */ - if (res) { - SAS_DPRINTK("lldd_execute_task returned: %d\n", res); - - sas_free_task(task); - if (res == -SAS_QUEUE_FULL) - return -ENOMEM; - } - -out: - return res; -} - -static u8 sas_ata_check_status(struct ata_port *ap) -{ - struct domain_device *dev = ap->private_data; - return dev->sata_dev.tf.command; -} - -static void sas_ata_phy_reset(struct ata_port *ap) -{ - struct domain_device *dev = ap->private_data; - struct sas_internal *i = - to_sas_internal(dev->port->ha->core.shost->transportt); - int res = 0; - - if (i->dft->lldd_I_T_nexus_reset) - res = i->dft->lldd_I_T_nexus_reset(dev); - - if (res) - SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__); - - switch (dev->sata_dev.command_set) { - case ATA_COMMAND_SET: - SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__); - ap->device[0].class = ATA_DEV_ATA; - break; - case ATAPI_COMMAND_SET: - SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__); - ap->device[0].class = ATA_DEV_ATAPI; - break; - default: - SAS_DPRINTK("%s: Unknown SATA command set: %d.\n", - __FUNCTION__, - dev->sata_dev.command_set); - ap->device[0].class = ATA_DEV_ATA; - break; - } - - ap->cbl = ATA_CBL_SATA; -} - -static void sas_ata_post_internal(struct ata_queued_cmd *qc) -{ - if (qc->flags & ATA_QCFLAG_FAILED) - qc->err_mask |= AC_ERR_OTHER; - - if (qc->err_mask) - SAS_DPRINTK("%s: Failure; reset phy!\n", __FUNCTION__); -} - -static void sas_ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) -{ - struct domain_device *dev = ap->private_data; - memcpy(tf, &dev->sata_dev.tf, sizeof (*tf)); -} - -static void sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in, - u32 val) -{ - struct domain_device *dev = ap->private_data; - - SAS_DPRINTK("STUB %s\n", __FUNCTION__); - switch (sc_reg_in) { - case SCR_STATUS: - dev->sata_dev.sstatus = val; - break; - case SCR_CONTROL: - dev->sata_dev.scontrol = val; - break; - case SCR_ERROR: - dev->sata_dev.serror = val; - break; - case SCR_ACTIVE: - dev->sata_dev.ap->sactive = val; - break; - } -} - -static u32 sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in) -{ - struct domain_device *dev = ap->private_data; - - SAS_DPRINTK("STUB %s\n", __FUNCTION__); - switch (sc_reg_in) { - case SCR_STATUS: - return dev->sata_dev.sstatus; - case SCR_CONTROL: - return dev->sata_dev.scontrol; - case SCR_ERROR: - return dev->sata_dev.serror; - case SCR_ACTIVE: - return dev->sata_dev.ap->sactive; - default: - return 0xffffffffU; - } -} - -static struct ata_port_operations sas_sata_ops = { - .port_disable = ata_port_disable, - .check_status = sas_ata_check_status, - .check_altstatus = sas_ata_check_status, - .dev_select = ata_noop_dev_select, - .phy_reset = sas_ata_phy_reset, - .post_internal_cmd = sas_ata_post_internal, - .tf_read = sas_ata_tf_read, - .qc_prep = ata_noop_qc_prep, - .qc_issue = sas_ata_qc_issue, - .port_start = ata_sas_port_start, - .port_stop = ata_sas_port_stop, - .scr_read = sas_ata_scr_read, - .scr_write = sas_ata_scr_write -}; - -static struct ata_port_info sata_port_info = { - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | - ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ, - .pio_mask = 0x1f, /* PIO0-4 */ - .mwdma_mask = 0x07, /* MWDMA0-2 */ - .udma_mask = ATA_UDMA6, - .port_ops = &sas_sata_ops -}; - struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) { struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent); @@ -1025,32 +760,16 @@ static inline struct domain_device *sas_find_target(struct scsi_target *starget) int sas_target_alloc(struct scsi_target *starget) { - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); struct domain_device *found_dev = sas_find_target(starget); + int res; if (!found_dev) return -ENODEV; if (dev_is_sata(found_dev)) { - struct ata_port *ap; - - ata_host_init(&found_dev->sata_dev.ata_host, - &ha->pcidev->dev, - sata_port_info.flags, - &sas_sata_ops); - ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host, - &sata_port_info, - shost); - if (!ap) { - SAS_DPRINTK("ata_sas_port_alloc failed.\n"); - return -ENODEV; - } - - ap->private_data = found_dev; - ap->cbl = ATA_CBL_SATA; - ap->scsi_host = shost; - found_dev->sata_dev.ap = ap; + res = sas_ata_init_host_and_port(found_dev, starget); + if (res) + return res; } starget->hostdata = found_dev; @@ -1271,7 +990,7 @@ int __sas_task_abort(struct sas_task *task) if (task->task_state_flags & SAS_TASK_STATE_ABORTED || task->task_state_flags & SAS_TASK_STATE_DONE) { spin_unlock_irqrestore(&task->task_state_lock, flags); - SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__, + SAS_DPRINTK("%s: Task %p already finished.\n", __func__, task); return 0; } @@ -1315,7 +1034,12 @@ void sas_task_abort(struct sas_task *task) return; } - scsi_req_abort_cmd(sc); + if (dev_is_sata(task->dev)) { + sas_ata_task_abort(task); + return; + } + + blk_abort_request(sc->request); scsi_schedule_eh(sc->device->host); } @@ -1342,6 +1066,45 @@ void sas_target_destroy(struct scsi_target *starget) return; } +static void sas_parse_addr(u8 *sas_addr, const char *p) +{ + int i; + for (i = 0; i < SAS_ADDR_SIZE; i++) { + u8 h, l; + if (!*p) + break; + h = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10; + p++; + l = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10; + p++; + sas_addr[i] = (h<<4) | l; + } +} + +#define SAS_STRING_ADDR_SIZE 16 + +int sas_request_addr(struct Scsi_Host *shost, u8 *addr) +{ + int res; + const struct firmware *fw; + + res = request_firmware(&fw, "sas_addr", &shost->shost_gendev); + if (res) + return res; + + if (fw->size < SAS_STRING_ADDR_SIZE) { + res = -ENODEV; + goto out; + } + + sas_parse_addr(addr, fw->data); + +out: + release_firmware(fw); + return res; +} +EXPORT_SYMBOL_GPL(sas_request_addr); + EXPORT_SYMBOL_GPL(sas_queuecommand); EXPORT_SYMBOL_GPL(sas_target_alloc); EXPORT_SYMBOL_GPL(sas_slave_configure);