--- linux-2.4.18-orig/drivers/scsi/hosts.h Mon Feb 25 14:38:04 2002 +++ linux-2.4.18/drivers/scsi/hosts.h Wed Oct 2 12:06:20 2002 @@ -418,6 +418,8 @@ */ unsigned some_device_starved:1; + unsigned init_done:1; + unsigned char need_scan; void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *); /* --- linux-2.4.18-orig/drivers/scsi/scsi.c Mon Feb 25 14:38:04 2002 +++ linux-2.4.18/drivers/scsi/scsi.c Wed Oct 2 12:06:20 2002 @@ -1975,8 +1975,10 @@ for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) if (SDpnt->host->hostt == tpnt) { for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if (sdtpnt->attach) + if (sdtpnt->attach) { (*sdtpnt->attach) (SDpnt); + SDpnt->need_attach = FALSE; + } if (SDpnt->attached) { scsi_build_commandblocks(SDpnt); if (0 == SDpnt->has_cmdblocks) @@ -1998,6 +2000,9 @@ (*sdtpnt->finish) (); } } + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { + shpnt->init_done = 1; + } } #if defined(USE_STATIC_SCSI_MEMORY) printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n", @@ -2291,8 +2296,10 @@ SDpnt = SDpnt->next) { SDpnt->attached += SDpnt->detected; SDpnt->detected = 0; - if (tpnt->attach) + if (tpnt->attach) { (*tpnt->attach) (SDpnt); + SDpnt->need_attach = FALSE; + } /* * If this driver attached to the device, and don't have any * command blocks for this device, allocate some. --- linux-2.4.18-orig/drivers/scsi/scsi.h Mon Feb 25 14:38:04 2002 +++ linux-2.4.18/drivers/scsi/scsi.h Wed Oct 2 12:06:20 2002 @@ -617,6 +617,7 @@ unsigned remap:1; /* support remapping */ unsigned starved:1; /* unable to process commands because host busy */ + unsigned need_attach:1; /* newly rescanned, need to attach device */ // Flag to allow revalidate to succeed in sd_open int allow_revalidate; --- linux-2.4.18-orig/drivers/scsi/scsi_lib.c Fri Oct 12 18:35:54 2001 +++ linux-2.4.18/drivers/scsi/scsi_lib.c Wed Oct 2 14:04:39 2002 @@ -5,6 +5,8 @@ * Initial versions: Eric Youngdale (eric@andante.org). * Based upon conversations with large numbers * of people at Linux Expo. + * 10/02/2002 - Andrew.R.Cress@intel.com, added scsi_rescan to + * automatically recognize hot-inserted disks */ /* @@ -818,6 +820,70 @@ return NULL; } +#ifdef CONFIG_SCSI_RESCAN +void scsi_rescan(struct Scsi_Host *SHpnt, unsigned int channel) +{ + Scsi_Device *SDpnt; + struct Scsi_Device_Template *sdtpnt; + int out_of_space = 0; + int new_dev = 0; + int fdidattach; + + /* + * Do scan_scsis here. This generates the Scsi_Devices entries. + * Since SHpnt->init_done, if devices already exist, skip them. + */ + scan_scsis(SHpnt, 0, channel, 0, 0); + + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + if (sdtpnt->init && sdtpnt->dev_noticed) + (*sdtpnt->init) (); + } + + /* Next we create the Scsi_Cmnd structures for new devices */ + for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { + fdidattach = 0; + if (SDpnt->host->host_no == SHpnt->host_no) { + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + /* + * attached can be set here for the new one, + * so also check if queue_depth has been + * set to a normal value yet (> 2). + */ + if (SDpnt->need_attach && sdtpnt->attach) { + /*Note /dev/sd* maj=8, /dev/sg* maj=21*/ + (*sdtpnt->attach) (SDpnt); + fdidattach = 1; + } /*endif need_attach*/ + } /*end sdtpnt loop*/ + if (fdidattach) { + fdidattach = 0; + new_dev++; + if (SHpnt->select_queue_depths != NULL) { + (SHpnt->select_queue_depths) (SHpnt, SHpnt->host_queue); + } + if (SDpnt->need_attach && SDpnt->attached) { + SDpnt->need_attach = FALSE; + scsi_build_commandblocks(SDpnt); + if (0 == SDpnt->has_cmdblocks) + out_of_space = 1; + } + } + } /*endif match host_no */ + } /*end SDpnt loop*/ + + /* May have added some devices, so resize the DMA pool. */ + if (new_dev > 0 && !out_of_space) scsi_resize_dma_pool(); + + for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { + if (sdtpnt->finish && sdtpnt->nr_dev) + (*sdtpnt->finish) (); + } + printk("scsi_rescan: %d new devices added\n",new_dev); + +} /*end scsi_rescan*/ +#endif + /* * Function: scsi_request_fn() * @@ -918,6 +984,19 @@ spin_lock_irq(&io_request_lock); continue; } + +#ifdef CONFIG_SCSI_RESCAN + if (!in_interrupt()) { + /* Check if we need to rescan after a reset. ARC*/ + if (SDpnt->host->need_scan == 1) { + SDpnt->host->need_scan = 2; + spin_unlock_irq(&io_request_lock); + scsi_rescan(SDpnt->host,SDpnt->channel); + spin_lock_irq(&io_request_lock); + SDpnt->host->need_scan = 0; + } + } +#endif } /* @@ -1175,6 +1254,11 @@ SDloop->was_reset = 1; SDloop->expecting_cc_ua = 1; } + } + if (SHpnt->init_done == 1 && SHpnt->need_scan == 0) { + SHpnt->need_scan = 1; + printk("scsi_report_bus_reset: scsi%d, channel %d need_scan\n", + SHpnt->host_no,channel); } } --- linux-2.4.18-orig/drivers/scsi/scsi_scan.c Mon Feb 25 14:38:04 2002 +++ linux-2.4.18/drivers/scsi/scsi_scan.c Wed Oct 2 12:06:20 2002 @@ -270,6 +270,28 @@ } /* + * scsi_dev_skip + * Returns 1 if there was already a device on this host at the same + * channel/dev/lun, indicating that the caller should skip this one. + * Make sure to not match the new/temp device created for the scan + * (sdnew). sdpnt->attached is often already set here on the new + * device(s), so we can't use that. + */ +static int +scsi_dev_skip(struct Scsi_Host *shpnt, uint channel, uint dev, uint lun, + Scsi_Device *sdnew) +{ + Scsi_Device *sdpnt; + for (sdpnt = shpnt->host_queue; sdpnt; sdpnt = sdpnt->next) + if (sdpnt != sdnew && (sdpnt->host == shpnt) && + (sdpnt->id == dev) && (sdpnt->lun == lun) && + (sdpnt->channel == channel)) { + return 1; + } + return 0; +} /*end scsi_dev_skip*/ + +/* * 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 / @@ -363,6 +385,8 @@ lun = hlun; if (lun >= shpnt->max_lun) goto leave; + if (shpnt->init_done && + scsi_dev_skip(shpnt,hchannel,hid,hlun,SDpnt)) goto leave; if ((0 == lun) || (lun > 7)) lun0_sl = SCSI_3; /* actually don't care for 0 == lun */ else @@ -385,6 +409,7 @@ for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) { if (sdtpnt->attach) { (*sdtpnt->attach) (oldSDpnt); + oldSDpnt->need_attach = FALSE; if (oldSDpnt->attached) { scsi_build_commandblocks(oldSDpnt); if (0 == oldSDpnt->has_cmdblocks) { @@ -428,6 +453,9 @@ /* don't probe further for luns > 7 for targets <= SCSI_2 */ if ((lun0_sl < SCSI_3) && (lun > 7)) break; + if (shpnt->init_done && + scsi_dev_skip(shpnt,channel,dev,lun, SDpnt)) + continue; /* ARC*/ if (!scan_scsis_single(channel, order_dev, lun, lun0_sl, &max_dev_lun, &sparse_lun, &SDpnt, shpnt, @@ -506,6 +534,10 @@ extern devfs_handle_t scsi_devfs_handle; int scsi_level; + if (SDpnt == NULL) { + printk("scan_scsis_single: SDpnt = NULL\n"); + return 0; + } SDpnt->host = shpnt; SDpnt->id = dev; SDpnt->lun = lun; @@ -537,7 +569,8 @@ * devices (and TEST_UNIT_READY to poll for media change). - Paul G. */ - SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n")); + SCSI_LOG_SCAN_BUS(3, printk("scsi_scan: [%d:%d:%d:%d] performing INQUIRY\n", + shpnt->host_no, channel, dev, lun)); /* * Build an INQUIRY command block. */ @@ -565,12 +598,19 @@ * for media change conditions here, so cannot require zero result. */ if (SRpnt->sr_result) { + int attn_ok = 0; 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[2] & 0xf) == UNIT_ATTENTION) { + if (SRpnt->sr_sense_buffer[12] == 0x28 && SRpnt->sr_sense_buffer[13] == 0) { /* not-ready to ready transition - good */ - } else { + attn_ok = 1; + } else if (SRpnt->sr_sense_buffer[12] == 0x29) { + /* 06/29/xx = reset occurred, but ok now - ARC */ + attn_ok = 1; + } + } + if (!attn_ok) { /* assume no peripheral if any other sort of error */ scsi_release_request(SRpnt); return 0; @@ -669,9 +709,12 @@ for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if (sdtpnt->detect) + if (sdtpnt->detect) { SDpnt->attached += (*sdtpnt->detect) (SDpnt); + /* did detect, but still need attach */ + SDpnt->need_attach = TRUE; + } SDpnt->scsi_level = scsi_result[2] & 0x07; if (SDpnt->scsi_level >= 2 || --- linux-2.4.18-orig/Documentation/Configure.help Mon Feb 25 14:37:51 2002 +++ linux-2.4.18/Documentation/Configure.help Wed Oct 2 14:14:17 2002 @@ -6771,6 +6771,13 @@ . The module will be called sg.o. If unsure, say N. +SCSI rescan on reset +CONFIG_SCSI_RESCAN + If you have an external SCSI disk enclosure that allows hot-insertion of + SCSI devices and does a SCSI bus reset when the hotplug occurs, say + Y here to allow the kernel to rescan the bus on which the reset + happens to attach any new devices that may have been inserted. + Probe all LUNs on each SCSI device CONFIG_SCSI_MULTI_LUN If you have a SCSI device that supports more than one LUN (Logical --- linux-2.4.18-orig/drivers/scsi/Config.in Mon Feb 25 14:38:04 2002 +++ linux-2.4.18/drivers/scsi/Config.in Wed Oct 2 14:08:38 2002 @@ -18,6 +18,8 @@ fi dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI +bool ' SCSI rescan on reset' CONFIG_SCSI_RESCAN $CONFIG_SCSI + comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' #if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then