⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				
	memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 12);
	/* Zero the sense buffer.  Some host adapters automatically request
	   sense on error.  0 is not a valid sense code.  */
	memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
	SCpnt->request_buffer = buffer;
	SCpnt->request_bufflen = bufflen;
	SCpnt->old_use_sg = SCpnt->use_sg;

	/* Start the timer ticking.  */

	SCpnt->internal_timeout = 0;
	internal_cmnd (SCpnt);

#ifdef DEBUG
	printk ("Leaving scsi_do_cmd()\n");
#endif
        }



/*
	The scsi_done() function disables the timeout timer for the scsi host, 
	marks the host as not busy, and calls the user specified completion 
	function for that host's current command.
*/

static void reset (Scsi_Cmnd * SCpnt)
{
#ifdef DEBUG
	printk("scsi: reset(%d)\n", SCpnt->host->host_no);
#endif
	
	SCpnt->flags |= (WAS_RESET | IS_RESETTING);
	scsi_reset(SCpnt);
	
#ifdef DEBUG
	printk("performing request sense\n");
#endif
	
	if(SCpnt->flags & NEEDS_JUMPSTART) {
	  SCpnt->flags &= ~NEEDS_JUMPSTART;
	  scsi_request_sense (SCpnt);
	};
}
	
	

static int check_sense (Scsi_Cmnd * SCpnt)
	{
  /* If there is no sense information, request it.  If we have already
     requested it, there is no point in asking again - the firmware must be
     confused. */
  if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
    if(!(SCpnt->flags & ASKED_FOR_SENSE))
      return SUGGEST_SENSE;
    else
      return SUGGEST_RETRY;
      }
  
  SCpnt->flags &= ~ASKED_FOR_SENSE;

#ifdef DEBUG_INIT
	printk("scsi%d : ", SCpnt->host->host_no);
	print_sense("", SCpnt);
	printk("\n");
#endif
	        if (SCpnt->sense_buffer[2] &0xe0)
		  return SUGGEST_ABORT;

		switch (SCpnt->sense_buffer[2] & 0xf)
		{
		case NO_SENSE:
			return 0;
		case RECOVERED_ERROR:
			if (scsi_devices[SCpnt->index].type == TYPE_TAPE)
			  return SUGGEST_IS_OK;
			else
			  return 0;

		case ABORTED_COMMAND:
			return SUGGEST_RETRY;	
		case NOT_READY:
		case UNIT_ATTENTION:
			return SUGGEST_ABORT;

		/* these three are not supported */	
		case COPY_ABORTED:
		case VOLUME_OVERFLOW:
		case MISCOMPARE:
	
		case MEDIUM_ERROR:
			return SUGGEST_REMAP;
		case BLANK_CHECK:
		case DATA_PROTECT:
		case HARDWARE_ERROR:
		case ILLEGAL_REQUEST:
		default:
			return SUGGEST_ABORT;
		}
	      }

/* This function is the mid-level interrupt routine, which decides how
 *  to handle error conditions.  Each invocation of this function must
 *  do one and *only* one of the following:
 *
 *  (1) Call last_cmnd[host].done.  This is done for fatal errors and
 *      normal completion, and indicates that the handling for this
 *      request is complete.
 *  (2) Call internal_cmnd to requeue the command.  This will result in
 *      scsi_done being called again when the retry is complete.
 *  (3) Call scsi_request_sense.  This asks the host adapter/drive for
 *      more information about the error condition.  When the information
 *      is available, scsi_done will be called again.
 *  (4) Call reset().  This is sort of a last resort, and the idea is that
 *      this may kick things loose and get the drive working again.  reset()
 *      automatically calls scsi_request_sense, and thus scsi_done will be
 *      called again once the reset is complete.
 *
 *      If none of the above actions are taken, the drive in question
 * will hang. If more than one of the above actions are taken by
 * scsi_done, then unpredictable behavior will result.
 */
static void scsi_done (Scsi_Cmnd * SCpnt)
	{
	int status=0;
	int exit=0;
	int checked;
	int oldto;
	struct Scsi_Host * host = SCpnt->host;
	int result = SCpnt->result;
	oldto = update_timeout(SCpnt, 0);

#define FINISHED 0
#define MAYREDO  1
#define REDO	 3
#define PENDING  4

#ifdef DEBUG
	printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
#endif
	switch (host_byte(result))	
	{
	case DID_OK:
		if (SCpnt->flags & IS_RESETTING)
			{
			SCpnt->flags &= ~IS_RESETTING;
			status = REDO;
			break;
			}

		if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
			/* Failed to obtain sense information */
			{
			SCpnt->flags &= ~WAS_SENSE;
			SCpnt->internal_timeout &= ~SENSE_TIMEOUT;

			if (!(SCpnt->flags & WAS_RESET))
				{
				printk("scsi%d : target %d lun %d request sense failed, performing reset.\n", 
					SCpnt->host->host_no, SCpnt->target, SCpnt->lun);
				reset(SCpnt);
				return;
				}
			else
				{
				exit = (DRIVER_HARD | SUGGEST_ABORT);
				status = FINISHED;
				}
			}
		else switch(msg_byte(result))
			{
			case COMMAND_COMPLETE:
			switch (status_byte(result))
			{
			case GOOD:
				if (SCpnt->flags & WAS_SENSE)
					{
#ifdef DEBUG
	printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");
#endif

					SCpnt->flags &= ~WAS_SENSE;
					SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
	
					switch (checked = check_sense(SCpnt))
					{
					case SUGGEST_SENSE:
					case 0: 
#ifdef DEBUG
	printk("NO SENSE.  status = REDO\n");
#endif

						update_timeout(SCpnt, oldto);
						status = REDO;
						break;
      					case SUGGEST_IS_OK:
						break;
					case SUGGEST_REMAP:			
					case SUGGEST_RETRY: 
#ifdef DEBUG
	printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
#endif

						status = MAYREDO;
						exit = DRIVER_SENSE | SUGGEST_RETRY;
						break;
					case SUGGEST_ABORT:
#ifdef DEBUG
	printk("SENSE SUGGEST ABORT - status = FINISHED");
#endif

						status = FINISHED;
						exit =  DRIVER_SENSE | SUGGEST_ABORT;
						break;
					default:
						printk ("Internal error %s %d \n", __FILE__, 
							__LINE__);
					}			   
					}	
				else
					{
#ifdef DEBUG
	printk("COMMAND COMPLETE message returned, status = FINISHED. \n");
#endif

					exit =  DRIVER_OK;
					status = FINISHED;
					}
				break;	

			case CHECK_CONDITION:
				switch (check_sense(SCpnt))
				  {
				  case 0: 
				    update_timeout(SCpnt, oldto);
				    status = REDO;
				    break;
				  case SUGGEST_REMAP:			
				  case SUGGEST_RETRY:
				    status = MAYREDO;
				    exit = DRIVER_SENSE | SUGGEST_RETRY;
				    break;
				  case SUGGEST_ABORT:
				    status = FINISHED;
				    exit =  DRIVER_SENSE | SUGGEST_ABORT;
				    break;
				  case SUGGEST_SENSE:
				scsi_request_sense (SCpnt);
				status = PENDING;
				break;       	
				  }
				break;       	
			
			case CONDITION_GOOD:
			case INTERMEDIATE_GOOD:
			case INTERMEDIATE_C_GOOD:
				break;
				
			case BUSY:
				update_timeout(SCpnt, oldto);
				status = REDO;
				break;

			case RESERVATION_CONFLICT:
				printk("scsi%d : RESERVATION CONFLICT performing reset.\n", 
					SCpnt->host->host_no);
				reset(SCpnt);
				return;
#if 0
				exit = DRIVER_SOFT | SUGGEST_ABORT;
				status = MAYREDO;
				break;
#endif
			default:
				printk ("Internal error %s %d \n"
					"status byte = %d \n", __FILE__, 
					__LINE__, status_byte(result));
				
			}
			break;
			default:
				panic("scsi: unsupported message byte %d recieved\n", msg_byte(result)); 
			}
			break;
	case DID_TIME_OUT:	
#ifdef DEBUG
	printk("Host returned DID_TIME_OUT - ");
#endif

		if (SCpnt->flags & WAS_TIMEDOUT)	
			{
#ifdef DEBUG
	printk("Aborting\n");
#endif	
			exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
			}		
		else 
			{
#ifdef DEBUG
			printk ("Retrying.\n");
#endif
			SCpnt->flags  |= WAS_TIMEDOUT;
			status = REDO;
			}
		break;
	case DID_BUS_BUSY:
	case DID_PARITY:
		status = REDO;
		break;
	case DID_NO_CONNECT:
#ifdef DEBUG
		printk("Couldn't connect.\n");
#endif
		exit  = (DRIVER_HARD | SUGGEST_ABORT);
		break;
	case DID_ERROR:	
		status = MAYREDO;
		exit = (DRIVER_HARD | SUGGEST_ABORT);
		break;
	case DID_BAD_TARGET:
	case DID_ABORT:
		exit = (DRIVER_INVALID | SUGGEST_ABORT);
		break;	
        case DID_RESET:
                if(msg_byte(result) == GOOD &&
                      status_byte(result) == CHECK_CONDITION) {
			switch (check_sense(SCpnt)) {
			case 0: 
			    update_timeout(SCpnt, oldto);
			    status = REDO;
			    break;
			case SUGGEST_REMAP:			
			case SUGGEST_RETRY:
			    status = MAYREDO;
			    exit = DRIVER_SENSE | SUGGEST_RETRY;
			    break;
			case SUGGEST_ABORT:
			    status = FINISHED;
			    exit =  DRIVER_SENSE | SUGGEST_ABORT;
			    break;
			case SUGGEST_SENSE:
                              scsi_request_sense (SCpnt);
                              status = PENDING;
                              break;
			}
		} else {
                status=REDO;
                exit = SUGGEST_RETRY;
		}
                break;
	default : 		
		exit = (DRIVER_ERROR | SUGGEST_DIE);
	}

	switch (status) 
		{
		case FINISHED:
		case PENDING:
			break;
		case MAYREDO:

#ifdef DEBUG
	printk("In MAYREDO, allowing %d retries, have %d\n",
	       SCpnt->allowed, SCpnt->retries);
#endif

			if ((++SCpnt->retries) < SCpnt->allowed)
			{
			if ((SCpnt->retries >= (SCpnt->allowed >> 1))
			    && !(SCpnt->flags & WAS_RESET))
			        {
					printk("scsi%d : reseting for second half of retries.\n",
						SCpnt->host->host_no);
					reset(SCpnt);
					break;
			        }

			}
			else
				{
				status = FINISHED;
				break;
				}
			/* fall through to REDO */

		case REDO:
			if (SCpnt->flags & WAS_SENSE)			
				scsi_request_sense(SCpnt); 	
			else	
			  {
			    memcpy ((void *) SCpnt->cmnd,
				    (void*) SCpnt->data_cmnd, 
				    sizeof(SCpnt->data_cmnd));
			    SCpnt->request_buffer = SCpnt->buffer;
			    SCpnt->request_bufflen = SCpnt->bufflen;
			    SCpnt->use_sg = SCpnt->old_use_sg;
			    internal_cmnd (SCpnt);
			  };
			break;	
		default: 
			INTERNAL_ERROR;
		}

	if (status == FINISHED) 
		{
		#ifdef DEBUG
			printk("Calling done function - at address %08x\n", SCpnt->done);
		#endif
		host->host_busy--; /* Indicate that we are free */
		wake_up(&host->host_wait);
		SCpnt->result = result | ((exit & 0xff) << 24);
		SCpnt->use_sg = SCpnt->old_use_sg;
		SCpnt->done (SCpnt);
		}


#undef FINISHED
#undef REDO
#undef MAYREDO
#undef PENDING
	}

/*
	The scsi_abort function interfaces with the abort() function of the host
	we are aborting, and causes the current command to not complete.  The 
	caller should deal with any error messages or status returned on the 
	next call.
	
	This will not be called rentrantly for a given host.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -