int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{ struct sas_internal *i = to_sas_internal(host->transportt); struct domain_device *dev = cmd_to_domain_dev(cmd); struct sas_task *task; int res = 0;
/* If the device fell off, no sense in issuing commands */ if (test_bit(SAS_DEV_GONE, &dev->state)) {
cmd->result = DID_BAD_TARGET << 16; goto out_done;
}
if (dev_is_sata(dev)) {
spin_lock_irq(dev->sata_dev.ap->lock);
res = ata_sas_queuecmd(cmd, dev->sata_dev.ap);
spin_unlock_irq(dev->sata_dev.ap->lock); return res;
}
task = sas_create_task(cmd, dev, GFP_ATOMIC); if (!task) return SCSI_MLQUEUE_HOST_BUSY;
res = i->dft->lldd_execute_task(task, GFP_ATOMIC); if (res) goto out_free_task; return0;
/* At this point, we only get called following an actual abort *ofthetask,soweshouldbeguaranteednottoberacingwith *anycompletionsfromtheLLD.Taskisfreedafterthis.
*/
sas_end_task(cmd, task);
if (dev_is_sata(dev)) { /* defer commands to libata so that libata EH can *handleataqcscorrectly
*/
list_move_tail(&cmd->eh_entry, &sas_ha->eh_ata_q); return;
}
/* now finish the command and move it on to the error *handlerdonelist,thisalsotakesitoffthe *errorhandlerpendinglist.
*/
scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q);
}
if (res == TMF_RESP_FUNC_COMPLETE) {
pr_notice("%s: task 0x%p is aborted\n",
__func__, task); return TASK_IS_ABORTED;
} elseif (si->dft->lldd_query_task) {
pr_notice("%s: querying task 0x%p\n", __func__, task);
res = si->dft->lldd_query_task(task); switch (res) { case TMF_RESP_FUNC_SUCC:
pr_notice("%s: task 0x%p at LU\n", __func__,
task); return TASK_IS_AT_LU; case TMF_RESP_FUNC_COMPLETE:
pr_notice("%s: task 0x%p not at LU\n",
__func__, task); return TASK_IS_NOT_AT_LU; case TMF_RESP_FUNC_FAILED:
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 TASK_ABORT_FAILED;
}
staticint sas_recover_lu(struct domain_device *dev, struct scsi_cmnd *cmd)
{ int res = TMF_RESP_FUNC_FAILED; struct scsi_lun lun; struct sas_internal *i =
to_sas_internal(dev->port->ha->shost->transportt);
int_to_scsilun(cmd->device->lun, &lun);
pr_notice("eh: device %016llx LUN 0x%llx has the task\n",
SAS_ADDR(dev->sas_addr),
cmd->device->lun);
if (i->dft->lldd_abort_task_set)
res = i->dft->lldd_abort_task_set(dev, lun.scsi_lun);
if (res == TMF_RESP_FUNC_FAILED) { if (i->dft->lldd_clear_task_set)
res = i->dft->lldd_clear_task_set(dev, lun.scsi_lun);
}
if (res == TMF_RESP_FUNC_FAILED) { if (i->dft->lldd_lu_reset)
res = i->dft->lldd_lu_reset(dev, lun.scsi_lun);
}
return res;
}
staticint sas_recover_I_T(struct domain_device *dev)
{ int res = TMF_RESP_FUNC_FAILED; struct sas_internal *i =
to_sas_internal(dev->port->ha->shost->transportt);
pr_notice("I_T nexus reset for dev %016llx\n",
SAS_ADDR(dev->sas_addr));
if (i->dft->lldd_I_T_nexus_reset)
res = i->dft->lldd_I_T_nexus_reset(dev);
return res;
}
/* take a reference on the last known good phy for this device */ struct sas_phy *sas_get_local_phy(struct domain_device *dev)
{ struct sas_ha_struct *ha = dev->port->ha; struct sas_phy *phy; unsignedlong flags;
/* a published domain device always has a valid phy, it may be *stale,butitisneverNULL
*/
BUG_ON(!dev->phy);
spin_lock_irqsave(host->host_lock, flags); /* We cannot do async aborts for SATA devices */ if (dev_is_sata(dev) && !host->host_eh_scheduled) {
spin_unlock_irqrestore(host->host_lock, flags); return FAILED;
}
spin_unlock_irqrestore(host->host_lock, flags);
if (task)
res = i->dft->lldd_abort_task(task); else
pr_notice("no task to abort\n"); if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) return SUCCESS;
/* clean out any commands that won the completion vs eh race */
list_for_each_entry_safe(cmd, n, work_q, eh_entry) { struct domain_device *dev = cmd_to_domain_dev(cmd); struct sas_task *task;
spin_lock_irqsave(&dev->done_lock, flags); /* by this point the lldd has either observed *SAS_HA_FROZENandisleavingthetaskalone,orhas *wontheracewithehanddecidedtocompleteit
*/
task = TO_SAS_TASK(cmd);
spin_unlock_irqrestore(&dev->done_lock, flags);
if (!task)
list_move_tail(&cmd->eh_entry, &done);
}
pr_debug("trying to find task 0x%p\n", task);
res = sas_scsi_find_task(task);
switch (res) { case TASK_IS_DONE:
pr_notice("%s: task 0x%p is done\n", __func__,
task);
sas_eh_finish_cmd(cmd); continue; case TASK_IS_ABORTED:
pr_notice("%s: task 0x%p is aborted\n",
__func__, task);
sas_eh_finish_cmd(cmd); continue; case TASK_IS_AT_LU:
pr_info("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) {
pr_notice("dev %016llx LU 0x%llx is recovered\n",
SAS_ADDR(task->dev),
cmd->device->lun);
sas_eh_finish_cmd(cmd);
sas_scsi_clear_queue_lu(work_q, cmd); goto Again;
}
fallthrough; case TASK_IS_NOT_AT_LU: case TASK_ABORT_FAILED:
pr_notice("task 0x%p is not at LU: I_T recover\n",
task);
tmf_resp = sas_recover_I_T(task->dev); if (tmf_resp == TMF_RESP_FUNC_COMPLETE ||
tmf_resp == -ENODEV) { struct domain_device *dev = task->dev;
pr_notice("I_T %016llx recovered\n",
SAS_ADDR(task->dev->sas_addr));
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;
pr_debug("clearing nexus for port:%d\n",
port->id);
res = i->dft->lldd_clear_nexus_port(port); if (res == TMF_RESP_FUNC_COMPLETE) {
pr_notice("clear nexus port:%d succeeded\n",
port->id);
sas_eh_finish_cmd(cmd);
sas_scsi_clear_queue_port(work_q,
port); goto Again;
}
} if (i->dft->lldd_clear_nexus_ha) {
pr_debug("clear nexus ha\n");
res = i->dft->lldd_clear_nexus_ha(ha); if (res == TMF_RESP_FUNC_COMPLETE) {
pr_notice("clear nexus ha succeeded\n");
sas_eh_finish_cmd(cmd); goto clear_q;
}
} /* If we are here -- this means that no amount *ofeffortcouldrecoverfromerrors.Quite *possiblytheHAjustdisappeared.
*/
pr_err("error from device %016llx, LUN 0x%llx couldn't be recovered in any way\n",
SAS_ADDR(task->dev->sas_addr),
cmd->device->lun);
/* now link into libata eh --- if we have any ata devices */
sas_ata_strategy_handler(shost);
scsi_eh_flush_done_q(&ha->eh_done_q);
/* check if any new eh work was scheduled during the last run */
spin_lock_irq(&ha->lock); if (ha->eh_active == 0) {
shost->host_eh_scheduled = 0;
retry = false;
}
spin_unlock_irq(&ha->lock);
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_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);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.