📄 scsi.c
字号:
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); 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);} resize_dma_pool(); for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { if(sdtpnt->finish && sdtpnt->nr_dev) {(*sdtpnt->finish)();} } } } else { for (channel = 0; channel <= shpnt->max_channel; channel++) { for (dev = 0; dev < shpnt->max_id; ++dev) { if (shpnt->this_id != 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, 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 */ leave: {/* Unchain SCpnt from host_queue */ Scsi_Cmnd *prev, *next, *hqptr; for(hqptr = shpnt->host_queue; hqptr != SCpnt; hqptr = hqptr->next) ; if(hqptr) { prev = hqptr->prev; next = hqptr->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);}/* * 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; SDtail = scsi_devices; if (scsi_devices) while (SDtail->next) SDtail = SDtail->next; memset (SDpnt, 0, sizeof (Scsi_Device)); SDpnt->host = shpnt; SDpnt->id = dev; SDpnt->lun = lun; SDpnt->channel = channel; /* 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; scsi_do_cmd (SCpnt, (void *) scsi_cmd, (void *) scsi_result, 256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5); down (&sem); }#if defined(DEBUG) || defined(DEBUG_INIT) printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n", dev, lun, SCpnt->result); print_driverbyte(SCpnt->result); print_hostbyte(SCpnt->result); printk("\n");#endif 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; }#if defined (DEBUG) || defined(DEBUG_INIT) printk ("scsi: performing INQUIRY\n");#endif /* * 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; scsi_do_cmd (SCpnt, (void *) scsi_cmd, (void *) scsi_result, 256, scan_scsis_done, SCSI_TIMEOUT, 3); down (&sem); }#if defined(DEBUG) || defined(DEBUG_INIT) printk ("scsi: INQUIRY %s with code 0x%x\n", SCpnt->result ? "failed" : "successful", SCpnt->result);#endif 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 */ } if (!strncmp (scsi_result + 8, "NEC", 3)) { if (!strncmp (scsi_result + 16, "CD-ROM DRIVE:84 ", 16) || !strncmp (scsi_result + 16, "CD-ROM DRIVE:25", 15)) SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR; else SDpnt->manufacturer = SCSI_MAN_NEC; } else if (!strncmp (scsi_result + 8, "TOSHIBA", 7)) SDpnt->manufacturer = SCSI_MAN_TOSHIBA; else if (!strncmp (scsi_result + 8, "SONY", 4)) SDpnt->manufacturer = SCSI_MAN_SONY; else if (!strncmp (scsi_result + 8, "PIONEER", 7)) SDpnt->manufacturer = SCSI_MAN_PIONEER; else SDpnt->manufacturer = SCSI_MAN_UNKNOWN; 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->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: SDpnt->writeable = 1; break; case TYPE_WORM: case TYPE_ROM: SDpnt->writeable = 0; break; default: printk ("scsi: unknown type %d\n", type); } 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 && (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; scsi_do_cmd (SCpnt, (void *) scsi_cmd, (void *) scsi_result, 0x2a, scan_scsis_done, SCSI_TIMEOUT, 3); down (&sem); } } /* Add this device to the linked list at the end */ if (SDtail) SDtail->next = SDpnt; else scsi_devices = SDpnt; SDtail = SDpnt; SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC); *SDpnt2=SDpnt; if (!SDpnt) printk ("scsi: scan_scsis_single: Cannot malloc\n"); /* * 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 is our time out function, called when the timer expires for a * given host adapter. It will attempt to abort the currently executing * command, that failing perform a kernel panic. */static void scsi_times_out (Scsi_Cmnd * SCpnt){ switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3)) { case NORMAL_TIMEOUT: {#ifdef DEBUG_TIMEOUT scsi_dump_status();#endif } if (!scsi_abort (SCpnt, DID_TIME_OUT)) return; case IN_ABORT: printk("SCSI host %d abort (pid %ld) timed out - resetting\n", SCpnt->host->host_no, SCpnt->pid); if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS)) return; case IN_RESET: case (IN_ABORT | IN_RESET): /* This might be controversial, but if there is a bus hang, * you might conceivably want the machine up and running * esp if you have an ide disk. */ printk("SCSI host %d channel %d reset (pid %ld) timed out - " "trying harder\n", SCpnt->host->host_no, SCpnt->channel, SCpnt->pid); SCpnt->internal_timeout &= ~IN_RESET; SCpnt->internal_timeout |= IN_RESET2; scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET); return; case IN_RESET2: case (IN_ABORT | IN_RESET2):
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -