From: Erik Andersen <andersen@codepoet.org>
To: James Bottomley <James.Bottomley@steeleye.com>,
linux-scsi@vger.kernel.org
Subject: Re: [PATCH] SCSI hotplug support
Date: Fri, 18 Oct 2002 05:28:14 -0600 [thread overview]
Message-ID: <20021018112814.GA32693@codepoet.org> (raw)
In-Reply-To: <20021016024016.GB4690@redhat.com>
On Tue Oct 15, 2002 at 10:40:16PM -0400, Doug Ledford wrote:
> middle of an interrupt or not). In this case though, it's pretty easy to
> tell it isn't interrupt context. That's fine. However, you still haven't
> tested the scenario I mentioned at the start of this particular part of
> the debate. If you plug in one drive, then plug in another, does the
> second one get added? Possible way to test this without having separate
> drives: load the sbp2 module *before* hotplugging your disks and see what
> happens.
I have several firewire drives so testing this is not a
problem... The answer is yes it is added. With my latest patch
applied to the kernel, I had 4 drives plugged into my 1394 card
(my 1394 RAID box) when I loaded the sbp2 module. All 4
coldplugged drives showed up in /proc/scsi/scsi. I then plugged
in another drive, at which point all 5 drives showed up under
/proc/scsi/scsi as expected.
I made an update of my patch. I have not attempted to convert
the 1394 hotplug driver to echo stuff into /proc/scsi/scsi.
However, this patch attempts to close the longstanding race
conditions inherent in add-single-device and remove-single-device
by using the BKL, and adds some better function docs. I didn't
see any other locks in the scsi code that looked sufficient to
handle the races, so please correct me if there is a better
way... This also fixes a stupid bug in the sbp2 part of my
previous patch that would cause coldplugged sbp2 devices to be
also hotplugged, causing them to be double registered with the
SCSI subsystem.
-Erik
--
Erik B. Andersen http://codepoet-consulting.com/
--This message was written using 73% post-consumer electrons--
--- linux-2.4.19/drivers/scsi/scsi_syms.c 2002-08-02 19:39:44.000000000 -0500
+++ linux-2.4.20-pre10-erik/drivers/scsi/scsi_syms.c 2002-10-09 16:41:01.000000000 -0500
@@ -103,3 +103,9 @@
extern int scsi_delete_timer(Scsi_Cmnd *);
EXPORT_SYMBOL(scsi_add_timer);
EXPORT_SYMBOL(scsi_delete_timer);
+
+/* Support for hot plugging and unplugging devices -- safe for
+ * ieee1394 or USB devices, but probably not for normal SCSI... */
+EXPORT_SYMBOL(scsi_add_single_device);
+EXPORT_SYMBOL(scsi_remove_single_device);
+
--- linux-2.4.19/drivers/scsi/hosts.h 2002-10-18 05:16:17.000000000 -0500
+++ linux-2.4.20-pre10-erik/drivers/scsi/hosts.h 2002-10-09 17:00:13.000000000 -0500
@@ -532,6 +532,13 @@
int scsi_register_device(struct Scsi_Device_Template * sdpnt);
void scsi_deregister_device(struct Scsi_Device_Template * tpnt);
+/* Support for hot plugging and unplugging devices -- safe for
+ * ieee1394 or USB devices, but probably not for normal SCSI... */
+extern int scsi_add_single_device(struct Scsi_Host *shpnt,
+ int channel, int id, int lun);
+extern int scsi_remove_single_device(struct Scsi_Host *shpnt,
+ int channel, int id, int lun);
+
/* These are used by loadable modules */
extern int scsi_register_module(int, void *);
extern int scsi_unregister_module(int, void *);
--- linux-2.4.19/drivers/scsi/scsi.c 2002-10-18 05:16:17.000000000 -0500
+++ linux-2.4.20-pre10-erik/drivers/scsi/scsi.c 2002-10-17 21:12:48.000000000 -0500
@@ -1553,6 +1553,165 @@
}
}
+
+/*
+ * Function: scsi_add_single_device()
+ *
+ * Purpose: Support for hotplugging SCSI devices. This function
+ * implements the actual functionality for
+ * echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
+ *
+ * Arguments: shpnt - pointer to the SCSI host structure
+ * channel - channel of the device to add
+ * id - id of the device to add
+ * lun - lun of the device to add
+ *
+ * Returns: 0 on success or an error code
+ *
+ * Lock status: None needed. However we do grab the BKL to avoid racing with
+ * scsi_register*(), scsi_unregister*(), scsi_remove_single_device()
+ * and anything else that might be messing with with the Scsi_Host or
+ * other fundamental data structures.
+ *
+ * Notes: This feature is probably unsafe for standard SCSI devices,
+ * but is perfectly normal for things like ieee1394 or USB
+ * drives since these busses are designed for hotplugging.
+ * Use at your own risk....
+ */
+int scsi_add_single_device(struct Scsi_Host *shpnt, int channel,
+ int id, int lun)
+{
+ Scsi_Device *scd;
+
+ /* Do a bit of sanity checking */
+ if (shpnt==NULL) {
+ return -ENXIO;
+ }
+
+ /* get the big kernel lock to avoid racing with
+ * scsi_register*(), scsi_unregister*(), scsi_remove_single_device()
+ * or anything else that might be messing with with the Scsi_Host or
+ * other fundamental data structures. */
+ lock_kernel();
+
+ /* Check if they asked us to add an already existing device.
+ * If so, ignore their misguided efforts. */
+ for (scd = shpnt->host_queue; scd; scd = scd->next) {
+ if ((scd->channel == channel && scd->id == id && scd->lun == lun)) {
+ break;
+ }
+ }
+ if (scd) {
+ unlock_kernel();
+ return -ENOSYS;
+ }
+
+ /* We have the BKL, so we should be safe while we muck
+ * about with Scsi_Device internals. */
+ scan_scsis(shpnt, 1, channel, id, lun);
+ unlock_kernel();
+ return 0;
+}
+
+/* Support for plugging/unplugging SCSI devices. This feature is
+ * probably unsafe for standard SCSI devices, but is perfectly
+ * normal for things like ieee1394 or USB drives since these
+ * busses are designed for hotplugging. Use at your own risk.... */
+/*
+ * Function: scsi_remove_single_device()
+ *
+ * Purpose: Support for hot-unplugging SCSI devices. This function
+ * implements the actual functionality for
+ * echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
+ *
+ * Arguments: shpnt - pointer to the SCSI host structure
+ * channel - channel of the device to add
+ * id - id of the device to add
+ * lun - lun of the device to add
+ *
+ * Returns: 0 on success or an error code
+ *
+ * Lock status: None needed. However we do grab the BKL to avoid racing with
+ * scsi_register*(), scsi_unregister*(), scsi_add_single_device()
+ * and anything else that might be messing with with the Scsi_Host or
+ * other fundamental data structures.
+ *
+ * Notes: This feature is probably unsafe for standard SCSI devices,
+ * but is perfectly normal for things like ieee1394 or USB
+ * drives since these busses are designed for hotplugging.
+ * Use at your own risk....
+ */
+int scsi_remove_single_device(struct Scsi_Host *shpnt, int channel,
+ int id, int lun)
+{
+ Scsi_Device *scd;
+ struct Scsi_Device_Template *SDTpnt;
+
+ /* Do a bit of sanity checking */
+ if (shpnt==NULL) {
+ return -ENODEV;
+ }
+
+ /* get the big kernel lock to avoid racing with
+ * scsi_register*(), scsi_unregister*(), scsi_add_single_device()
+ * or anything else that might be messing with with the Scsi_Host or
+ * other fundamental data structures. */
+ lock_kernel();
+
+ /* Make sure the specified device is in fact present */
+ for (scd = shpnt->host_queue; scd; scd = scd->next) {
+ if ((scd->channel == channel && scd->id == id && scd->lun == lun)) {
+ break;
+ }
+ }
+ if (scd==NULL) {
+ unlock_kernel();
+ return -ENODEV;
+ }
+
+ /* See if the specified device is busy. We have the BKL, so we
+ * should not race with sd_open(), sd_release() and similar that
+ * increment access_count */
+ if (scd->access_count) {
+ unlock_kernel();
+ return -EBUSY;
+ }
+
+ SDTpnt = scsi_devicelist;
+ while (SDTpnt != NULL) {
+ if (SDTpnt->detach)
+ (*SDTpnt->detach) (scd);
+ SDTpnt = SDTpnt->next;
+ }
+
+ /* We have the BKL, so we should be safe while we muck
+ * about with Scsi_Device internals. */
+ if (scd->attached == 0) {
+ /* Nobody is using this device, so we
+ * can now free all command structures. */
+ if (shpnt->hostt->revoke)
+ shpnt->hostt->revoke(scd);
+ devfs_unregister (scd->de);
+ scsi_release_commandblocks(scd);
+
+ /* Now we can remove the device structure */
+ if (scd->next != NULL)
+ scd->next->prev = scd->prev;
+
+ if (scd->prev != NULL)
+ scd->prev->next = scd->next;
+
+ if (shpnt->host_queue == scd) {
+ shpnt->host_queue = scd->next;
+ }
+ blk_cleanup_queue(&scd->request_queue);
+ kfree((char *) scd);
+ }
+
+ unlock_kernel();
+ return 0;
+}
+
#ifdef CONFIG_PROC_FS
static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
{
@@ -1605,8 +1764,6 @@
static int proc_scsi_gen_write(struct file * file, const char * buf,
unsigned long length, void *data)
{
- struct Scsi_Device_Template *SDTpnt;
- Scsi_Device *scd;
struct Scsi_Host *HBA_ptr;
char *p;
int host, channel, id, lun;
@@ -1721,13 +1878,12 @@
/*
* Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
* with "0 1 2 3" replaced by your "Host Channel Id Lun".
- * Consider this feature BETA.
+ *
+ * Consider this feature pre-BETA.
+ *
* CAUTION: This is not for hotplugging your peripherals. As
* SCSI was not designed for this you could damage your
- * hardware !
- * However perhaps it is legal to switch on an
- * already connected device. It is perhaps not
- * guaranteed this device doesn't corrupt an ongoing data transfer.
+ * hardware and thoroughly confuse the SCSI subsystem.
*/
if (!strncmp("add-single-device", buffer + 5, 17)) {
p = buffer + 23;
@@ -1745,33 +1901,11 @@
break;
}
}
- err = -ENXIO;
- if (!HBA_ptr)
- goto out;
-
- for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
- if ((scd->channel == channel
- && scd->id == id
- && scd->lun == lun)) {
- break;
- }
- }
-
- err = -ENOSYS;
- if (scd)
- goto out; /* We do not yet support unplugging */
-
- scan_scsis(HBA_ptr, 1, channel, id, lun);
-
- /* FIXME (DB) This assumes that the queue_depth routines can be used
- in this context as well, while they were all designed to be
- called only once after the detect routine. (DB) */
- /* queue_depth routine moved to inside scan_scsis(,1,,,) so
- it is called before build_commandblocks() */
-
- err = length;
+ if ((err=scsi_add_single_device(HBA_ptr, channel, id, lun))==0)
+ err = length;
goto out;
}
+
/*
* Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
* with "0 1 2 3" replaced by your "Host Channel Id Lun".
@@ -1781,7 +1915,6 @@
* CAUTION: This is not for hotplugging your peripherals. As
* SCSI was not designed for this you could damage your
* hardware and thoroughly confuse the SCSI subsystem.
- *
*/
else if (!strncmp("remove-single-device", buffer + 5, 20)) {
p = buffer + 26;
@@ -1797,58 +1930,8 @@
break;
}
}
- err = -ENODEV;
- if (!HBA_ptr)
- goto out;
-
- for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
- if ((scd->channel == channel
- && scd->id == id
- && scd->lun == lun)) {
- break;
- }
- }
-
- if (scd == NULL)
- goto out; /* there is no such device attached */
-
- err = -EBUSY;
- if (scd->access_count)
- goto out;
-
- SDTpnt = scsi_devicelist;
- while (SDTpnt != NULL) {
- if (SDTpnt->detach)
- (*SDTpnt->detach) (scd);
- SDTpnt = SDTpnt->next;
- }
-
- if (scd->attached == 0) {
- /*
- * Nobody is using this device any more.
- * Free all of the command structures.
- */
- if (HBA_ptr->hostt->revoke)
- HBA_ptr->hostt->revoke(scd);
- devfs_unregister (scd->de);
- scsi_release_commandblocks(scd);
-
- /* Now we can remove the device structure */
- if (scd->next != NULL)
- scd->next->prev = scd->prev;
-
- if (scd->prev != NULL)
- scd->prev->next = scd->next;
-
- if (HBA_ptr->host_queue == scd) {
- HBA_ptr->host_queue = scd->next;
- }
- blk_cleanup_queue(&scd->request_queue);
- kfree((char *) scd);
- } else {
- goto out;
- }
- err = 0;
+ err=scsi_remove_single_device(HBA_ptr, channel, id, lun);
+ goto out;
}
out:
--- linux-2.4.19/drivers/ieee1394/sbp2.c 2002-10-18 05:16:14.000000000 -0500
+++ linux-2.4.20-pre10-erik/drivers/ieee1394/sbp2.c 2002-10-18 05:29:20.000000000 -0500
@@ -562,6 +562,8 @@
.update = sbp2_update
};
+static int sbp2_init_has_finished_initializing;
+
/* List of device firmware's that require a forced 36 byte inquiry. */
static u32 sbp2_broken_inquiry_list[] = {
0x00002800, /* Stefan Richter <richtest@bauwesen.tu-cottbus.de> */
@@ -1082,6 +1084,8 @@
hpsb_register_protocol(&sbp2_driver);
+ sbp2_init_has_finished_initializing++;
+
return 0;
}
@@ -1681,6 +1685,23 @@
SBP2_INFO("Logged into SBP-2 device");
+ /* Try to hook ourselves into the SCSI subsystem, but only if
+ * sbp2_init has finished doing its thing. If we register
+ * anything while sbp2_init is handling coldplugged devices, we
+ * will will end up double registering things (a bad idea). */
+ if (sbp2_init_has_finished_initializing) {
+ struct Scsi_Host *HBA_ptr;
+ HBA_ptr=hi->scsi_host;
+ if (HBA_ptr==NULL) {
+ return 0;
+ }
+ if (scsi_add_single_device(HBA_ptr, 0, scsi_id->id, 0)==0) {
+ SBP2_DEBUG("connecting SBP-2 device into the SCSI subsystem");
+ } else {
+ SBP2_INFO("Unable to connect SBP-2 device into the SCSI subsystem");
+ }
+ }
+
return(0);
}
@@ -1739,8 +1760,23 @@
SBP2_INFO("Logged out of SBP-2 device");
- return(0);
+ /* Now that we are logged out of the SBP-2 device, lets
+ * try to un-hook ourselves from the SCSI subsystem */
+ {
+ struct Scsi_Host *HBA_ptr;
+
+ HBA_ptr=hi->scsi_host;
+ if (HBA_ptr==NULL) {
+ return 0;
+ }
+ if (scsi_remove_single_device(HBA_ptr, 0, scsi_id->id, 0)==0) {
+ SBP2_DEBUG("disconnecting SBP-2 device from the SCSI subsystem");
+ } else {
+ SBP2_INFO("Unable to disconnect SBP-2 device from the SCSI subsystem");
+ }
+ }
+ return(0);
}
/*
next prev parent reply other threads:[~2002-10-18 11:28 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-10-14 5:40 [PATCH] SCSI hotplug support Erik Andersen
2002-10-14 7:06 ` Matthew Dharm
2002-10-14 7:12 ` Erik Andersen
2002-10-14 15:47 ` Kurt Garloff
2002-10-14 16:19 ` Mike Anderson
2002-10-14 20:41 ` Erik Andersen
2002-10-14 22:10 ` Mike Anderson
2002-10-14 20:46 ` Erik Andersen
2002-10-14 15:57 ` James Bottomley
2002-10-14 17:22 ` Mike Anderson
2002-10-14 17:30 ` Matthew Dharm
2002-10-14 17:39 ` James Bottomley
2002-10-14 19:11 ` Oliver Xymoron
2002-10-15 0:42 ` Kurt Garloff
2002-10-14 20:37 ` Erik Andersen
2002-10-14 21:07 ` James Bottomley
2002-10-14 21:54 ` Erik Andersen
2002-10-14 22:25 ` Doug Ledford
2002-10-15 5:25 ` Erik Andersen
2002-10-15 15:33 ` Doug Ledford
2002-10-15 18:18 ` Erik Andersen
2002-10-15 18:22 ` Doug Ledford
2002-10-15 18:45 ` Erik Andersen
2002-10-15 19:13 ` Doug Ledford
2002-10-15 19:32 ` Erik Andersen
2002-10-15 19:45 ` James Bottomley
2002-10-15 19:50 ` Scott Merritt
2002-10-15 19:55 ` Doug Ledford
2002-10-15 22:07 ` Erik Andersen
2002-10-16 2:40 ` Doug Ledford
2002-10-18 11:28 ` Erik Andersen [this message]
2002-10-15 21:43 ` Oliver Neukum
2002-10-15 22:07 ` Erik Andersen
2002-10-14 22:19 ` Oliver Neukum
2002-10-15 0:22 ` Doug Ledford
2002-10-15 7:53 ` Oliver Neukum
2002-10-15 14:35 ` Doug Ledford
2002-10-15 15:19 ` Oliver Neukum
2002-10-15 15:40 ` James Bottomley
2002-10-15 17:47 ` Erik Andersen
2002-10-15 18:34 ` Doug Ledford
2002-10-15 18:22 ` Scott Merritt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20021018112814.GA32693@codepoet.org \
--to=andersen@codepoet.org \
--cc=James.Bottomley@steeleye.com \
--cc=linux-scsi@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.