Subject: Re: detaching SCSI devices
To: Jason Thorpe <thorpej@nas.nasa.gov>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: tech-kern
Date: 07/08/1999 18:38:56
>> We have the ability to attach new SCSI devices, via scsictl's "scan"
>> bus command.  [...detach...]

> Send me a copy please.

Under separate cover.  (This message is going to tech-kern too.)

> This is on my todo list to do in a generic fashion, but I'd like to
> see how you implemented it :-)

"scsictl /dev/scsibus0 detach 2 0", eg.  I had to do it as a scsibus
command rather than a device command because to do it as a device
command you have to detach a device even though it's open, which (while
probably possible - delay the detach until last close?) was more hair
than I wanted to get into.  Initially I just did the detach anyway, but
that crashed when closing the device (not surprising, since the
scsipi_link had been freed).  Now, you can't detach a device that's
open, and since that makes it useless as a device command, it's a
bus-only thing.

As for how, well, it's pretty simple unless I missed something.  The
meat of it is in scsiconf.c.  It does occur to me that config_detach
should take more care with FSTATE_STAR devices; it should be possible
to free up more than just the last-used unit, so that if you have
sd0-sd5 and dettach (in order) sd3, sd4, sd5, then it reclaims all
three units.  Doing this right would be a little interesting, but
shouldn't be too bad....

Anyhow, here's the scsiconf.c stuff.  Jason, I'll mail you a patch kit
corresponding to my current draft state separately.

--- OLD/sys/dev/scsipi/scsiconf.c	Thu Jan  1 00:00:00 1970
+++ NEW/sys/dev/scsipi/scsiconf.c	Thu Jan  1 00:00:00 1970
@@ -89,6 +89,7 @@
  */
 int scsi_probedev __P((struct scsibus_softc *, int, int));
 int scsi_probe_bus __P((int bus, int target, int lun));
+int scsi_detach_device __P((int bus, int target, int lun));
 
 struct scsipi_device probe_switch = {
 	NULL,
@@ -744,6 +745,58 @@
 	return (docontinue);
 }
 
+/*
+ * (Try to) detach a device from its scsibus.
+ * All three numbers must be specified; no wildcards here!
+ *
+ * ENXIO if it ain't there
+ * EIO for attempts to detach the adapter itself
+ */
+int
+scsi_detach_device(bus, target, lun)
+	int bus, target, lun;
+{
+	struct scsibus_softc *scsi;
+	struct scsipi_link *link;
+	int err;
+
+	/* Check the bus number, get the softc */
+	if ((bus < 0) || (bus >= scsibus_cd.cd_ndevs))
+		return(ENXIO);
+	scsi = scsibus_cd.cd_devs[bus];
+	if (scsi == 0)
+		return(ENXIO);
+
+	/* Basic sanity check */
+	if ((target < 0) || (lun < 0))
+		return(ENXIO);
+
+	/* Can't detach the adapter! */
+	if (target == scsi->adapter_link->scsipi_scsi.adapter_target)
+		return(EIO);
+
+	/* Target ID/LUN in range? */
+	if ((target > scsi->sc_maxtarget) || (lun > scsi->sc_maxlun))
+		return(ENXIO);
+
+	/* Get the link, make sure there's something there */
+	link = scsi->sc_link[target][lun];
+	if (link == 0)
+		return(ENXIO);
+
+	/* Try to do the detach */
+	err = config_detach(link->device_softc,0);
+	if (err)
+		return(err);
+
+	/* Clear the bus's pointer, and free */
+	scsi->sc_link[target][lun] = 0;
+	free(link,M_DEVBUF);
+
+	/* Done; return success */
+	return(0);
+}
+
 /****** Entry points for user control of the SCSI bus. ******/
 
 int
@@ -805,6 +858,7 @@
 	switch (cmd) {
 	case SCBUSIOSCAN:
 	case SCBUSIORESET:
+	case SCBUSIODETACH:
 		if ((flag & FWRITE) == 0)
 			return (EBADF);
 	}
@@ -818,6 +872,15 @@
 		/* XXX Change interface to this function. */
 		error = scsi_probe_busses(minor(dev), a->sa_target,
 		    a->sa_lun);
+		break;
+	    }
+
+	case SCBUSIODETACH:
+	    {
+		struct scbusiodetach_args *a =
+		    (struct scbusiodetach_args *)addr;
+
+		error = scsi_detach_device(minor(dev),a->sa_target,a->sa_lun);
 		break;
 	    }
 

The rest are frills (for example, I had to tweak sd_scsi.c to have a
detach function; ideally all the _scsi attachments should have one).

					der Mouse

			       mouse@rodents.montreal.qc.ca
		     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B