| /* |
| * scsi_scan.c Copyright (C) 2000 Eric Youngdale |
| * |
| * Bus scan logic. |
| * |
| * This used to live in scsi.c, but that file was just a laundry basket |
| * full of misc stuff. This got separated out in order to make things |
| * clearer. |
| */ |
| |
| #include <linux/config.h> |
| #include <linux/module.h> |
| #include <linux/init.h> |
| |
| #include <linux/blk.h> |
| |
| #include "scsi.h" |
| #include "hosts.h" |
| #include "constants.h" |
| |
| #ifdef CONFIG_KMOD |
| #include <linux/kmod.h> |
| #endif |
| |
| /* |
| * Flags for irregular SCSI devices that need special treatment |
| */ |
| #define BLIST_NOLUN 0x001 /* Don't scan for LUNs */ |
| #define BLIST_FORCELUN 0x002 /* Known to have LUNs, force sanning */ |
| #define BLIST_BORKEN 0x004 /* Flag for broken handshaking */ |
| #define BLIST_KEY 0x008 /* Needs to be unlocked by special command */ |
| #define BLIST_SINGLELUN 0x010 /* LUNs should better not be used in parallel */ |
| #define BLIST_NOTQ 0x020 /* Buggy Tagged Command Queuing */ |
| #define BLIST_SPARSELUN 0x040 /* Non consecutive LUN numbering */ |
| #define BLIST_MAX5LUN 0x080 /* Avoid LUNS >= 5 */ |
| #define BLIST_ISDISK 0x100 /* Treat as (removable) disk */ |
| #define BLIST_ISROM 0x200 /* Treat as (removable) CD-ROM */ |
| #define BLIST_LARGELUN 0x400 /* LUNs larger than 7 despite reporting as SCSI 2 */ |
| #define BLIST_INQUIRY_36 0x800 /* override additional length field */ |
| #define BLIST_INQUIRY_58 0x1000 /* ... for broken inquiry responses */ |
| |
| /* |
| * scan_scsis_single() return values. |
| */ |
| #define SCSI_SCAN_NO_RESPONSE 0 |
| #define SCSI_SCAN_DEVICE_PRESENT 1 |
| #define SCSI_SCAN_DEVICE_ADDED 2 |
| |
| static void print_inquiry(unsigned char *data); |
| static int scan_scsis_single(unsigned int channel, unsigned int dev, |
| unsigned int lun, int scsi_level, Scsi_Device ** SDpnt2, |
| struct Scsi_Host *shpnt, char *scsi_result); |
| static void scan_scsis_target(unsigned int channel, unsigned int dev, |
| Scsi_Device ** SDpnt2, struct Scsi_Host *shpnt, |
| char *scsi_result); |
| static int find_lun0_scsi_level(unsigned int channel, unsigned int dev, |
| struct Scsi_Host *shpnt); |
| |
| struct dev_info { |
| const char *vendor; |
| const char *model; |
| const char *revision; /* Latest revision known to be bad. Not used yet */ |
| unsigned flags; |
| }; |
| |
| /* |
| * This is what was previously known as the blacklist. The concept |
| * has been expanded so that we can specify other types of things we |
| * need to be aware of. |
| */ |
| static struct dev_info device_list[] = |
| { |
| /* The following devices are known not to tolerate a lun != 0 scan for |
| * one reason or another. Some will respond to all luns, others will |
| * lock up. |
| */ |
| {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"DENON", "DRD-25X", "V", BLIST_NOLUN}, /* Locks up if probed for lun != 0 */ |
| {"HITACHI", "DK312C", "CM81", BLIST_NOLUN}, /* Responds to all lun - dtg */ |
| {"HITACHI", "DK314C", "CR21", BLIST_NOLUN}, /* responds to all lun */ |
| {"IMS", "CDD521/10", "2.06", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ |
| {"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ |
| {"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ |
| {"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN}, /* Locks up when LUN>0 polled */ |
| {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN}, /* Locks-up sometimes when LUN>0 polled. */ |
| {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN}, /* guess what? */ |
| {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN}, /*Responds to all lun */ |
| {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN}, /* Locks-up when LUN>0 polled. */ |
| {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* Responds to all lun */ |
| {"RODIME", "RO3000S", "2.33", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 |
| * for aha152x controller, which causes |
| * SCSI code to reset bus.*/ |
| {"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 |
| * for aha152x controller, which causes |
| * SCSI code to reset bus.*/ |
| {"SEAGATE", "ST296", "921", BLIST_NOLUN}, /* Responds to all lun */ |
| {"SEAGATE", "ST1581", "6538", BLIST_NOLUN}, /* Responds to all lun */ |
| {"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN}, |
| {"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN}, |
| {"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN}, |
| {"SONY", "CD-ROM CDU-8012", "*", BLIST_NOLUN}, |
| {"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"TEAC", "CD-ROM", "1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 |
| * for seagate controller, which causes |
| * SCSI code to reset bus.*/ |
| {"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN}, /* Responds to all lun */ |
| {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, /* causes failed REQUEST SENSE on lun 1 |
| * for seagate controller, which causes |
| * SCSI code to reset bus.*/ |
| {"QUANTUM", "LPS525S", "3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ |
| {"QUANTUM", "PD1225S", "3110", BLIST_NOLUN}, /* Locks sometimes if polled for lun != 0 */ |
| {"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN}, /* Locks up when polled for lun != 0 */ |
| {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ |
| {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ |
| {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ |
| {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ |
| {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 |
| * extra reset */ |
| {"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ |
| {"RELISYS", "Scorpio", "*", BLIST_NOLUN}, /* responds to all LUN */ |
| {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all LUN */ |
| |
| /* |
| * Other types of devices that have special flags. |
| */ |
| {"SONY", "CD-ROM CDU-8001", "*", BLIST_BORKEN}, |
| {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, |
| {"IOMEGA", "Io20S *F", "*", BLIST_KEY}, |
| {"INSITE", "Floptical F*8I", "*", BLIST_KEY}, |
| {"INSITE", "I325VM", "*", BLIST_KEY}, |
| {"LASOUND","CDX7405","3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, |
| {"MICROP", "4110", "*", BLIST_NOTQ}, /* Buggy Tagged Queuing */ |
| {"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, |
| {"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, |
| {"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN}, |
| {"NAKAMICH", "MJ-4.8S", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, |
| {"NAKAMICH", "MJ-5.16S", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, |
| {"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, |
| {"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, |
| {"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, |
| {"EMULEX", "MD21/S2 ESDI", "*", BLIST_SINGLELUN}, |
| {"CANON", "IPUBJD", "*", BLIST_SPARSELUN}, |
| {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN}, |
| {"DEC","HSG80","*", BLIST_FORCELUN}, |
| {"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN}, |
| {"COMPAQ","CR3500","*", BLIST_FORCELUN}, |
| {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, |
| {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, |
| {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, |
| {"TOSHIBA","CDROM","*", BLIST_ISROM}, |
| {"TOSHIBA","CD-ROM","*", BLIST_ISROM}, |
| {"MegaRAID", "LD", "*", BLIST_FORCELUN}, |
| {"DGC", "RAID", "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0) |
| {"DGC", "DISK", "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) |
| {"DELL", "PV660F", "*", BLIST_SPARSELUN}, |
| {"DELL", "PV660F PSEUDO", "*", BLIST_SPARSELUN}, |
| {"DELL", "PSEUDO DEVICE .", "*", BLIST_SPARSELUN}, // Dell PV 530F |
| {"DELL", "PV530F", "*", BLIST_SPARSELUN}, // Dell PV 530F |
| {"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, |
| {"HP", "A6189A", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // HP VA7400, by Alar Aun |
| {"CMD", "CRA-7280", "*", BLIST_SPARSELUN}, // CMD RAID Controller |
| {"CNSI", "G7324", "*", BLIST_SPARSELUN}, // Chaparral G7324 RAID |
| {"CNSi", "G8324", "*", BLIST_SPARSELUN}, // Chaparral G8324 RAID |
| {"Zzyzx", "RocketStor 500S", "*", BLIST_SPARSELUN}, |
| {"Zzyzx", "RocketStor 2000", "*", BLIST_SPARSELUN}, |
| {"SONY", "TSL", "*", BLIST_FORCELUN}, // DDS3 & DDS4 autoloaders |
| {"DELL", "PERCRAID", "*", BLIST_FORCELUN}, |
| {"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, |
| {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN}, |
| {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN}, |
| {"COMPAQ", "MSA1000", "*", BLIST_FORCELUN}, |
| {"HP", "C1557A", "*", BLIST_FORCELUN}, |
| {"IBM", "AuSaV1S2", "*", BLIST_FORCELUN}, |
| |
| /* |
| * Must be at end of list... |
| */ |
| {NULL, NULL, NULL} |
| }; |
| |
| static char * scsi_null_device_strs = "nullnullnullnull"; |
| |
| #define MAX_SCSI_LUNS 0xFFFFFFFF |
| |
| #ifdef CONFIG_SCSI_MULTI_LUN |
| static unsigned int max_scsi_luns = MAX_SCSI_LUNS; |
| #else |
| static unsigned int max_scsi_luns = 1; |
| #endif |
| |
| #ifdef CONFIG_SCSI_REPORT_LUNS |
| /* |
| * max_scsi_report_luns: the maximum number of LUNS that will be |
| * returned from the REPORT LUNS command. 8 times this value must |
| * be allocated. In theory this could be up to an 8 byte value, but |
| * in practice, the maximum number of LUNs suppored by any device |
| * is about 16k. |
| */ |
| static unsigned int max_scsi_report_luns = 128; |
| #endif |
| |
| #ifdef MODULE |
| |
| MODULE_PARM(max_scsi_luns, "i"); |
| MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)"); |
| |
| #ifdef CONFIG_SCSI_REPORT_LUNS |
| MODULE_PARM(max_scsi_report_luns, "i"); |
| MODULE_PARM_DESC(max_scsi_report_luns, "REPORT LUNS maximum number of LUNS received (should be between 1 and 16384)"); |
| #endif |
| |
| #else |
| |
| static int __init scsi_luns_setup(char *str) |
| { |
| unsigned int tmp; |
| |
| if (get_option(&str, &tmp) == 1) { |
| max_scsi_luns = tmp; |
| return 1; |
| } else { |
| printk("scsi_luns_setup : usage max_scsi_luns=n " |
| "(n should be between 1 and 2^32-1)\n"); |
| return 0; |
| } |
| } |
| |
| __setup("max_scsi_luns=", scsi_luns_setup); |
| |
| #ifdef CONFIG_SCSI_REPORT_LUNS |
| static int __init max_scsi_report_luns_setup(char *str) |
| { |
| unsigned int tmp; |
| |
| if (get_option(&str, &tmp) == 1) { |
| max_scsi_report_luns = tmp; |
| return 1; |
| } else { |
| printk("scsi_report_luns_setup : usage max_scsi_report_luns=n " |
| "(n should be between 1 and 16384)\n"); |
| return 0; |
| } |
| } |
| |
| __setup("max_scsi_report_luns=", max_scsi_report_luns_setup); |
| #endif /* CONFIG_SCSI_REPORT_LUNS */ |
| |
| #endif |
| |
| #ifdef CONFIG_SCSI_REPORT_LUNS |
| /* |
| * Function: scsilun_to_int |
| * |
| * Purpose: Convert ScsiLun (8 byte LUN) to an int. |
| * |
| * Arguments: scsilun_pnt - pointer to a ScsiLun to be converted |
| * |
| * Lock status: None |
| * |
| * Returns: cpu ordered integer containing the truncated LUN value |
| * |
| * Notes: The ScsiLun is assumed to be four levels, with each level |
| * effectively containing a SCSI byte-ordered (big endidan) |
| * short; the addressing bits of each level are ignored (the |
| * highest two bits). For a description of the LUN format, post |
| * SCSI-3 see the SCSI Architecture Model, for SCSI-3 see the |
| * SCSI Controller Commands. |
| * |
| * Given a ScsiLun of: 0a 04 0b 03 00 00 00 00, this function |
| * returns the integer: 0x0b030a04 |
| */ |
| static int scsilun_to_int(ScsiLun *scsilun_pnt) |
| { |
| int i; |
| unsigned int lun; |
| |
| lun = 0; |
| for (i = 0; i < sizeof(lun); i += 2) |
| lun = lun | (((scsilun_pnt->scsi_lun[i] << 8) | |
| scsilun_pnt->scsi_lun[i + 1]) << (i * 8)); |
| return lun; |
| } |
| #endif |
| |
| static void print_inquiry(unsigned char *data) |
| { |
| int i; |
| |
| printk(" Vendor: "); |
| for (i = 8; i < 16; i++) { |
| if (data[i] >= 0x20 && i < data[4] + 5) |
| printk("%c", data[i]); |
| else |
| printk(" "); |
| } |
| |
| printk(" Model: "); |
| for (i = 16; i < 32; i++) { |
| if (data[i] >= 0x20 && i < data[4] + 5) |
| printk("%c", data[i]); |
| else |
| printk(" "); |
| } |
| |
| printk(" Rev: "); |
| for (i = 32; i < 36; i++) { |
| if (data[i] >= 0x20 && i < data[4] + 5) |
| printk("%c", data[i]); |
| else |
| printk(" "); |
| } |
| |
| printk("\n"); |
| |
| i = data[0] & 0x1f; |
| |
| printk(" Type: %s ", |
| i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown "); |
| printk(" ANSI SCSI revision: %02x", data[2] & 0x07); |
| if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1) |
| printk(" CCS\n"); |
| else |
| printk("\n"); |
| } |
| |
| static int get_device_flags(unsigned char *vendor_pnt, unsigned char *model_pnt) |
| { |
| int i = 0; |
| for (i = 0; 1; i++) { |
| if (device_list[i].vendor == NULL) |
| return 0; |
| while (*vendor_pnt && *vendor_pnt == ' ') |
| vendor_pnt++; |
| if (memcmp(device_list[i].vendor, vendor_pnt, |
| strlen(device_list[i].vendor))) |
| continue; |
| while (*model_pnt && *model_pnt == ' ') |
| model_pnt++; |
| if (memcmp(device_list[i].model, model_pnt, |
| strlen(device_list[i].model))) |
| continue; |
| return device_list[i].flags; |
| } |
| return 0; |
| } |
| |
| /* |
| * 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. |
| */ |
| void scan_scsis(struct Scsi_Host *shpnt, |
| uint hardcoded, |
| uint hchannel, |
| uint hid, |
| uint hlun) |
| { |
| uint channel; |
| unsigned int dev; |
| unsigned int lun; |
| unsigned char *scsi_result; |
| unsigned char scsi_result0[256]; |
| Scsi_Device *SDpnt; |
| Scsi_Device *SDtail; |
| |
| scsi_result = NULL; |
| |
| SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), |
| GFP_ATOMIC); |
| if (SDpnt) { |
| memset(SDpnt, 0, sizeof(Scsi_Device)); |
| SDpnt->vendor = scsi_null_device_strs; |
| SDpnt->model = scsi_null_device_strs; |
| SDpnt->rev = scsi_null_device_strs; |
| /* |
| * 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->request_queue.queuedata = (void *) SDpnt; |
| /* Make sure we have something that is valid for DMA purposes */ |
| scsi_result = ((!shpnt->unchecked_isa_dma) |
| ? &scsi_result0[0] : kmalloc(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 |
| */ |
| SDpnt->queue_depth = 1; |
| SDpnt->host = shpnt; |
| SDpnt->online = TRUE; |
| |
| scsi_initialize_merge_fn(SDpnt); |
| |
| /* |
| * Initialize the object that we will use to wait for command blocks. |
| */ |
| init_waitqueue_head(&SDpnt->scpnt_wait); |
| |
| /* |
| * 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. |
| */ |
| if (hardcoded == 1) { |
| Scsi_Device *oldSDpnt = SDpnt; |
| struct Scsi_Device_Template *sdtpnt; |
| unsigned int lun0_sl; |
| |
| 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; |
| if ((0 == lun) || (lun > 7)) |
| lun0_sl = SCSI_3; /* actually don't care for 0 == lun */ |
| else |
| lun0_sl = find_lun0_scsi_level(channel, dev, shpnt); |
| scan_scsis_single(channel, dev, lun, lun0_sl, &SDpnt, shpnt, |
| scsi_result); |
| if (SDpnt != oldSDpnt) { |
| |
| /* it could happen the blockdevice hasn't yet been inited */ |
| /* queue_depth() moved from scsi_proc_info() so that |
| it is called before scsi_build_commandblocks() */ |
| if (shpnt->select_queue_depths != NULL) |
| (shpnt->select_queue_depths)(shpnt, |
| shpnt->host_queue); |
| |
| for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) |
| if (sdtpnt->init && sdtpnt->dev_noticed) |
| (*sdtpnt->init) (); |
| |
| 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 ?? */ |
| } |
| } |
| } |
| } |
| 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) { |
| scan_scsis_target(channel, order_dev, |
| &SDpnt, shpnt, scsi_result); |
| } |
| } |
| } |
| } /* 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); |
| if (SDpnt->inquiry) |
| kfree(SDpnt->inquiry); |
| 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")); |
| } |
| } |
| } |
| |
| /* |
| * Function: scan_scsis_single |
| * |
| * Purpose: Determine if a SCSI device (a single LUN) exists, and |
| * configure it into the system. |
| * |
| * Arguments: channel - the host's channel |
| * dev - target dev (target id) |
| * lun - LUN |
| * scsi_level - SCSI 1, 2 or 3 |
| * SDpnt2 - pointer to pointer of a preallocated Scsi_Device |
| * shpnt - host device to use |
| * scsi_result - preallocated buffer for the SCSI command result |
| * |
| * Lock status: None |
| * |
| * Returns: SCSI_SCAN_NO_RESPONSE - no valid response received from the |
| * device, this includes allocation failures preventing IO from |
| * being sent, or any general failures. |
| * |
| * SCSI_SCAN_DEVICE_PRESENT - device responded, SDpnt2 has all |
| * values needed to send IO set, plus scsi_level is set, but no |
| * new Scsi_Device was added/allocated. |
| * |
| * SCSI_SCAN_DEVICE_ADDED - device responded, and added to list; |
| * SDpnt2 filled, and pointed to new allocated Scsi_Device. |
| * |
| * Notes: This could be cleaned up more by moving SDpnt2 and Scsi_Device |
| * allocation into scan_scsis_target. |
| */ |
| static int scan_scsis_single(unsigned int channel, unsigned int dev, |
| unsigned int lun, int scsi_level, 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; |
| int possible_inq_resp_len; |
| 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; |
| |
| if (NULL == (SRpnt = scsi_allocate_request(SDpnt))) { |
| printk("scan_scsis_single: no memory\n"); |
| scsi_release_commandblocks(SDpnt); |
| return SCSI_SCAN_NO_RESPONSE; |
| } |
| |
| /* |
| * 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 scan: INQUIRY to host %d channel %d id %d lun %d\n", |
| shpnt->host_no, channel, dev, lun) |
| ); |
| |
| /* |
| * Build an INQUIRY command block. |
| */ |
| memset(scsi_cmd, 0, 6); |
| scsi_cmd[0] = INQUIRY; |
| if ((lun > 0) && (scsi_level <= SCSI_2)) |
| scsi_cmd[1] = (lun << 5) & 0xe0; |
| scsi_cmd[4] = 36; /* issue conservative alloc_length */ |
| SRpnt->sr_cmd_len = 0; |
| SRpnt->sr_data_direction = SCSI_DATA_READ; |
| |
| memset(scsi_result, 0, 36); |
| scsi_wait_req (SRpnt, (void *) scsi_cmd, |
| (void *) scsi_result, |
| 36, 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)); |
| |
| /* |
| * Now that we don't do TEST_UNIT_READY anymore, we must be prepared |
| * for media change conditions here, so cannot require zero result. |
| */ |
| if (SRpnt->sr_result) { |
| if ((driver_byte(SRpnt->sr_result) & DRIVER_SENSE) != 0 && |
| (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION && |
| SRpnt->sr_sense_buffer[12] == 0x28 && |
| SRpnt->sr_sense_buffer[13] == 0) { |
| /* not-ready to ready transition - good */ |
| /* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */ |
| } else { |
| /* assume no peripheral if any other sort of error */ |
| scsi_release_request(SRpnt); |
| return 0; |
| } |
| } |
| |
| /* |
| * Get any flags for this device. |
| */ |
| bflags = get_device_flags (&scsi_result[8], &scsi_result[16]); |
| |
| possible_inq_resp_len = (unsigned char)scsi_result[4] + 5; |
| if (BLIST_INQUIRY_36 & bflags) |
| possible_inq_resp_len = 36; |
| else if (BLIST_INQUIRY_58 & bflags) |
| possible_inq_resp_len = 58; |
| else if (possible_inq_resp_len > 255) |
| possible_inq_resp_len = 36; /* sanity */ |
| |
| if (possible_inq_resp_len > 36) { /* do additional INQUIRY */ |
| memset(scsi_cmd, 0, 6); |
| scsi_cmd[0] = INQUIRY; |
| if ((lun > 0) && (scsi_level <= SCSI_2)) |
| scsi_cmd[1] = (lun << 5) & 0xe0; |
| scsi_cmd[4] = (unsigned char)possible_inq_resp_len; |
| 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); |
| /* assume successful */ |
| } |
| SDpnt->inquiry_len = possible_inq_resp_len; |
| SDpnt->inquiry = kmalloc(possible_inq_resp_len, GFP_ATOMIC); |
| if (NULL == SDpnt->inquiry) { |
| scsi_release_commandblocks(SDpnt); |
| scsi_release_request(SRpnt); |
| return SCSI_SCAN_NO_RESPONSE; |
| } |
| memcpy(SDpnt->inquiry, scsi_result, possible_inq_resp_len); |
| SDpnt->vendor = (char *)(SDpnt->inquiry + 8); |
| SDpnt->model = (char *)(SDpnt->inquiry + 16); |
| SDpnt->rev = (char *)(SDpnt->inquiry + 32); |
| |
| SDpnt->scsi_level = scsi_result[2] & 0x07; |
| if (SDpnt->scsi_level >= 2 || |
| (SDpnt->scsi_level == 1 && |
| (scsi_result[3] & 0x0f) == 1)) |
| SDpnt->scsi_level++; |
| |
| /* |
| * Check the peripheral qualifier field - this tells us whether LUNS |
| * are supported here or not. |
| */ |
| if ((scsi_result[0] >> 5) == 3) { |
| /* |
| * Peripheral qualifier 3 (011b): The device server is not |
| * capable of supporting a physical device on this logical |
| * unit. |
| */ |
| scsi_release_commandblocks(SDpnt); |
| scsi_release_request(SRpnt); |
| return SCSI_SCAN_DEVICE_PRESENT; |
| } |
| /* 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 */ |
| } |
| |
| |
| 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_PRINTER: |
| 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); |
| |
| /* |
| * 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; |
| if (shpnt->max_lun <= 8) |
| scsi_cmd[1] = (lun << 5) & 0xe0; |
| else scsi_cmd[1] = 0; /* any other idea? */ |
| 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_result no longer holds inquiry data. |
| */ |
| } |
| |
| 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 SCSI_SCAN_NO_RESPONSE; |
| } |
| memset(SDpnt, 0, sizeof(Scsi_Device)); |
| SDpnt->vendor = scsi_null_device_strs; |
| SDpnt->model = scsi_null_device_strs; |
| SDpnt->rev = scsi_null_device_strs; |
| |
| *SDpnt2 = SDpnt; |
| SDpnt->queue_depth = 1; |
| SDpnt->host = shpnt; |
| SDpnt->online = TRUE; |
| SDpnt->scsi_level = scsi_level; |
| |
| /* |
| * 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; |
| scsi_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; |
| |
| return SCSI_SCAN_DEVICE_ADDED; |
| } |
| |
| /* |
| * Function: scsi_report_lun_scan |
| * |
| * Purpose: Use a SCSI REPORT LUN to determine what LUNs to scan. |
| * |
| * Arguments: SDlun0_pnt - pointer to a Scsi_Device for LUN 0 |
| * channel - the host's channel |
| * dev - target dev (target id) |
| * SDpnt2 - pointer to pointer of a preallocated Scsi_Device |
| * shpnt - host device to use |
| * scsi_result - preallocated buffer for the SCSI command result |
| * |
| * Lock status: None |
| * |
| * Returns: If the LUNs for device at shpnt/channel/dev are scanned, |
| * return 0, else return 1. |
| * |
| * Notes: This code copies and truncates the 8 byte LUN into the |
| * current 4 byte (int) lun. |
| */ |
| static int scsi_report_lun_scan(Scsi_Device *SDlun0_pnt, unsigned |
| int channel, unsigned int dev, Scsi_Device **SDpnt2, |
| struct Scsi_Host *shpnt, char *scsi_result) |
| { |
| #ifdef CONFIG_SCSI_REPORT_LUNS |
| |
| char devname[64]; |
| unsigned char scsi_cmd[MAX_COMMAND_SIZE]; |
| unsigned int length; |
| unsigned int lun; |
| unsigned int num_luns; |
| unsigned int retries; |
| ScsiLun *fcp_cur_lun_pnt, *lun_data_pnt; |
| Scsi_Request *SRpnt; |
| int scsi_level; |
| char *byte_pnt; |
| int got_command_blocks = 0; |
| |
| /* |
| * Only support SCSI-3 and up devices. |
| */ |
| if (SDlun0_pnt->scsi_level < SCSI_3) |
| return 1; |
| |
| /* |
| * Note SDlun0_pnt might be invalid after scan_scsis_single is called. |
| */ |
| |
| /* |
| * Command blocks might be built depending on whether LUN 0 was |
| * configured or not. Checking has_cmdblocks here is ugly. |
| */ |
| if (SDlun0_pnt->has_cmdblocks == 0) { |
| got_command_blocks = 1; |
| scsi_build_commandblocks(SDlun0_pnt); |
| } |
| SRpnt = scsi_allocate_request(SDlun0_pnt); |
| |
| sprintf (devname, "host %d channel %d id %d", |
| SDlun0_pnt->host->host_no, SDlun0_pnt->channel, |
| SDlun0_pnt->id); |
| /* |
| * Allocate enough to hold the header (the same size as one ScsiLun) |
| * plus the max number of luns we are requesting. |
| * |
| * XXX: Maybe allocate this once, like scsi_result, and pass it down. |
| * scsi_result can't be used, as it is needed for the scan INQUIRY |
| * data. In addition, reallocating and trying again (with the exact |
| * amount we need) would be nice, but then we need to somehow limit the |
| * size allocated based on the available memory (and limits of kmalloc). |
| */ |
| length = (max_scsi_report_luns + 1) * sizeof(ScsiLun); |
| lun_data_pnt = (ScsiLun *) kmalloc(length, |
| (shpnt->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC)); |
| if (lun_data_pnt == NULL) { |
| printk("scsi: scsi_report_lun_scan: Cannot malloc\n"); |
| if (got_command_blocks) |
| scsi_release_commandblocks(SDlun0_pnt); |
| return 1; |
| } |
| |
| scsi_cmd[0] = REPORT_LUNS; |
| /* |
| * bytes 1 - 5: reserved, set to zero. |
| */ |
| memset(&scsi_cmd[1], 0, 5); |
| /* |
| * bytes 6 - 9: length of the command. |
| */ |
| scsi_cmd[6] = (unsigned char) (length >> 24) & 0xff; |
| scsi_cmd[7] = (unsigned char) (length >> 16) & 0xff; |
| scsi_cmd[8] = (unsigned char) (length >> 8) & 0xff; |
| scsi_cmd[9] = (unsigned char) length & 0xff; |
| |
| scsi_cmd[10] = 0; /* reserved */ |
| scsi_cmd[11] = 0; /* control */ |
| SRpnt->sr_cmd_len = 0; |
| SRpnt->sr_data_direction = SCSI_DATA_READ; |
| |
| /* |
| * We can get a UNIT ATTENTION, for example a power on/reset, so retry |
| * a few times (like sd.c does for TEST UNIT READY). Experience shows |
| * some combinations of adapter/devices get at least two power |
| * on/resets. |
| * |
| * Illegal requests (for devices that do not support REPORT LUNS) |
| * should come through as a check condition, and will not generate a |
| * retry. |
| */ |
| retries = 0; |
| while (retries++ < 3) { |
| SCSI_LOG_SCAN_BUS(3, |
| printk("scsi: Sending REPORT LUNS to %s (try %d)\n", |
| devname, retries)); |
| |
| scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) lun_data_pnt, |
| length, SCSI_TIMEOUT+4*HZ, 3); |
| |
| SCSI_LOG_SCAN_BUS(3, |
| printk("scsi: REPORT LUNS %s (try %d) result 0x%x\n", |
| SRpnt->sr_result ? "failed" : "successful", retries, |
| SRpnt->sr_result)); |
| |
| if (SRpnt->sr_result == 0 |
| || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION) |
| break; |
| } |
| |
| scsi_release_request(SRpnt); |
| if (got_command_blocks) |
| scsi_release_commandblocks(SDlun0_pnt); |
| |
| if (SRpnt->sr_result) { |
| kfree((char *) lun_data_pnt); |
| return 1; |
| } |
| |
| /* |
| * Get the length from the first four bytes of lun_data_pnt. |
| */ |
| byte_pnt = (char*) lun_data_pnt->scsi_lun; |
| length = ((byte_pnt[0] << 24) | (byte_pnt[1] << 16) | |
| (byte_pnt[2] << 8) | (byte_pnt[3] << 0)); |
| if ((length / sizeof(ScsiLun)) > max_scsi_report_luns) { |
| printk("scsi: On %s only %d (max_scsi_report_luns) of %d luns" |
| " reported, try increasing max_scsi_report_luns.\n", |
| devname, max_scsi_report_luns, |
| length / sizeof(ScsiLun)); |
| num_luns = max_scsi_report_luns; |
| } else |
| num_luns = (length / sizeof(ScsiLun)); |
| |
| scsi_level = SDlun0_pnt->scsi_level; |
| |
| SCSI_LOG_SCAN_BUS(3, |
| printk("scsi: REPORT LUN scan of host %d channel %d id %d\n", |
| SDlun0_pnt->host->host_no, SDlun0_pnt->channel, |
| SDlun0_pnt->id)); |
| /* |
| * Scan the luns in lun_data_pnt. The entry at offset 0 is really |
| * the header, so start at 1 and go up to and including num_luns. |
| */ |
| for (fcp_cur_lun_pnt = &lun_data_pnt[1]; |
| fcp_cur_lun_pnt <= &lun_data_pnt[num_luns]; |
| fcp_cur_lun_pnt++) { |
| lun = scsilun_to_int(fcp_cur_lun_pnt); |
| /* |
| * Check if the unused part of fcp_cur_lun_pnt is non-zero, |
| * and so does not fit in lun. |
| */ |
| if (memcmp(&fcp_cur_lun_pnt->scsi_lun[sizeof(lun)], |
| "\0\0\0\0", 4) != 0) { |
| int i; |
| |
| /* |
| * Output an error displaying the LUN in byte order, |
| * this differs from what linux would print for the |
| * integer LUN value. |
| */ |
| printk("scsi: %s lun 0x", devname); |
| byte_pnt = (char*) fcp_cur_lun_pnt->scsi_lun; |
| for (i = 0; i < sizeof(ScsiLun); i++) |
| printk("%02x", byte_pnt[i]); |
| printk(" has a LUN larger than that supported by" |
| " the kernel\n"); |
| } else if (lun == 0) { |
| /* |
| * LUN 0 has already been scanned. |
| */ |
| } else if (lun > shpnt->max_lun) { |
| printk("scsi: %s lun %d has a LUN larger than allowed" |
| " by the host adapter\n", devname, lun); |
| } else { |
| /* |
| * Don't use SDlun0_pnt after this call - it can be |
| * overwritten via SDpnt2 if there was no real device |
| * at LUN 0. |
| */ |
| if (scan_scsis_single(channel, dev, lun, |
| scsi_level, SDpnt2, shpnt, scsi_result) |
| == SCSI_SCAN_NO_RESPONSE) { |
| /* |
| * Got some results, but now none, abort. |
| */ |
| printk("scsi: no response from %s lun %d while" |
| " scanning, scan aborted\n", devname, |
| lun); |
| break; |
| } |
| } |
| } |
| |
| kfree((char *) lun_data_pnt); |
| return 0; |
| |
| #else |
| return 1; |
| #endif /* CONFIG_SCSI_REPORT_LUNS */ |
| |
| } |
| |
| /* |
| * Function: scan_scsis_target |
| * |
| * Purpose: Scan the given scsi target dev, and as needed all LUNs |
| * on the target dev. |
| * |
| * Arguments: channel - the host's channel |
| * dev - target dev (target id) |
| * SDpnt2 - pointer to pointer of a preallocated Scsi_Device |
| * shpnt - host device to use |
| * scsi_result - preallocated buffer for the SCSI command result |
| * |
| * Lock status: None |
| * |
| * Returns: void |
| * |
| * Notes: This tries to be compatible with linux 2.4.x. This function |
| * relies on scan_scsis_single to setup SDlun0_pnt. |
| * |
| * It would be better if the Scsi_Device allocation and freeing |
| * was done here, rather than oddly embedded in scan_scsis_single |
| * and scan_scsis. |
| */ |
| static void scan_scsis_target(unsigned int channel, unsigned int dev, |
| Scsi_Device **SDpnt2, struct Scsi_Host *shpnt, |
| char *scsi_result) |
| { |
| int bflags, scsi_level; |
| Scsi_Device *SDlun0_pnt; |
| unsigned int sparse_lun = 0; |
| unsigned int max_dev_lun, lun; |
| unsigned int sdlun0_res; |
| |
| /* |
| * Scan lun 0, use the results to determine whether to scan further. |
| * Ideally, we would not configure LUN 0 until we scan. |
| */ |
| SDlun0_pnt = *SDpnt2; |
| sdlun0_res = scan_scsis_single(channel, dev, 0 /* LUN 0 */, SCSI_2, |
| SDpnt2, shpnt, scsi_result); |
| if (sdlun0_res == SCSI_SCAN_NO_RESPONSE) |
| return; |
| |
| /* |
| * If no new SDpnt was allocated (SCSI_SCAN_DEVICE_PRESENT), SDlun0_pnt |
| * can later be modified. It is unlikely the lun level would change, |
| * but save it just in case. |
| */ |
| scsi_level = SDlun0_pnt->scsi_level; |
| |
| /* |
| * We could probably use and save the bflags from lun 0 for all luns |
| * on a target, but be safe and match current behaviour. (LUN 0 |
| * bflags controls the target settings checked within this function.) |
| */ |
| bflags = get_device_flags (SDlun0_pnt->vendor, SDlun0_pnt->model); |
| |
| /* |
| * Some scsi devices cannot be polled for lun != 0 due to firmware bugs |
| */ |
| if (bflags & BLIST_NOLUN) |
| return; |
| |
| /* |
| * Ending the scan here if max_scsi_luns == 1 breaks scanning of |
| * SPARSE, FORCE, MAX5 LUN devices, and the report lun scans. |
| */ |
| |
| if (scsi_report_lun_scan(SDlun0_pnt, channel, dev, SDpnt2, shpnt, |
| scsi_result) == 0) |
| return; |
| |
| SCSI_LOG_SCAN_BUS(3, |
| printk("scsi: Sequential scan of host %d channel %d id %d\n", |
| SDlun0_pnt->host->host_no, SDlun0_pnt->channel, |
| SDlun0_pnt->id)); |
| |
| max_dev_lun = (max_scsi_luns < shpnt->max_lun ? |
| max_scsi_luns : shpnt->max_lun); |
| /* |
| * 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 = shpnt->max_lun; |
| sparse_lun = 1; |
| } else if (sdlun0_res == SCSI_SCAN_DEVICE_PRESENT) { |
| /* |
| * LUN 0 responded, but no LUN 0 was added, don't scan any |
| * further. This matches linux 2.4.x behaviour. |
| */ |
| return; |
| } |
| /* |
| * If less than SCSI_1_CSS, and not a forced lun scan, stop |
| * scanning, this matches 2.4 behaviour, but it could be a bug |
| * to scan SCSI_1_CSS devices past LUN 0. |
| */ |
| if ((scsi_level < SCSI_1_CCS) && ((bflags & |
| (BLIST_FORCELUN | BLIST_SPARSELUN | BLIST_MAX5LUN)) == 0)) |
| return; |
| /* |
| * 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 = shpnt->max_lun; |
| /* |
| * REGAL CDC-4X: avoid hang after LUN 4 |
| */ |
| if (bflags & BLIST_MAX5LUN) |
| max_dev_lun = min(5U, max_dev_lun); |
| /* |
| * Do not scan past LUN 7. |
| */ |
| if (scsi_level < SCSI_3) |
| max_dev_lun = min(8U, max_dev_lun); |
| |
| /* |
| * We have already scanned lun 0. |
| */ |
| for (lun = 1; lun < max_dev_lun; ++lun) { |
| int res; |
| /* |
| * Scan until scan_scsis_single says stop, |
| * unless sparse_lun is set. |
| */ |
| res = scan_scsis_single(channel, dev, lun, |
| scsi_level, SDpnt2, shpnt, scsi_result); |
| if (res == SCSI_SCAN_NO_RESPONSE) { |
| /* |
| * Got a response on LUN 0, but now no response. |
| */ |
| printk("scsi: no response from device" |
| " host%d/bus%d/target%d/lun%d" |
| " while scanning, scan aborted\n", |
| shpnt->host_no, channel, dev, lun); |
| return; |
| } else if ((res == SCSI_SCAN_DEVICE_PRESENT) |
| && !sparse_lun) |
| return; |
| } |
| } |
| |
| /* |
| * Returns the scsi_level of lun0 on this host, channel and dev (if already |
| * known), otherwise returns SCSI_2. |
| */ |
| static int find_lun0_scsi_level(unsigned int channel, unsigned int dev, |
| struct Scsi_Host *shpnt) |
| { |
| int res = SCSI_2; |
| Scsi_Device *SDpnt; |
| |
| for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) |
| { |
| if ((0 == SDpnt->lun) && (dev == SDpnt->id) && |
| (channel == SDpnt->channel)) |
| return (int)SDpnt->scsi_level; |
| } |
| /* haven't found lun0, should send INQUIRY but take easy route */ |
| return res; |
| } |