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

📄 scsi.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Obviously the bus reset didn't work.	 * Let's try even harder and call for an HBA reset.         * Maybe the HBA itself crashed and this will shake it loose.	 */	printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",	       SCpnt->host->host_no, SCpnt->pid);	SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);	SCpnt->internal_timeout |= IN_RESET3;        scsi_reset (SCpnt,		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);	return;		    default:	printk("SCSI host %d reset (pid %ld) timed out again -\n",	       SCpnt->host->host_no, SCpnt->pid);	printk("probably an unrecoverable SCSI bus or device hang.\n");	return;    }    }/* This function takes a quick look at a request, and decides if it * can be queued now, or if there would be a stall while waiting for * something else to finish.  This routine assumes that interrupts are * turned off when entering the routine.  It is the responsibility * of the calling code to ensure that this is the case.  */Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device){    Scsi_Cmnd * SCpnt = NULL;    int tablesize;    Scsi_Cmnd * found = NULL;    struct buffer_head * bh, *bhp;        if (!device)	panic ("No device passed to request_queueable().\n");        if (req && req->rq_status == RQ_INACTIVE)	panic("Inactive in request_queueable");    /*     * Look for a free command block.  If we have been instructed not to queue     * multiple commands to multi-lun devices, then check to see what else is      * going for this device first.     */          if (!device->single_lun) {	SCpnt = device->device_queue;	while(SCpnt){	    if(SCpnt->request.rq_status == RQ_INACTIVE) break;	    SCpnt = SCpnt->device_next;	}    } else {	SCpnt = device->host->host_queue;	while(SCpnt){	    if(SCpnt->channel == device->channel                 && SCpnt->target == device->id) {		if (SCpnt->lun == device->lun) {		    if(found == NULL 		       && SCpnt->request.rq_status == RQ_INACTIVE) 		    {			found=SCpnt;		    }		} 		if(SCpnt->request.rq_status != RQ_INACTIVE) {		    /*		     * I think that we should really limit things to one		     * outstanding command per device - this is what tends                      * to trip up buggy firmware.		     */		    return NULL;		}	    }	    SCpnt = SCpnt->next;	}	SCpnt = found;    }        if (!SCpnt) return NULL;        if (SCSI_BLOCK(device->host)) return NULL;        if (req) {	memcpy(&SCpnt->request, req, sizeof(struct request));	tablesize = device->host->sg_tablesize;	bhp = bh = req->bh;	if(!tablesize) bh = NULL;	/* Take a quick look through the table to see how big it is.  	 * We already have our copy of req, so we can mess with that 	 * if we want to. 	 */	while(req->nr_sectors && bh){	    bhp = bhp->b_reqnext;	    if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;	    req->nr_sectors -= bh->b_size >> 9;	    req->sector += bh->b_size >> 9;	    if(!tablesize) break;	    bh = bhp;	}	if(req->nr_sectors && bh && bh->b_reqnext){  /* Any leftovers? */	    SCpnt->request.bhtail = bh;	    req->bh = bh->b_reqnext; /* Divide request */	    bh->b_reqnext = NULL;	    bh = req->bh;	    	    /* Now reset things so that req looks OK */	    SCpnt->request.nr_sectors -= req->nr_sectors;	    req->current_nr_sectors = bh->b_size >> 9;	    req->buffer = bh->b_data;	    SCpnt->request.sem = NULL; /* Wait until whole thing done */	} else {	    req->rq_status = RQ_INACTIVE;	    wake_up(&wait_for_request);	}    } else {	SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Busy, but no request */	SCpnt->request.sem = NULL;   /* And no one is waiting for the device 				      * either */    }        SCpnt->use_sg = 0;               /* Reset the scatter-gather flag */    SCpnt->old_use_sg  = 0;    SCpnt->transfersize = 0;    SCpnt->underflow = 0;    SCpnt->cmd_len = 0;/* Since not everyone seems to set the device info correctly * before Scsi_Cmnd gets send out to scsi_do_command, we do it here. */     SCpnt->channel = device->channel;    SCpnt->lun = device->lun;    SCpnt->target = device->id;    return SCpnt;}/* This function returns a structure pointer that will be valid for * the device.  The wait parameter tells us whether we should wait for * the unit to become free or not.  We are also able to tell this routine * not to return a descriptor if the host is unable to accept any more * commands for the time being.  We need to keep in mind that there is no * guarantee that the host remain not busy.  Keep in mind the * request_queueable function also knows the internal allocation scheme * of the packets for each device  */Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,			     int wait){    kdev_t dev;    struct request * req = NULL;    int tablesize;    unsigned long flags;    struct buffer_head * bh, *bhp;    struct Scsi_Host * host;    Scsi_Cmnd * SCpnt = NULL;    Scsi_Cmnd * SCwait = NULL;    Scsi_Cmnd * found = NULL;        if (!device)	panic ("No device passed to allocate_device().\n");        if (reqp) req = *reqp;        /* See if this request has already been queued by an interrupt routine */    if (req) {	if(req->rq_status == RQ_INACTIVE) return NULL;	dev = req->rq_dev;    } else        dev = 0;		/* unused */        host = device->host;        if (intr_count && SCSI_BLOCK(host)) return NULL;        while (1==1){	if (!device->single_lun) {	    SCpnt = device->device_queue;	    while(SCpnt){		SCwait = SCpnt;		if(SCpnt->request.rq_status == RQ_INACTIVE) break;		SCpnt = SCpnt->device_next;	    }	} else {	    SCpnt = device->host->host_queue;	    while(SCpnt){		if(SCpnt->channel == device->channel                    && SCpnt->target == device->id) {		    if (SCpnt->lun == device->lun) {			SCwait = SCpnt;			if(found == NULL 			   && SCpnt->request.rq_status == RQ_INACTIVE) 			{			    found=SCpnt;			}		    } 		    if(SCpnt->request.rq_status != RQ_INACTIVE) {			/*			 * I think that we should really limit things to one			 * outstanding command per device - this is what tends                         * to trip up buggy firmware.			 */			found = NULL;			break;		    }		}		SCpnt = SCpnt->next;	    }	    SCpnt = found;	}	save_flags(flags);	cli();	/* See if this request has already been queued by an interrupt routine	 */	if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) {	    restore_flags(flags);	    return NULL;	}	if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE)	/* Might have changed */	{#if 1	/* NEW CODE */		if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){ 			sleep_on(&device->device_wait); 			restore_flags(flags);	 	} else { 			restore_flags(flags);	 		if (!wait) return NULL; 			if (!SCwait) {	 			printk("Attempt to allocate device channel %d,"                                       " target %d, lun %d\n", device->channel,                                       device->id, device->lun); 				panic("No device found in allocate_device\n");	 		} 		}#else	/* ORIGINAL CODE */		    restore_flags(flags);		    if(!wait) return NULL;		    if (!SCwait) {			printk("Attempt to allocate device channel %d, target"                               " %d, lun %d\n", device->channel, device->id,                                device->lun);			panic("No device found in allocate_device\n");		    }		    SCSI_SLEEP(&device->device_wait,			       (SCwait->request.rq_status != RQ_INACTIVE));#endif	} else {	    if (req) {		memcpy(&SCpnt->request, req, sizeof(struct request));		tablesize = device->host->sg_tablesize;		bhp = bh = req->bh;		if(!tablesize) bh = NULL;		/* Take a quick look through the table to see how big it is.  		 * We already have our copy of req, so we can mess with that 		 * if we want to.  		 */		while(req->nr_sectors && bh){		    bhp = bhp->b_reqnext;		    if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;		    req->nr_sectors -= bh->b_size >> 9;		    req->sector += bh->b_size >> 9;		    if(!tablesize) break;		    bh = bhp;		}		if(req->nr_sectors && bh && bh->b_reqnext){/* Any leftovers? */		    SCpnt->request.bhtail = bh;		    req->bh = bh->b_reqnext; /* Divide request */		    bh->b_reqnext = NULL;		    bh = req->bh;		    /* Now reset things so that req looks OK */		    SCpnt->request.nr_sectors -= req->nr_sectors;		    req->current_nr_sectors = bh->b_size >> 9;		    req->buffer = bh->b_data;		    SCpnt->request.sem = NULL; /* Wait until whole thing done*/		}		else		{		    req->rq_status = RQ_INACTIVE;		    *reqp = req->next;		    wake_up(&wait_for_request);		}	    } else {		SCpnt->request.rq_status = RQ_SCSI_BUSY;		SCpnt->request.sem = NULL;   /* And no one is waiting for this 					      * to complete */	    }	    restore_flags(flags);	    break;	}    }        SCpnt->use_sg = 0;            /* Reset the scatter-gather flag */    SCpnt->old_use_sg  = 0;    SCpnt->transfersize = 0;      /* No default transfer size */    SCpnt->cmd_len = 0;    SCpnt->underflow = 0;         /* Do not flag underflow conditions */    /* Since not everyone seems to set the device info correctly     * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.     */     SCpnt->channel = device->channel;    SCpnt->lun = device->lun;    SCpnt->target = device->id;    return SCpnt;}/* * This is inline because we have stack problemes if we recurse to deeply. */inline void internal_cmnd (Scsi_Cmnd * SCpnt){    unsigned long flags, timeout;    struct Scsi_Host * host;#ifdef DEBUG_DELAY    unsigned long clock;#endif#if DEBUG    unsigned long *ret = 0;#ifdef __mips__    __asm__ __volatile__ ("move\t%0,$31":"=r"(ret));#else   ret =  __builtin_return_address(0);#endif#endif        host = SCpnt->host;        save_flags(flags);    cli();    /* Assign a unique nonzero serial_number. */    if (++serial_number == 0) serial_number = 1;    SCpnt->serial_number = serial_number;    /*     * We will wait MIN_RESET_DELAY clock ticks after the last reset so     * we can avoid the drive not being ready.     */    timeout = host->last_reset + MIN_RESET_DELAY;    if (jiffies < timeout) {	int ticks_remaining = timeout - jiffies;	/*	 * NOTE: This may be executed from within an interrupt	 * handler!  This is bad, but for now, it'll do.  The irq	 * level of the interrupt handler has been masked out by the	 * platform dependent interrupt handling code already, so the	 * sti() here will not cause another call to the SCSI host's	 * interrupt handler (assuming there is one irq-level per	 * host).	 */	sti();	while (--ticks_remaining >= 0) udelay(1000000/HZ);	host->last_reset = jiffies - MIN_RESET_DELAY;    }    restore_flags(flags);        update_timeout(SCpnt, SCpnt->timeout_per_command);        /*     * We will use a queued command if possible, otherwise we will emulate the     * queuing and calling of completion function ourselves.     */#ifdef DEBUG    printk("internal_cmnd (host = %d, channel = %d, target = %d, "	   "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n", 	   SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd, 	   SCpnt->buffer, SCpnt->bufflen, SCpnt->done);#endif        if (host->can_queue)    {#ifdef DEBUG	printk("queuecommand : routine at %p\n",	       host->hostt->queuecommand);#endif	/* This locking tries to prevent all sorts of races between	 * queuecommand and the interrupt code.  In effect,	 * we are only allowed to be in queuecommand once at	 * any given time, and we can only be in the interrupt	 * handler and the queuecommand function at the same time	 * when queuecommand is called while servicing the	 * interrupt. 	 */		if(!intr_count && SCpnt->host->irq)	    disable_irq(SCpnt->host->irq);		host->hostt->queuecommand (SCpnt, scsi_done);		if(!intr_count && SCpnt->host->irq)	    enable_irq(SCpnt->host->irq);    }    else    {	int temp;#ifdef DEBUG	printk("command() :  routine at %p\n", host->hostt->command);#endif	temp = host->hostt->command (SCpnt);	SCpnt->result = temp;#ifdef DEBUG_DELAY	clock = jiffies + 4 * HZ;	while (jiffies < clock) barrier();	printk("done(host = %d, result = %04x) : routine at %p\n", 	       host->host_no, temp, host->hostt->command);#endif	scsi_done(SCpnt);    }#ifdef DEBUG    printk("leaving internal_cmnd()\n");#endif}static void scsi_request_sense (Scsi_Cmnd * SCpnt){    unsigned long flags;        save_flags(flags);    cli();    SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;    update_timeout(SCpnt, SENSE_TIMEOUT);    restore_flags(flags);            memcpy ((void *) SCpnt->cmnd , (void *) generic_sense, 	    sizeof(generic_sense));        SCpnt->cmnd[1] = SCpnt->lun << 5;    SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);        SCpnt->request_buffer = &SCpnt->sense_buffer;    SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);    SCpnt->use_sg = 0;    SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);    internal_cmnd (SCpnt);}

⌨️ 快捷键说明

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