scsi_error.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,846 行 · 第 1/4 页
C
1,846 行
struct scsi_device *sdev; shost_for_each_device(sdev, shost) { stu_scmd = NULL; list_for_each_entry(scmd, work_q, eh_entry) if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) && scsi_check_sense(scmd) == FAILED ) { stu_scmd = scmd; break; } if (!stu_scmd) continue; SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending START_UNIT to sdev:" " 0x%p\n", current->comm, sdev)); if (!scsi_eh_try_stu(stu_scmd)) { if (!scsi_device_online(sdev) || !scsi_eh_tur(stu_scmd)) { list_for_each_safe(lh, lh_sf, work_q) { scmd = list_entry(lh, struct scsi_cmnd, eh_entry); if (scmd->device == sdev) scsi_eh_finish_cmd(scmd, done_q); } } } else { SCSI_LOG_ERROR_RECOVERY(3, printk("%s: START_UNIT failed to sdev:" " 0x%p\n", current->comm, sdev)); } } return list_empty(work_q);}/** * scsi_eh_bus_device_reset - send bdr if needed * @shost: scsi host being recovered. * @eh_done_q: list_head for processed commands. * * Notes: * Try a bus device reset. still, look to see whether we have multiple * devices that are jammed or not - if we have multiple devices, it * makes no sense to try bus_device_reset - we really would need to try * a bus_reset instead. **/static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q){ struct list_head *lh, *lh_sf; struct scsi_cmnd *scmd, *bdr_scmd; struct scsi_device *sdev; int rtn; shost_for_each_device(sdev, shost) { bdr_scmd = NULL; list_for_each_entry(scmd, work_q, eh_entry) if (scmd->device == sdev) { bdr_scmd = scmd; break; } if (!bdr_scmd) continue; SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending BDR sdev:" " 0x%p\n", current->comm, sdev)); rtn = scsi_try_bus_device_reset(bdr_scmd); if (rtn == SUCCESS) { if (!scsi_device_online(sdev) || !scsi_eh_tur(bdr_scmd)) { list_for_each_safe(lh, lh_sf, work_q) { scmd = list_entry(lh, struct scsi_cmnd, eh_entry); if (scmd->device == sdev) scsi_eh_finish_cmd(scmd, done_q); } } } else { SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BDR" " failed sdev:" "0x%p\n", current->comm, sdev)); } } return list_empty(work_q);}/** * scsi_try_bus_reset - ask host to perform a bus reset * @scmd: SCSI cmd to send bus reset. **/static int scsi_try_bus_reset(struct scsi_cmnd *scmd){ unsigned long flags; int rtn; SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n", __FUNCTION__)); scmd->owner = SCSI_OWNER_LOWLEVEL; scmd->serial_number_at_timeout = scmd->serial_number; if (!scmd->device->host->hostt->eh_bus_reset_handler) return FAILED; spin_lock_irqsave(scmd->device->host->host_lock, flags); rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd); spin_unlock_irqrestore(scmd->device->host->host_lock, flags); if (rtn == SUCCESS) { if (!scmd->device->host->hostt->skip_settle_delay) ssleep(BUS_RESET_SETTLE_TIME); spin_lock_irqsave(scmd->device->host->host_lock, flags); scsi_report_bus_reset(scmd->device->host, scmd->device->channel); spin_unlock_irqrestore(scmd->device->host->host_lock, flags); } return rtn;}/** * scsi_try_host_reset - ask host adapter to reset itself * @scmd: SCSI cmd to send hsot reset. **/static int scsi_try_host_reset(struct scsi_cmnd *scmd){ unsigned long flags; int rtn; SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n", __FUNCTION__)); scmd->owner = SCSI_OWNER_LOWLEVEL; scmd->serial_number_at_timeout = scmd->serial_number; if (!scmd->device->host->hostt->eh_host_reset_handler) return FAILED; spin_lock_irqsave(scmd->device->host->host_lock, flags); rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd); spin_unlock_irqrestore(scmd->device->host->host_lock, flags); if (rtn == SUCCESS) { if (!scmd->device->host->hostt->skip_settle_delay) ssleep(HOST_RESET_SETTLE_TIME); spin_lock_irqsave(scmd->device->host->host_lock, flags); scsi_report_bus_reset(scmd->device->host, scmd->device->channel); spin_unlock_irqrestore(scmd->device->host->host_lock, flags); } return rtn;}/** * scsi_eh_bus_reset - send a bus reset * @shost: scsi host being recovered. * @eh_done_q: list_head for processed commands. **/static int scsi_eh_bus_reset(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q){ struct list_head *lh, *lh_sf; struct scsi_cmnd *scmd; struct scsi_cmnd *chan_scmd; unsigned int channel; int rtn; /* * we really want to loop over the various channels, and do this on * a channel by channel basis. we should also check to see if any * of the failed commands are on soft_reset devices, and if so, skip * the reset. */ for (channel = 0; channel <= shost->max_channel; channel++) { chan_scmd = NULL; list_for_each_entry(scmd, work_q, eh_entry) { if (channel == scmd->device->channel) { chan_scmd = scmd; break; /* * FIXME add back in some support for * soft_reset devices. */ } } if (!chan_scmd) continue; SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending BRST chan:" " %d\n", current->comm, channel)); rtn = scsi_try_bus_reset(chan_scmd); if (rtn == SUCCESS) { list_for_each_safe(lh, lh_sf, work_q) { scmd = list_entry(lh, struct scsi_cmnd, eh_entry); if (channel == scmd->device->channel) if (!scsi_device_online(scmd->device) || !scsi_eh_tur(scmd)) scsi_eh_finish_cmd(scmd, done_q); } } else { SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BRST" " failed chan: %d\n", current->comm, channel)); } } return list_empty(work_q);}/** * scsi_eh_host_reset - send a host reset * @work_q: list_head for processed commands. * @done_q: list_head for processed commands. **/static int scsi_eh_host_reset(struct list_head *work_q, struct list_head *done_q){ int rtn; struct list_head *lh, *lh_sf; struct scsi_cmnd *scmd; if (!list_empty(work_q)) { scmd = list_entry(work_q->next, struct scsi_cmnd, eh_entry); SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending HRST\n" , current->comm)); rtn = scsi_try_host_reset(scmd); if (rtn == SUCCESS) { list_for_each_safe(lh, lh_sf, work_q) { scmd = list_entry(lh, struct scsi_cmnd, eh_entry); if (!scsi_device_online(scmd->device) || (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) || !scsi_eh_tur(scmd)) scsi_eh_finish_cmd(scmd, done_q); } } else { SCSI_LOG_ERROR_RECOVERY(3, printk("%s: HRST" " failed\n", current->comm)); } } return list_empty(work_q);}/** * scsi_eh_offline_sdevs - offline scsi devices that fail to recover * @work_q: list_head for processed commands. * @done_q: list_head for processed commands. * **/static void scsi_eh_offline_sdevs(struct list_head *work_q, struct list_head *done_q){ struct list_head *lh, *lh_sf; struct scsi_cmnd *scmd; list_for_each_safe(lh, lh_sf, work_q) { scmd = list_entry(lh, struct scsi_cmnd, eh_entry); printk(KERN_INFO "scsi: Device offlined - not" " ready after error recovery: host" " %d channel %d id %d lun %d\n", scmd->device->host->host_no, scmd->device->channel, scmd->device->id, scmd->device->lun); scsi_device_set_state(scmd->device, SDEV_OFFLINE); if (scsi_eh_eflags_chk(scmd, SCSI_EH_CANCEL_CMD)) { /* * FIXME: Handle lost cmds. */ } scsi_eh_finish_cmd(scmd, done_q); } return;}/** * scsi_decide_disposition - Disposition a cmd on return from LLD. * @scmd: SCSI cmd to examine. * * Notes: * This is *only* called when we are examining the status after sending * out the actual data command. any commands that are queued for error * recovery (e.g. test_unit_ready) do *not* come through here. * * When this routine returns failed, it means the error handler thread * is woken. In cases where the error code indicates an error that * doesn't require the error handler read (i.e. we don't need to * abort/reset), this function should return SUCCESS. **/int scsi_decide_disposition(struct scsi_cmnd *scmd){ int rtn; /* * if the device is offline, then we clearly just pass the result back * up to the top level. */ if (!scsi_device_online(scmd->device)) { SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report" " as SUCCESS\n", __FUNCTION__)); return SUCCESS; } /* * first check the host byte, to see if there is anything in there * that would indicate what we need to do. */ switch (host_byte(scmd->result)) { case DID_PASSTHROUGH: /* * no matter what, pass this through to the upper layer. * nuke this special code so that it looks like we are saying * did_ok. */ scmd->result &= 0xff00ffff; return SUCCESS; case DID_OK: /* * looks good. drop through, and check the next byte. */ break; case DID_NO_CONNECT: case DID_BAD_TARGET: case DID_ABORT: /* * note - this means that we just report the status back * to the top level driver, not that we actually think * that it indicates SUCCESS. */ return SUCCESS; /* * when the low level driver returns did_soft_error, * it is responsible for keeping an internal retry counter * in order to avoid endless loops (db) * * actually this is a bug in this function here. we should * be mindful of the maximum number of retries specified * and not get stuck in a loop. */ case DID_SOFT_ERROR: goto maybe_retry; case DID_IMM_RETRY: return NEEDS_RETRY; case DID_ERROR: if (msg_byte(scmd->result) == COMMAND_COMPLETE && status_byte(scmd->result) == RESERVATION_CONFLICT) /* * execute reservation conflict processing code * lower down */ break; /* fallthrough */ case DID_BUS_BUSY: case DID_PARITY: goto maybe_retry; case DID_TIME_OUT: /* * when we scan the bus, we get timeout messages for * these commands if there is no device available. * other hosts report did_no_connect for the same thing. */ if ((scmd->cmnd[0] == TEST_UNIT_READY || scmd->cmnd[0] == INQUIRY)) { return SUCCESS; } else { return FAILED; } case DID_RESET: return SUCCESS; default: return FAILED; } /* * next, check the message byte. */ if (msg_byte(scmd->result) != COMMAND_COMPLETE) return FAILED; /* * check the status byte to see if this indicates anything special. */ switch (status_byte(scmd->result)) { case QUEUE_FULL: /* * the case of trying to send too many commands to a * tagged queueing device. */ case BUSY: /* * device can't talk to us at the moment. Should only * occur (SAM-3) when the task queue is empty, so will cause * the empty queue handling to trigger a stall in the * device. */ return ADD_TO_MLQUEUE; case GOOD: case COMMAND_TERMINATED: return SUCCESS; case CHECK_CONDITION: rtn = scsi_check_sense(scmd); if (rtn == NEEDS_RETRY) goto maybe_retry; /* if rtn == FAILED, we have no sense information; * returning FAILED will wake the error handler thread * to collect the sense and redo the decide * disposition */ return rtn; case CONDITION_GOOD: case INTERMEDIATE_GOOD: case INTERMEDIATE_C_GOOD: /* * who knows? FIXME(eric) */ return SUCCESS; case RESERVATION_CONFLICT: printk("scsi%d (%d,%d,%d) : reservation conflict\n", scmd->device->host->host_no, scmd->device->channel, scmd->device->id, scmd->device->lun); return SUCCESS; /* causes immediate i/o error */ default: return FAILED; } return FAILED; maybe_retry: /* we requeue for retry because the error was retryable, and * the request was not marked fast fail. Note that above, * even if the request is marked fast fail, we still requeue * for queue congestion conditions (QUEUE_FULL or BUSY) */ if ((++scmd->retries) < scmd->allowed && !blk_noretry_request(scmd->request)) { return NEEDS_RETRY; } else { /* * no more retries - report this one back to upper level. */ return SUCCESS; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?