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

📄 scsi.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
       (scsi_result[3] & 0x0f) == 1))    SDpnt->scsi_level++;  /*   * Accommodate drivers that want to sleep when they should be in a polling   * loop.   */  SDpnt->disconnect = 0;  /*   * Get any flags for this device.   */  bflags = get_device_flags (scsi_result);  /*   * Set the tagged_queue flag for SCSI-II devices that purport to support   * tagged queuing in the INQUIRY data.   */  SDpnt->tagged_queue = 0;  if ((SDpnt->scsi_level >= SCSI_2) &&      (scsi_result[7] & 2) &&      !(bflags & BLIST_NOTQ)) {    SDpnt->tagged_supported = 1;    SDpnt->current_tag = 0;  }  /*   * Some revisions of the Texel CD ROM drives have handshaking problems when   * used with the Seagate controllers.  Before we know what type of device   * we're talking to, we assume it's borken and then change it here if it   * turns out that it isn't a TEXEL drive.   */  if ((bflags & BLIST_BORKEN) == 0)    SDpnt->borken = 0;  /*   * If we want to only allow I/O to one of the luns attached to this device   * at a time, then we set this flag.   */  if (bflags & BLIST_SINGLELUN)    SDpnt->single_lun = 1;  /*   * These devices need this "key" to unlock the devices so we can use it   */  if ((bflags & BLIST_KEY) != 0) {    printk ("Unlocked floptical drive.\n");    SDpnt->lockable = 0;    scsi_cmd[0] = MODE_SENSE;    scsi_cmd[1] = (lun << 5) & 0xe0;    scsi_cmd[2] = 0x2e;    scsi_cmd[3] = 0;    scsi_cmd[4] = 0x2a;    scsi_cmd[5] = 0;    SCpnt->cmd_len = 0;    {      struct semaphore sem = MUTEX_LOCKED;      SCpnt->request.rq_status = RQ_SCSI_BUSY;      SCpnt->request.sem = &sem;      spin_lock_irq(&io_request_lock);      scsi_do_cmd (SCpnt, (void *) scsi_cmd,                   (void *) scsi_result, 0x2a,                   scan_scsis_done, SCSI_TIMEOUT, 3);      spin_unlock_irq(&io_request_lock);      down (&sem);      SCpnt->request.sem = NULL;    }  }  /*   * Detach the command from the device. It was just a temporary to be used while   * scanning the bus - the real ones will be allocated later.   */  SDpnt->device_queue = NULL;  /*   * This device was already hooked up to the host in question,   * so at this point we just let go of it and it should be fine.  We do need to   * allocate a new one and attach it to the host so that we can further scan the bus.   */  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);  *SDpnt2=SDpnt;  if (!SDpnt)  {      printk ("scsi: scan_scsis_single: Cannot malloc\n");      return 0;  }  /*   * And hook up our command block to the new device we will be testing   * for.   */  SDpnt->device_queue = SCpnt;  SDpnt->online = TRUE;  /*   * Since we just found one device, there had damn well better be one in the list   * already.   */  if( shpnt->host_queue == NULL )      panic("scan_scsis_single: Host queue == NULL\n");  SDtail = shpnt->host_queue;  while (SDtail->next)  {      SDtail = SDtail->next;  }  /* Add this device to the linked list at the end */  SDtail->next = SDpnt;  SDpnt->prev = SDtail;  SDpnt->next = NULL;  /*   * Some scsi devices cannot be polled for lun != 0 due to firmware bugs   */  if (bflags & BLIST_NOLUN)    return 0;                   /* break; */  /*   * If this device is known to support sparse multiple units, override the   * other settings, and scan all of them.   */  if (bflags & BLIST_SPARSELUN) {    *max_dev_lun = 8;    *sparse_lun = 1;    return 1;  }  /*   * If this device is known to support multiple units, override the other   * settings, and scan all of them.   */  if (bflags & BLIST_FORCELUN) {    *max_dev_lun = 8;    return 1;  }  /*   * REGAL CDC-4X: avoid hang after LUN 4   */  if (bflags & BLIST_MAX5LUN) {    *max_dev_lun = 5;    return 1;  }  /*   * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI   * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1   * (ANSI SCSI Revision 1) and Response Data Format 0   */  if (((scsi_result[2] & 0x07) == 0)      ||      ((scsi_result[2] & 0x07) == 1 &&       (scsi_result[3] & 0x0f) == 0))    return 0;  return 1;}/* *  Flag bits for the internal_timeout array */#define NORMAL_TIMEOUT 0#define IN_ABORT  1#define IN_RESET  2#define IN_RESET2 4#define IN_RESET3 8/* 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 * scsi_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 scsi_request_queueable().\n");    if (req && req->rq_status == RQ_INACTIVE)	panic("Inactive in scsi_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->next;	}    } else {	SCpnt = device->device_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, 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 */    }    atomic_inc(&SCpnt->host->host_active);     SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target,                               atomic_read(&SCpnt->host->host_active)));    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;    SCpnt->state = SCSI_STATE_INITIALIZING;    SCpnt->owner = SCSI_OWNER_HIGHLEVEL;    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 * scsi_request_queueable function also knows the internal allocation scheme * of the packets for each device */Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,			     int wait){    kdev_t dev;    struct request * req = NULL;    int tablesize;    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 scsi_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 (in_interrupt() && SCSI_BLOCK(device, 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->next;	    }	} else {	    SCpnt = device->device_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;	}	/* See if this request has already been queued by an interrupt routine	 */	if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) {	    return NULL;	}	if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE)	/* Might have changed */	{		if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){			spin_unlock(&io_request_lock);		/* FIXME!!!! */ 			sleep_on(&device->device_wait); 			spin_lock_irq(&io_request_lock);	/* FIXME!!!! */	 	} else {	 		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 scsi_allocate_device\n");	 		} 		}	} 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;

⌨️ 快捷键说明

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