📄 scsi_scan.c
字号:
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, 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 */ leave: { /* Unchain SRpnt 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) { blk_cleanup_queue(&SDpnt->request_queue); kfree((char *) SDpnt); } /* If we allocated a buffer so we could do DMA, free it now */ if (scsi_result != &scsi_result0[0] && scsi_result != NULL) { kfree(scsi_result); } { 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) */static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun, int *sparse_lun, Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, char *scsi_result){ char devname[64]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; struct Scsi_Device_Template *sdtpnt; Scsi_Device *SDtail, *SDpnt = *SDpnt2; Scsi_Request * SRpnt; int bflags, type = -1; extern devfs_handle_t scsi_devfs_handle; SDpnt->host = shpnt; SDpnt->id = dev; SDpnt->lun = lun; SDpnt->channel = channel; SDpnt->online = TRUE; scsi_build_commandblocks(SDpnt); /* 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; SDpnt->starved = 0; SRpnt = scsi_allocate_request(SDpnt); /* * We used to do a TEST_UNIT_READY before the INQUIRY but that was * not really necessary. Spec recommends using INQUIRY to scan for * devices (and TEST_UNIT_READY to poll for media change). - Paul G. */ 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; SRpnt->sr_cmd_len = 0; SRpnt->sr_data_direction = SCSI_DATA_READ; scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) scsi_result, 256, SCSI_TIMEOUT+4*HZ, 3); SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n", SRpnt->sr_result ? "failed" : "successful", SRpnt->sr_result)); if (SRpnt->sr_result) { scsi_release_request(SRpnt); 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) { scsi_release_request(SRpnt); return 0; /* assume no peripheral if any sort of error */ } /* * Get any flags for this device. */ bflags = get_device_flags (scsi_result); /* The Toshiba ROM was "gender-changed" here as an inline hack. This is now much more generic. This is a mess: What we really want is to leave the scsi_result alone, and just change the SDpnt structure. And the SDpnt is what we want print_inquiry to print. -- REW */ if (bflags & BLIST_ISDISK) { scsi_result[0] = TYPE_DISK; scsi_result[1] |= 0x80; /* removable */ } if (bflags & BLIST_ISROM) { scsi_result[0] = TYPE_ROM; 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; /* Use the peripheral qualifier field to determine online/offline */ if (((scsi_result[0] >> 5) & 7) == 1) SDpnt->online = FALSE; else 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: case TYPE_COMM: 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); sprintf (devname, "host%d/bus%d/target%d/lun%d", SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun); if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname); else SDpnt->de = devfs_mk_dir (scsi_devfs_handle, devname, NULL); 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 && (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; /* * 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; SRpnt->sr_cmd_len = 0; SRpnt->sr_data_direction = SCSI_DATA_READ; scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) scsi_result, 0x2a, SCSI_TIMEOUT, 3); } scsi_release_request(SRpnt); SRpnt = NULL; scsi_release_commandblocks(SDpnt); /* * 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 *) kmalloc(sizeof(Scsi_Device), GFP_ATOMIC); if (!SDpnt) { printk("scsi: scan_scsis_single: Cannot malloc\n"); return 0; } memset(SDpnt, 0, sizeof(Scsi_Device)); *SDpnt2 = SDpnt; SDpnt->queue_depth = 1; SDpnt->host = shpnt; SDpnt->online = TRUE; /* * Register the queue for the device. All I/O requests will come * in through here. We also need to register a pointer to * ourselves, since the queue handler won't know what device * the queue actually represents. We could look it up, but it * is pointless work. */ scsi_initialize_queue(SDpnt, shpnt); SDpnt->host = shpnt; initialize_merge_fn(SDpnt); /* * Mark this device as online, or otherwise we won't be able to do much with it. */ SDpnt->online = TRUE; /* * Initialize the object that we will use to wait for command blocks. */ init_waitqueue_head(&SDpnt->scpnt_wait); /* * 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -