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 + -
显示快捷键?