Messages in this thread Patch in this message | | | Date | Wed, 15 Dec 2004 01:24:53 -0600 | From | Matt Domsch <> | Subject | Re: How to add/drop SCSI drives from within the driver? |
| |
On Wed, Dec 08, 2004 at 02:01:21PM -0600, James Bottomley wrote: > On Wed, 2004-12-08 at 13:42 -0500, Salyzyn, Mark wrote: > > James Bottomley writes: > > >The real way I'd like to handle this is via hotplug. The hotplug event > > >would transmit the HCTL in the environment. Whether the drive actually > > >gets incorporated into the system and where is user policy, so it's > > >appropriate that it should be in userland. > > Hotplug is the standard way of handling configuration changes (whether > requested or forced). There's value to handling things in a standard > manner. If the current implementation needs improving, then you're free > to do it (and it would benefit far more than just SCSI...). > > So the firmware calls the SCSI API which triggers the hotplug event and > adds the device ... there's no problem.
James, I've been thinking about this a little more, and you may be on to something here. Let each driver add files as such:
/sys/class/scsi_host |-- host0 | |-- add_logical_drive | |-- remove_logical_drive | `-- rescan_logical_drive
Then we can go 2 ways with this. 1) driver functions directly call scsi_add_device(), scsi_remove_device(), and something for rescan (option 2 handles this one cleanly for us). ATM, megaraid_mbox doesn't implement a rescan function, so this point may be moot.
2) driver functions call a midlayer library function, which invokes /sbin/hotplug with appropriate data, and add a new /etc/hotplug.d helper app which would then write to these files:
/sys/class/scsi_host |-- host0 | |-- scan /sys/devices/pci0000:0x/0000:0x:0x.0/host0 |-- 0:0:0:0 | |-- delete | |-- rescan
to do likewise.
Patch below against scsi-misc-2.6, as a proof of concept for option 1 above, option 2 would take a little more time to do and get right, but I want to get feedback as to direction before digging further.
Thanks, Matt
-- Matt Domsch Sr. Software Engineer, Lead Engineer Dell Linux Solutions linux.dell.com & www.dell.com/linux Linux on Dell mailing lists @ http://lists.us.dell.com
===== drivers/scsi/megaraid/megaraid_mbox.c 1.11 vs edited ===== --- 1.11/drivers/scsi/megaraid/megaraid_mbox.c 2004-11-18 16:12:10 -06:00 +++ edited/drivers/scsi/megaraid/megaraid_mbox.c 2004-12-15 01:18:19 -06:00 @@ -455,6 +455,133 @@ static struct pci_driver megaraid_pci_dr /* + * sysfs class device support + * creates three files: + * /sys/class/scsi_host + * |-- host0 + * | |-- add_logical_drive + * | |-- remove_logical_drive + * | `-- rescan_logical_drive + * + * These make the midlayer invoke /sbin/hotplug, which then calls back into sysfs + * /sys/class/scsi_host + * |-- host0 + * | |-- scan + * + * and + * + * /sys/devices/pci0000:0x/0000:0x:0x.0/host0 + * |-- 0:0:0:0 + * | |-- delete + * | |-- rescan + * + * respectively. This allows userspace applications to work + * using their logical drive number, and lets the driver translate + * that into host, channel, id, and lun values which the other + * mechanisms require. This is similar to how hot plug CPU works. + */ + +/** + * lda_to_hcil() + * @adapter + * @lda - logical drive address + * @host_no + * @channel + * @id + * @lun + * + * converts a logical drive address into a host, channel id, lun tuple. + */ + +static inline int megaraid_lda_to_hcil(struct Scsi_Host *shost, u32 lda, + u32 *host_no, u32 *channel, u32 *id, u32 *lun) +{ + if (lda > MAX_LOGICAL_DRIVES_40LD) + return -EINVAL; + *host_no = shost->host_no; + *channel = shost->max_channel; + *id = (lda < shost->this_id) ? lda : lda + 1; + *lun = 0; + return 0; +} + +enum megaraid_host_action { + LD_ADD = 1, + LD_REMOVE = 2, + LD_RESCAN = 3, +}; + +static int megaraid_host_store(struct class_device *class_dev, const char *buf, size_t count, int action) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct scsi_device *sdev; + int fields=0, rc=-EINVAL; + u32 lda=0, host_no=0, channel=0, id=0, lun=0; + fields = sscanf(buf, "%u", &lda); + if (fields != 1) + return rc; + if (lda > MAX_LOGICAL_DRIVES_40LD) + return rc; + rc = megaraid_lda_to_hcil(shost, lda, &host_no, &channel, &id, &lun); + if (rc) + return rc; + + /* + * This is where the call-out to /sbin/hotplug would go. + * for now, short-circuit that and just call the necessary + * functions directly. + */ + rc = -EINVAL; + switch (action) { + case LD_ADD: + scsi_add_device(shost, channel, id, lun); + break; + case LD_REMOVE: + sdev = scsi_device_lookup(shost, channel, id, lun); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + return -EINVAL; + } + break; + case LD_RESCAN: + return -ENOSYS; + default: + return -EINVAL; + } + return count; +} + +static ssize_t megaraid_host_store_add_ld(struct class_device *class_dev, const char *buf, size_t count) +{ + return megaraid_host_store(class_dev, buf, count, LD_ADD); +} +static ssize_t megaraid_host_store_remove_ld(struct class_device *class_dev, const char *buf, size_t count) +{ + return megaraid_host_store(class_dev, buf, count, LD_REMOVE); +} +static ssize_t megaraid_host_store_rescan_ld(struct class_device *class_dev, const char *buf, size_t count) +{ + return megaraid_host_store(class_dev, buf, count, LD_RESCAN); +} + + +#define MEGARAID_HOST_WOATTR(_name,_store) \ +CLASS_DEVICE_ATTR(_name, S_IWUSR|S_IWGRP, NULL, _store) + +static MEGARAID_HOST_WOATTR(add_logical_drive, megaraid_host_store_add_ld); +static MEGARAID_HOST_WOATTR(remove_logical_drive, megaraid_host_store_remove_ld); +static MEGARAID_HOST_WOATTR(rescan_logical_drive, megaraid_host_store_rescan_ld); + +/* Host attributes initializer */ +static struct class_device_attribute *megaraid_host_attrs[] = { + &class_device_attr_add_logical_drive, + &class_device_attr_remove_logical_drive, + &class_device_attr_rescan_logical_drive, + NULL, +}; + +/* * Scsi host template for megaraid unified driver */ static struct scsi_host_template megaraid_template_g = { @@ -467,6 +594,7 @@ static struct scsi_host_template megarai .eh_bus_reset_handler = megaraid_reset_handler, .eh_host_reset_handler = megaraid_reset_handler, .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = megaraid_host_attrs, }; - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |