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

📄 scsi.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
		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->host->last_reset > 0 &&		     jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)		&& !(SCpnt->flags & WAS_RESET))	    {		printk("scsi%d channel %d : resetting for second half of retries.\n",		       SCpnt->host->host_no, SCpnt->channel);		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);		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;	    SCpnt->cmd_len = SCpnt->old_cmd_len;	    internal_cmnd (SCpnt);	}	break;    default:	INTERNAL_ERROR;    }        if (status == FINISHED) {#ifdef DEBUG	printk("Calling done function - at address %p\n", SCpnt->done);#endif	host->host_busy--; /* Indicate that we are free */		if (host->block && host->host_busy == 0) {	    host_active = NULL;	    	    /* For block devices "wake_up" is done in end_scsi_request */	    if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&		MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {		struct Scsi_Host * next;				for (next = host->block; next != host; next = next->block)		    wake_up(&next->host_wait);	    }	    	}		wake_up(&host->host_wait);	SCpnt->result = result | ((exit & 0xff) << 24);	SCpnt->use_sg = SCpnt->old_use_sg;	SCpnt->cmd_len = SCpnt->old_cmd_len;	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 reentrantly for a given host. *//* * Since we're nice guys and specified that abort() and reset() * can be non-reentrant.  The internal_timeout flags are used for * this. */int scsi_abort (Scsi_Cmnd * SCpnt, int why){    int oldto;    unsigned long flags;    struct Scsi_Host * host = SCpnt->host;        while(1)    {	save_flags(flags);	cli();		/*	 * Protect against races here.  If the command is done, or we are	 * on a different command forget it.	 */	if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {	    restore_flags(flags);	    return 0;	}	if (SCpnt->internal_timeout & IN_ABORT)	{	    restore_flags(flags);	    while (SCpnt->internal_timeout & IN_ABORT)		barrier();	}	else	{	    SCpnt->internal_timeout |= IN_ABORT;	    oldto = update_timeout(SCpnt, ABORT_TIMEOUT);	    	    if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {		/* OK, this command must have died when we did the		 *  reset.  The device itself must have lied. 		 */		printk("Stale command on %d %d:%d appears to have died when"		       " the bus was reset\n", 		       SCpnt->channel, SCpnt->target, SCpnt->lun);	    }	    	    restore_flags(flags);	    if (!host->host_busy) {		SCpnt->internal_timeout &= ~IN_ABORT;		update_timeout(SCpnt, oldto);		return 0;	    }	    printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"		   " channel %d, id %d, lun %d ",		   SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel, 		   (int) SCpnt->target, (int) SCpnt->lun);	    print_command (SCpnt->cmnd);	    if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)		return 0;	    SCpnt->abort_reason = why;	    switch(host->hostt->abort(SCpnt)) {		/* We do not know how to abort.  Try waiting another		 * time increment and see if this helps. Set the		 * WAS_TIMEDOUT flag set so we do not try this twice		 */	    case SCSI_ABORT_BUSY: /* Tough call - returning 1 from				   * this is too severe 				   */	    case SCSI_ABORT_SNOOZE:		if(why == DID_TIME_OUT) {		    save_flags(flags);		    cli();		    SCpnt->internal_timeout &= ~IN_ABORT;		    if(SCpnt->flags & WAS_TIMEDOUT) {			restore_flags(flags);			return 1; /* Indicate we cannot handle this.				   * We drop down into the reset handler				   * and try again 				   */		    } else {			SCpnt->flags |= WAS_TIMEDOUT;			oldto = SCpnt->timeout_per_command;			update_timeout(SCpnt, oldto);		    }		    restore_flags(flags);		}		return 0;	    case SCSI_ABORT_PENDING:		if(why != DID_TIME_OUT) {		    save_flags(flags);		    cli();		    update_timeout(SCpnt, oldto);		    restore_flags(flags);		}		return 0;	    case SCSI_ABORT_SUCCESS:		/* We should have already aborted this one.  No		 * need to adjust timeout 		 */                 SCpnt->internal_timeout &= ~IN_ABORT;                 return 0;	    case SCSI_ABORT_NOT_RUNNING:		SCpnt->internal_timeout &= ~IN_ABORT;		update_timeout(SCpnt, 0);		return 0;	    case SCSI_ABORT_ERROR:	    default:		SCpnt->internal_timeout &= ~IN_ABORT;		return 1;	    }	}    }}/* Mark a single SCSI Device as having been reset. */static inline void scsi_mark_device_reset(Scsi_Device *Device){  Device->was_reset = 1;  Device->expecting_cc_ua = 1;}/* Mark all SCSI Devices on a specific Host as having been reset. */void scsi_mark_host_reset(struct Scsi_Host *Host){  Scsi_Cmnd *SCpnt;  for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)      scsi_mark_device_reset(SCpnt->device);}/* Mark all SCSI Devices on a specific Host Bus as having been reset. */void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel){  Scsi_Cmnd *SCpnt;  for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)      if (SCpnt->channel == channel)	  scsi_mark_device_reset(SCpnt->device);}int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags){    int temp;    unsigned long flags;    Scsi_Cmnd * SCpnt1;    struct Scsi_Host * host = SCpnt->host;    printk("SCSI bus is being reset for host %d channel %d.\n",	   host->host_no, SCpnt->channel); #if 0    /*     * First of all, we need to make a recommendation to the low-level     * driver as to whether a BUS_DEVICE_RESET should be performed,     * or whether we should do a full BUS_RESET.  There is no simple     * algorithm here - we basically use a series of heuristics     * to determine what we should do.     */    SCpnt->host->suggest_bus_reset = FALSE;        /*     * First see if all of the active devices on the bus have     * been jammed up so that we are attempting resets.  If so,     * then suggest a bus reset.  Forcing a bus reset could     * result in some race conditions, but no more than     * you would usually get with timeouts.  We will cross     * that bridge when we come to it.     *     * This is actually a pretty bad idea, since a sequence of     * commands will often timeout together and this will cause a     * Bus Device Reset followed immediately by a SCSI Bus Reset.     * If all of the active devices really are jammed up, the     * Bus Device Reset will quickly timeout and scsi_times_out     * will follow up with a SCSI Bus Reset anyway.     */    SCpnt1 = host->host_queue;    while(SCpnt1) {	if( SCpnt1->request.rq_status != RQ_INACTIVE	    && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )            	break;        SCpnt1 = SCpnt1->next; 	}    if( SCpnt1 == NULL ) {        reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;    }        /*     * If the code that called us is suggesting a hard reset, then     * definitely request it.  This usually occurs because a     * BUS_DEVICE_RESET times out.     *     * Passing reset_flags along takes care of this automatically.     */    if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {        SCpnt->host->suggest_bus_reset = TRUE;    }#endif        while (1) {	save_flags(flags);	cli();	/*	 * Protect against races here.  If the command is done, or we are	 * on a different command forget it.	 */	if (reset_flags & SCSI_RESET_ASYNCHRONOUS)	  if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {	    restore_flags(flags);	    return 0;	  }	if (SCpnt->internal_timeout & IN_RESET)	{	    restore_flags(flags);	    while (SCpnt->internal_timeout & IN_RESET)		barrier();	}	else	{	    SCpnt->internal_timeout |= IN_RESET;	    update_timeout(SCpnt, RESET_TIMEOUT);	    	    if (host->host_busy)	    {		restore_flags(flags);		SCpnt1 = host->host_queue;		while(SCpnt1) {		    if (SCpnt1->request.rq_status != RQ_INACTIVE) {#if 0			if (!(SCpnt1->flags & IS_RESETTING) &&			    !(SCpnt1->internal_timeout & IN_ABORT))			    scsi_abort(SCpnt1, DID_RESET);#endif			SCpnt1->flags |= (WAS_RESET | IS_RESETTING);		    }		    SCpnt1 = SCpnt1->next;		}				host->last_reset = jiffies;		temp = host->hostt->reset(SCpnt, reset_flags);		/*		  This test allows the driver to introduce an additional bus		  settle time delay by setting last_reset up to 20 seconds in		  the future.  In the normal case where the driver does not		  modify last_reset, it must be assumed that the actual bus		  reset occurred immediately prior to the return to this code,		  and so last_reset must be updated to the current time, so		  that the delay in internal_cmnd will guarantee at least a		  MIN_RESET_DELAY bus settle time.		*/		if ((host->last_reset < jiffies) || 		    (host->last_reset > (jiffies + 20 * HZ)))		  host->last_reset = jiffies;	    }	    else	    {		if (!host->block) host->host_busy++;		restore_flags(flags);		host->last_reset = jiffies;	        SCpnt->flags |= (WAS_RESET | IS_RESETTING);		temp = host->hostt->reset(SCpnt, reset_flags);		if ((host->last_reset < jiffies) || 		    (host->last_reset > (jiffies + 20 * HZ)))		  host->last_reset = jiffies;		if (!host->block) host->host_busy--;	    }	    #ifdef DEBUG	    printk("scsi reset function returned %d\n", temp);#endif                        /*             * Now figure out what we need to do, based upon             * what the low level driver said that it did.	     * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,	     * or SCSI_RESET_WAKEUP, then the low level driver did a	     * bus device reset or bus reset, so we should go through	     * and mark one or all of the devices on that bus	     * as having been reset.             */            switch(temp & SCSI_RESET_ACTION) {	    case SCSI_RESET_SUCCESS:	        if (temp & SCSI_RESET_HOST_RESET)		  scsi_mark_host_reset(host);	        else if (temp & SCSI_RESET_BUS_RESET)		  scsi_mark_bus_reset(host, SCpnt->channel);		else scsi_mark_device_reset(SCpnt->device);		save_flags(flags);		cli();		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);		restore_flags(flags);		return 0;	    case SCSI_RESET_PENDING:	        if (temp & SCSI_RESET_HOST_RESET)		  scsi_mark_host_reset(host);	        else if (temp & SCSI_RESET_BUS_RESET)		  scsi_mark_bus_reset(host, SCpnt->channel);		else scsi_mark_device_reset(SCpnt->device);	    case SCSI_RESET_NOT_RUNNING:		return 0;	    case SCSI_RESET_PUNT:		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);                scsi_request_sense (SCpnt);                return 0;	    case SCSI_RESET_WAKEUP:	        if (temp & SCSI_RESET_HOST_RESET)		  scsi_mark_host_reset(host);	        else if (temp & SCSI_RESET_BUS_RESET)		  scsi_mark_bus_reset(host, SCpnt->channel);		else scsi_mark_device_reset(SCpnt->device);		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);		scsi_request_sense (SCpnt);                /*                 * If a bus reset was performed, we                 * need to wake up each and every command                 * that was active on the bus or if it was a HBA                 * reset all active commands on all channels                 */                if( temp & SCSI_RESET_HOST_RESET )                {		    SCpnt1 = host->host_queue;		    while(SCpnt1) {			if (SCpnt1->request.rq_status != RQ_INACTIVE			    && SCpnt1 != SCpnt)

⌨️ 快捷键说明

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