📄 scsi.c
字号:
(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 + -