📄 scsi.c
字号:
"(n should be 0 or non-zero)\n"); } else { scsi_logging_level = (ints[1])? ~0 : 0; }}#ifdef CONFIG_SCSI_MULTI_LUNstatic int max_scsi_luns = 8;#elsestatic int max_scsi_luns = 1;#endif__initfunc(void scsi_luns_setup(char *str, int *ints)){ if (ints[0] != 1) printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n"); else max_scsi_luns = ints[1];}/* * Detecting SCSI devices : * We scan all present host adapter's busses, from ID 0 to ID (max_id). * We use the INQUIRY command, determine device type, and pass the ID / * lun address of all sequential devices to the tape driver, all random * devices to the disk driver. */static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, unchar hchannel, unchar hid, unchar hlun){ int channel; int dev; int lun; int max_dev_lun; Scsi_Cmnd * SCpnt; unsigned char * scsi_result; unsigned char scsi_result0[256]; Scsi_Device * SDpnt; Scsi_Device * SDtail; int sparse_lun; scsi_result = NULL; SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA); if (SCpnt) { SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC); if (SDpnt) { /* Make sure we have something that is valid for DMA purposes */ scsi_result = ( ( !shpnt->unchecked_isa_dma ) ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); } } if (scsi_result == NULL) { printk ("Unable to obtain scsi_result buffer\n"); goto leave; } /* * We must chain ourself in the host_queue, so commands can time out */ SCpnt->next = NULL; SDpnt->device_queue = SCpnt; SDpnt->host = shpnt; SDpnt->online = TRUE; /* * Next, hook the device to the host in question. */ SDpnt->prev = NULL; SDpnt->next = NULL; if( shpnt->host_queue != NULL ) { SDtail = shpnt->host_queue; while( SDtail->next != NULL ) SDtail = SDtail->next; SDtail->next = SDpnt; SDpnt->prev = SDtail; } else { shpnt->host_queue = SDpnt; } /* * We need to increment the counter for this one device so we can track when * things are quiet. */ atomic_inc(&shpnt->host_active); if (hardcoded == 1) { Scsi_Device *oldSDpnt=SDpnt; struct Scsi_Device_Template * sdtpnt; channel = hchannel; if(channel > shpnt->max_channel) goto leave; dev = hid; if(dev >= shpnt->max_id) goto leave; lun = hlun; if(lun >= shpnt->max_lun) goto leave; scan_scsis_single (channel, dev, lun, &max_dev_lun, &sparse_lun, &SDpnt, SCpnt, shpnt, scsi_result); /* See warning by (DB) in scsi_proc_info() towards end of 'add-single-device' section. (dpg) */ if (shpnt->select_queue_depths != NULL) (shpnt->select_queue_depths)(shpnt, shpnt->host_queue); if(SDpnt!=oldSDpnt) { /* it could happen the blockdevice hasn't yet been inited */ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)(); oldSDpnt->scsi_request_fn = NULL; for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { if(sdtpnt->attach) { (*sdtpnt->attach)(oldSDpnt); if(oldSDpnt->attached) { scsi_build_commandblocks(oldSDpnt); if (0 == oldSDpnt->has_cmdblocks) { printk("scan_scsis: DANGER, no command blocks\n"); /* What to do now ?? */ } } } } resize_dma_pool(); for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { if(sdtpnt->finish && sdtpnt->nr_dev) {(*sdtpnt->finish)();} } } } else { /* Actual LUN. PC ordering is 0->n IBM/spec ordering is n->0 */ int order_dev; for (channel = 0; channel <= shpnt->max_channel; channel++) { for (dev = 0; dev < shpnt->max_id; ++dev) { if( shpnt->reverse_ordering) /* Shift to scanning 15,14,13... or 7,6,5,4, */ order_dev = shpnt->max_id-dev-1; else order_dev = dev; if (shpnt->this_id != order_dev) { /* * We need the for so our continue, etc. work fine. We put this in * a variable so that we can override it during the scan if we * detect a device *KNOWN* to have multiple logical units. */ max_dev_lun = (max_scsi_luns < shpnt->max_lun ? max_scsi_luns : shpnt->max_lun); sparse_lun = 0; for (lun = 0; lun < max_dev_lun; ++lun) { if (!scan_scsis_single (channel, order_dev, lun, &max_dev_lun, &sparse_lun, &SDpnt, SCpnt, shpnt, scsi_result) && !sparse_lun) break; /* break means don't probe further for luns!=0 */ } /* for lun ends */ } /* if this_id != id ends */ } /* for dev ends */ } /* for channel ends */ } /* if/else hardcoded */ /* * We need to decrement the counter for this one device * so we know when everything is quiet. */ atomic_dec(&shpnt->host_active); leave: {/* Unchain SCpnt from host_queue */ Scsi_Device *prev, *next; Scsi_Device * dqptr; for(dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next) continue; if(dqptr) { prev = dqptr->prev; next = dqptr->next; if(prev) prev->next = next; else shpnt->host_queue = next; if(next) next->prev = prev; } } /* Last device block does not exist. Free memory. */ if (SDpnt != NULL) scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device)); if (SCpnt != NULL) scsi_init_free ((char *) SCpnt, sizeof (Scsi_Cmnd)); /* If we allocated a buffer so we could do DMA, free it now */ if (scsi_result != &scsi_result0[0] && scsi_result != NULL) { scsi_init_free (scsi_result, 512); } { Scsi_Device * sdev; Scsi_Cmnd * scmd; SCSI_LOG_SCAN_BUS(4,printk("Host status for host %p:\n", shpnt)); for(sdev = shpnt->host_queue; sdev; sdev = sdev->next) { SCSI_LOG_SCAN_BUS(4,printk("Device %d %p: ", sdev->id, sdev)); for(scmd=sdev->device_queue; scmd; scmd = scmd->next) { SCSI_LOG_SCAN_BUS(4,printk("%p ", scmd)); } SCSI_LOG_SCAN_BUS(4,printk("\n")); } }}/* * The worker for scan_scsis. * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. * Global variables used : scsi_devices(linked list) */int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, int *sparse_lun, Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt, struct Scsi_Host * shpnt, char *scsi_result){ unsigned char scsi_cmd[12]; struct Scsi_Device_Template *sdtpnt; Scsi_Device * SDtail, *SDpnt=*SDpnt2; int bflags, type=-1; SDpnt->host = shpnt; SDpnt->id = dev; SDpnt->lun = lun; SDpnt->channel = channel; SDpnt->online = TRUE; /* Some low level driver could use device->type (DB) */ SDpnt->type = -1; /* * Assume that the device will have handshaking problems, and then fix this * field later if it turns out it doesn't */ SDpnt->borken = 1; SDpnt->was_reset = 0; SDpnt->expecting_cc_ua = 0; scsi_cmd[0] = TEST_UNIT_READY; scsi_cmd[1] = lun << 5; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0; SCpnt->host = SDpnt->host; SCpnt->device = SDpnt; SCpnt->target = SDpnt->id; SCpnt->lun = SDpnt->lun; SCpnt->channel = SDpnt->channel; { struct semaphore sem = MUTEX_LOCKED; SCpnt->request.sem = &sem; SCpnt->request.rq_status = RQ_SCSI_BUSY; spin_lock_irq(&io_request_lock); scsi_do_cmd (SCpnt, (void *) scsi_cmd, (void *) scsi_result, 256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5); spin_unlock_irq(&io_request_lock); down (&sem); SCpnt->request.sem = NULL; } SCSI_LOG_SCAN_BUS(3, printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n", dev, lun, SCpnt->result)); SCSI_LOG_SCAN_BUS(3,print_driverbyte(SCpnt->result)); SCSI_LOG_SCAN_BUS(3,print_hostbyte(SCpnt->result)); SCSI_LOG_SCAN_BUS(3,printk("\n")); if (SCpnt->result) { if (((driver_byte (SCpnt->result) & DRIVER_SENSE) || (status_byte (SCpnt->result) & CHECK_CONDITION)) && ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) { if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) && ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) && ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0)) return 1; } else return 0; } SCSI_LOG_SCAN_BUS(3,printk ("scsi: performing INQUIRY\n")); /* * Build an INQUIRY command block. */ scsi_cmd[0] = INQUIRY; scsi_cmd[1] = (lun << 5) & 0xe0; scsi_cmd[2] = 0; scsi_cmd[3] = 0; scsi_cmd[4] = 255; scsi_cmd[5] = 0; SCpnt->cmd_len = 0; { struct semaphore sem = MUTEX_LOCKED; SCpnt->request.sem = &sem; SCpnt->request.rq_status = RQ_SCSI_BUSY; spin_lock_irq(&io_request_lock); scsi_do_cmd (SCpnt, (void *) scsi_cmd, (void *) scsi_result, 256, scan_scsis_done, SCSI_TIMEOUT, 3); spin_unlock_irq(&io_request_lock); down (&sem); SCpnt->request.sem = NULL; } SCSI_LOG_SCAN_BUS(3,printk ("scsi: INQUIRY %s with code 0x%x\n", SCpnt->result ? "failed" : "successful", SCpnt->result)); if (SCpnt->result) return 0; /* assume no peripheral if any sort of error */ /* * Check the peripheral qualifier field - this tells us whether LUNS * are supported here or not. */ if( (scsi_result[0] >> 5) == 3 ) { return 0; /* assume no peripheral if any sort of error */ } /* * It would seem some TOSHIBA CDROM gets things wrong */ if (!strncmp (scsi_result + 8, "TOSHIBA", 7) && !strncmp (scsi_result + 16, "CD-ROM", 6) && scsi_result[0] == TYPE_DISK) { scsi_result[0] = TYPE_ROM; scsi_result[1] |= 0x80; /* removable */ } /* * It would seem the Panasonic DVD-RAM is backwards too * If DVD-RAM or PD media used, it seems to function * as Direct-Access */ if (!strncmp (scsi_result + 8, "MATSHITA", 7) && !strncmp (scsi_result + 16, "PD-2 LF-D100", 12)) { scsi_result[0] = TYPE_DISK; scsi_result[1] |= 0x80; /* removable */ } memcpy (SDpnt->vendor, scsi_result + 8, 8); memcpy (SDpnt->model, scsi_result + 16, 16); memcpy (SDpnt->rev, scsi_result + 32, 4); SDpnt->removable = (0x80 & scsi_result[1]) >> 7; SDpnt->online = TRUE; SDpnt->lockable = SDpnt->removable; SDpnt->changed = 0; SDpnt->access_count = 0; SDpnt->busy = 0; SDpnt->has_cmdblocks = 0; /* * Currently, all sequential devices are assumed to be tapes, all random * devices disk, with the appropriate read only flags set for ROM / WORM * treated as RO. */ switch (type = (scsi_result[0] & 0x1f)) { case TYPE_TAPE: case TYPE_DISK: case TYPE_MOD: case TYPE_PROCESSOR: case TYPE_SCANNER: case TYPE_MEDIUM_CHANGER: case TYPE_ENCLOSURE: SDpnt->writeable = 1; break; case TYPE_WORM: case TYPE_ROM: SDpnt->writeable = 0; break; default: printk ("scsi: unknown type %d\n", type); } SDpnt->device_blocked = FALSE; SDpnt->device_busy = 0; SDpnt->single_lun = 0; SDpnt->soft_reset = (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2); SDpnt->random = (type == TYPE_TAPE) ? 0 : 1; SDpnt->type = (type & 0x1f); print_inquiry (scsi_result); for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) if (sdtpnt->detect) SDpnt->attached += (*sdtpnt->detect) (SDpnt); SDpnt->scsi_level = scsi_result[2] & 0x07; if (SDpnt->scsi_level >= 2 || (SDpnt->scsi_level == 1 &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -