微視linux scsi驅動超時錯誤處理

超時錯誤處理從底層看起

int usb_stor_control_thread(void * __us)
{
	for(;;) {
		us->proto_handler(us->srb, us);	
		=>void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
		{
			result = us->transport(srb, us);
			=>int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
			{
				result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, cbwlen, NULL);
				=>int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, unsigned int *act_len)
				{
					/* fill and submit the URB */
					usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
							  usb_stor_blocking_completion, NULL);
					result = usb_stor_msg_common(us, 0);
					=>int usb_stor_msg_common(struct us_data *us, int timeout)
					{
						struct completion urb_done;
						long timeleft;
						int status;

						/* don't submit URBs during abort processing */
						if (test_bit(US_FLIDX_ABORTING, &us->dflags))
							return -EIO;

						/* set up data structures for the wakeup system */
						init_completion(&urb_done);

						/* fill the common fields in the URB */
						us->current_urb->context = &urb_done;
						us->current_urb->actual_length = 0;
						us->current_urb->error_count = 0;
						us->current_urb->status = 0;

						/* we assume that if transfer_buffer isn't us->iobuf then it
						 * hasn't been mapped for DMA.  Yes, this is clunky, but it's
						 * easier than always having the caller tell us whether the
						 * transfer buffer has already been mapped. */
						us->current_urb->transfer_flags = URB_NO_SETUP_DMA_MAP;
						if (us->current_urb->transfer_buffer == us->iobuf)
							us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
						us->current_urb->transfer_dma = us->iobuf_dma;
						us->current_urb->setup_dma = us->cr_dma;

						/* submit the URB */
						status = usb_submit_urb(us->current_urb, GFP_NOIO);//發命令,等中斷返回
						=>int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
						{
							return usb_hcd_submit_urb(urb, mem_flags);
							=>int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
							{
								
							}
						}
						
						if (status) {
							/* something went wrong */
							return status;
						}

						/* since the URB has been submitted successfully, it's now okay
						 * to cancel it */
						set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);

						/* did an abort occur during the submission? */
						if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {

							/* cancel the URB, if it hasn't been cancelled already */
							if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
								US_DEBUGP("-- cancelling URB\n");
								usb_unlink_urb(us->current_urb);
							}
						}
					 
						/* wait for the completion of the URB */
						timeleft = wait_for_completion_interruptible_timeout(
								&urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT);//等中斷執行complete後返回
					 
						clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);

						if (timeleft <= 0) {
							US_DEBUGP("%s -- cancelling URB\n",
								  timeleft == 0 ? "Timeout" : "Signal");
							usb_kill_urb(us->current_urb);
						}

						/* return the URB status */
						return us->current_urb->status;
					}

					/* store the actual length of the data transferred */
					if (act_len)
						*act_len = us->current_urb->actual_length;
					return interpret_urb_result(us, pipe, length, result, us->current_urb->actual_length);
					
				}
				
			}
			
			/* if the command gets aborted by the higher layers, we need to
			 * short-circuit all other processing
			 */
			if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {//command_abort喚醒後置的標記位
				US_DEBUGP("-- command was aborted\n");
				srb->result = DID_ABORT << 16;
				goto Handle_Errors;
			}
			
			
		}
		
		/* indicate that the command is done */
		if (us->srb->result != DID_ABORT << 16) {
			US_DEBUGP("scsi cmd done, result=0x%x\n", 
				   us->srb->result);
			us->srb->scsi_done(us->srb);
		} else {
SkipForAbort:
			US_DEBUGP("scsi command aborted\n");
		}
	}
}

如果超時則觸發scsi_times_out函數,最終scsi_eh_scmd_add會觸發command_abort函數結束等待,從而進行故障恢復操作

enum blk_eh_timer_return scsi_times_out(struct request *req)
{
	struct scsi_cmnd *scmd = req->special;
	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;

	scsi_log_completion(scmd, TIMEOUT_ERROR);

	if (scmd->device->host->transportt->eh_timed_out)
		rtn = scmd->device->host->transportt->eh_timed_out(scmd);
	else if (scmd->device->host->hostt->eh_timed_out)
		rtn = scmd->device->host->hostt->eh_timed_out(scmd);

	if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
		     !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
			 =>int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
			 
		scmd->result |= DID_TIME_OUT << 16;
		rtn = BLK_EH_HANDLED;
	}

	return rtn;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章