* [PATCH] add sysfs attributes to scan and delete scsi_devices
@ 2003-07-08 20:40 Patrick Mansfield
2003-07-08 20:41 ` examples using " Patrick Mansfield
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Patrick Mansfield @ 2003-07-08 20:40 UTC (permalink / raw)
To: linux-scsi, James Bottomley
This patch against recent 2.5 bk adds a sysfs attribute to allow scanning
(or rescanning) and deletion of scsi_devices.
It also allows scanning of entire hosts, channels, or targets.
diff -purN -X /home/patman/dontdiff bleed-2.5/drivers/scsi/scsi_priv.h scan-del-attr-bl-2.5/drivers/scsi/scsi_priv.h
--- bleed-2.5/drivers/scsi/scsi_priv.h Wed Jul 2 13:40:54 2003
+++ scan-del-attr-bl-2.5/drivers/scsi/scsi_priv.h Mon Jul 7 12:45:29 2003
@@ -107,6 +107,8 @@ extern void scsi_forget_host(struct Scsi
extern void scsi_free_sdev(struct scsi_device *);
extern void scsi_free_shost(struct Scsi_Host *);
extern void scsi_rescan_device(struct device *);
+extern int scsi_scan(const char *);
+extern int scsi_remove(const char *);
/* scsi_sysfs.c */
extern int scsi_device_register(struct scsi_device *);
diff -purN -X /home/patman/dontdiff bleed-2.5/drivers/scsi/scsi_scan.c scan-del-attr-bl-2.5/drivers/scsi/scsi_scan.c
--- bleed-2.5/drivers/scsi/scsi_scan.c Mon Jul 7 11:10:22 2003
+++ scan-del-attr-bl-2.5/drivers/scsi/scsi_scan.c Mon Jul 7 12:45:29 2003
@@ -49,6 +49,12 @@
#define SCSI_UID_UNKNOWN 'Z'
/*
+ * Special value for scanning to specify scanning or rescanning of all
+ * possible channels, (target) ids, or luns on a given host.
+ */
+#define SCAN_WILD_CARD ~0
+
+/*
* Return values of some of the scanning functions.
*
* SCSI_SCAN_NO_RESPONSE: no valid response received from the target, this
@@ -679,13 +685,32 @@ static int scsi_add_lun(struct scsi_devi
**/
static int scsi_probe_and_add_lun(struct Scsi_Host *host,
uint channel, uint id, uint lun, int *bflagsp,
- struct scsi_device **sdevp)
+ struct scsi_device **sdevp, int rescan)
{
struct scsi_device *sdev;
struct scsi_request *sreq;
unsigned char *result;
int bflags, res = SCSI_SCAN_NO_RESPONSE;
+ /*
+ * The rescan flag is used as an optimization, the first scan of a
+ * host adapter calls into here with rescan == 0.
+ */
+ if (rescan) {
+ sdev = scsi_find_device(host, channel, id, lun);
+ if (sdev) {
+ SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
+ "scsi scan: device exists on <%d:%d:%d:%d>\n",
+ host->host_no, channel, id, lun));
+ if (sdevp)
+ *sdevp = sdev;
+ if (bflagsp)
+ *bflagsp = scsi_get_device_flags(sdev->vendor,
+ sdev->model);
+ return SCSI_SCAN_LUN_PRESENT;
+ }
+ }
+
sdev = scsi_alloc_sdev(host, channel, id, lun);
if (!sdev)
goto out;
@@ -760,7 +785,7 @@ static int scsi_probe_and_add_lun(struct
* Modifies sdevscan->lun.
**/
static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel,
- uint id, int bflags, int lun0_res, int scsi_level)
+ uint id, int bflags, int lun0_res, int scsi_level, int rescan)
{
unsigned int sparse_lun, lun, max_dev_lun;
@@ -829,7 +854,8 @@ static void scsi_sequential_lun_scan(str
*/
for (lun = 1; lun < max_dev_lun; ++lun)
if ((scsi_probe_and_add_lun(shost, channel, id, lun,
- NULL, NULL) != SCSI_SCAN_LUN_PRESENT) && !sparse_lun)
+ NULL, NULL, rescan) != SCSI_SCAN_LUN_PRESENT) &&
+ !sparse_lun)
return;
}
@@ -880,7 +906,8 @@ static int scsilun_to_int(struct scsi_lu
* 0: scan completed (or no memory, so further scanning is futile)
* 1: no report lun scan, or not configured
**/
-static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
+static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
+ int rescan)
{
char devname[64];
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -1034,7 +1061,7 @@ static int scsi_report_lun_scan(struct s
int res;
res = scsi_probe_and_add_lun(sdev->host, sdev->channel,
- sdev->id, lun, NULL, NULL);
+ sdev->id, lun, NULL, NULL, rescan);
if (res == SCSI_SCAN_NO_RESPONSE) {
/*
* Got some results, but now none, abort.
@@ -1060,7 +1087,7 @@ static int scsi_report_lun_scan(struct s
return 0;
}
#else
-# define scsi_report_lun_scan(sdev, blags) (1)
+# define scsi_report_lun_scan(sdev, blags, rescan) (1)
#endif /* CONFIG_SCSI_REPORT_LUNS */
struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
@@ -1069,7 +1096,11 @@ struct scsi_device *scsi_add_device(stru
struct scsi_device *sdev;
int res;
- res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev);
+ /*
+ * Caller already checked if sdev exists, but be paranoid and call
+ * with rescan of 1.
+ */
+ res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev, 1);
if (res != SCSI_SCAN_LUN_PRESENT)
sdev = ERR_PTR(-ENODEV);
return sdev;
@@ -1112,7 +1143,7 @@ void scsi_rescan_device(struct device *d
* sequential scan of LUNs on the target id.
**/
static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
- unsigned int id)
+ unsigned int id, unsigned int lun, int rescan)
{
int bflags = 0;
int res;
@@ -1124,19 +1155,29 @@ static void scsi_scan_target(struct Scsi
*/
return;
+ if (lun != SCAN_WILD_CARD) {
+ /*
+ * Scan for a specific host/chan/id/lun.
+ */
+ scsi_probe_and_add_lun(shost, channel, id, lun, NULL, NULL,
+ rescan);
+ return;
+ }
+
/*
* Scan LUN 0, if there is some response, scan further. Ideally, we
* would not configure LUN 0 until all LUNs are scanned.
*/
- res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev);
+ res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev,
+ rescan);
if (res == SCSI_SCAN_LUN_PRESENT) {
- if (scsi_report_lun_scan(sdev, bflags) != 0)
+ if (scsi_report_lun_scan(sdev, bflags, rescan) != 0)
/*
* The REPORT LUN did not scan the target,
* do a sequential scan.
*/
scsi_sequential_lun_scan(shost, channel, id, bflags,
- res, sdev->scsi_level);
+ res, sdev->scsi_level, rescan);
} else if (res == SCSI_SCAN_TARGET_PRESENT) {
/*
* There's a target here, but lun 0 is offline so we
@@ -1145,37 +1186,26 @@ static void scsi_scan_target(struct Scsi
* a default scsi level of SCSI_2
*/
scsi_sequential_lun_scan(shost, channel, id, BLIST_SPARSELUN,
- SCSI_SCAN_TARGET_PRESENT, SCSI_2);
+ SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan);
}
}
-/**
- * scsi_scan_host - scan the given adapter
- * @shost: adapter to scan
- *
- * Description:
- * Iterate and call scsi_scan_target to scan all possible target id's
- * on all possible channels.
- **/
-void scsi_scan_host(struct Scsi_Host *shost)
+static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
+ unsigned int id, unsigned int lun, int rescan)
{
- uint channel, id, order_id;
+ uint order_id;
- /*
- * The sdevscan host, channel, id and lun are filled in as
- * needed to scan.
- */
- for (channel = 0; channel <= shost->max_channel; channel++) {
- /*
- * XXX adapter drivers when possible (FCP, iSCSI)
- * could modify max_id to match the current max,
- * not the absolute max.
- *
- * XXX add a shost id iterator, so for example,
- * the FC ID can be the same as a target id
- * without a huge overhead of sparse id's.
- */
+ if (id == SCAN_WILD_CARD)
for (id = 0; id < shost->max_id; ++id) {
+ /*
+ * XXX adapter drivers when possible (FCP, iSCSI)
+ * could modify max_id to match the current max,
+ * not the absolute max.
+ *
+ * XXX add a shost id iterator, so for example,
+ * the FC ID can be the same as a target id
+ * without a huge overhead of sparse id's.
+ */
if (shost->reverse_ordering)
/*
* Scan from high to low id.
@@ -1183,9 +1213,155 @@ void scsi_scan_host(struct Scsi_Host *sh
order_id = shost->max_id - id - 1;
else
order_id = id;
- scsi_scan_target(shost, channel, order_id);
+ scsi_scan_target(shost, channel, order_id, lun, rescan);
}
+ else
+ scsi_scan_target(shost, channel, id, lun, rescan);
+}
+
+static int scsi_scan_host_selected(struct Scsi_Host *shost,
+ unsigned int channel, unsigned int id,
+ unsigned int lun, int rescan)
+{
+ if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
+ ((id != SCAN_WILD_CARD) && (id > shost->max_id)) ||
+ ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
+ return -EINVAL;
+
+ if (channel == SCAN_WILD_CARD)
+ for (channel = 0; channel <= shost->max_channel; channel++)
+ scsi_scan_channel(shost, channel, id, lun, rescan);
+ else
+ scsi_scan_channel(shost, channel, id, lun, rescan);
+ return 0;
+}
+
+/**
+ * scsi_scan_host - scan the given adapter
+ * @shost: adapter to scan
+ **/
+void scsi_scan_host(struct Scsi_Host *shost)
+{
+ scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
+ SCAN_WILD_CARD, 0);
+}
+
+static int check_set(unsigned int *val, char *src, char *wild)
+{
+ char *last;
+
+ if (wild && strncmp(src, wild, 20) == 0) {
+ *val = SCAN_WILD_CARD;
+ } else {
+ /*
+ * Doesn't check for int overflow
+ */
+ *val = simple_strtoul(src, &last, 0);
+ if (*last != '\0')
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * scsi_scan - scan and possibly rescan for a given adapter
+ * @str: string with values of form "host_no chan id lun"
+ *
+ * Description:
+ * Determine the host_no, channel, id, and lun by parsing @str, and
+ * then call scsi_scan_host_selected. Except for host_no, values can
+ * be wild-carded using "-".
+ *
+ * Returns: 0 on success, -error on failure.
+ **/
+int scsi_scan(const char *str)
+{
+ struct Scsi_Host *shost;
+ char s1[15], s2[15], s3[15], s4[15], junk;
+ unsigned int host_no, channel, id, lun;
+ int res;
+
+ res = sscanf(str, "%10s %10s %10s %10s %c", s1, s2, s3, s4, &junk);
+ if (res != 4)
+ return -EINVAL;
+ if (check_set(&host_no, s1, NULL))
+ return -EINVAL;
+ if (check_set(&channel, s2, "-"))
+ return -EINVAL;
+ if (check_set(&id, s3, "-"))
+ return -EINVAL;
+ if (check_set(&lun, s4, "-"))
+ return -EINVAL;
+
+ SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n",
+ __FUNCTION__, host_no, channel, id, lun));
+ /*
+ * Doesn't check for overflow of host_no
+ */
+ shost = scsi_host_lookup(host_no);
+ if (!shost)
+ return -ENODEV;
+
+ res = scsi_scan_host_selected(shost, channel, id, lun, 1 /* rescan */);
+ scsi_host_put(shost);
+ return res;
+}
+
+/**
+ * scsi_remove - remove one scsi_device from shost
+ * @str: string with values of form "host_no chan id lun"
+ *
+ * Description:
+ * Determine the host_no, channel, id, and lun by parsing @str, and
+ * then call scsi_remove_device. No wild card support.
+ *
+ * Returns: 0 on success, -error on failure.
+ **/
+int scsi_remove(const char *str)
+{
+ struct scsi_device *sdev;
+ struct Scsi_Host *shost;
+ char s1[15], s2[15], s3[15], s4[15], junk;
+ unsigned int host_no, channel, id, lun;
+ int res;
+
+ res = sscanf(str, "%10s %10s %10s %10s %c", s1, s2, s3, s4, &junk);
+ if (res != 4)
+ return -EINVAL;
+ if (check_set(&host_no, s1, NULL))
+ return -EINVAL;
+ if (check_set(&channel, s2, NULL))
+ return -EINVAL;
+ if (check_set(&id, s3, NULL))
+ return -EINVAL;
+ if (check_set(&lun, s4, NULL))
+ return -EINVAL;
+
+ SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n",
+ __FUNCTION__, host_no, channel, id, lun));
+ /*
+ * Doesn't check for overflow of host_no
+ */
+ shost = scsi_host_lookup(host_no);
+ if (!shost)
+ return -ENODEV;
+
+ sdev = scsi_find_device(shost, channel, id, lun);
+ if (!sdev) {
+ res = -ENODEV;
+ goto out;
+ }
+
+ if (sdev->access_count) {
+ res = -EBUSY;
+ goto out;
}
+
+ res = 0;
+ scsi_remove_device(sdev);
+out:
+ scsi_host_put(shost);
+ return res;
}
void scsi_forget_host(struct Scsi_Host *shost)
diff -purN -X /home/patman/dontdiff bleed-2.5/drivers/scsi/scsi_sysfs.c scan-del-attr-bl-2.5/drivers/scsi/scsi_sysfs.c
--- bleed-2.5/drivers/scsi/scsi_sysfs.c Wed Jul 2 18:33:55 2003
+++ scan-del-attr-bl-2.5/drivers/scsi/scsi_sysfs.c Tue Jul 8 10:54:23 2003
@@ -73,6 +73,27 @@ struct bus_type scsi_bus_type = {
.match = scsi_bus_match,
};
+static ssize_t store_scan(struct bus_type *bus, const char *buf, size_t count)
+{
+ int res;
+
+ res = scsi_scan(buf);
+ if (res == 0)
+ res = count;
+ return res;
+};
+static BUS_ATTR(scan, S_IWUSR, NULL, store_scan);
+
+static ssize_t store_delete(struct bus_type *bus, const char *buf, size_t count)
+{
+ int res;
+
+ res = scsi_remove(buf);
+ if (res == 0)
+ res = count;
+ return res;
+};
+static BUS_ATTR(delete, S_IWUSR, NULL, store_delete);
int scsi_sysfs_register(void)
{
@@ -81,6 +102,12 @@ int scsi_sysfs_register(void)
error = bus_register(&scsi_bus_type);
if (error)
return error;
+ error = bus_create_file(&scsi_bus_type, &bus_attr_scan);
+ if (error)
+ goto bus_unregister;
+ error = bus_create_file(&scsi_bus_type, &bus_attr_delete);
+ if (error)
+ goto bus_unregister;
error = class_register(&shost_class);
if (error)
goto bus_unregister;
^ permalink raw reply [flat|nested] 10+ messages in thread* examples using sysfs attributes to scan and delete scsi_devices 2003-07-08 20:40 [PATCH] add sysfs attributes to scan and delete scsi_devices Patrick Mansfield @ 2003-07-08 20:41 ` Patrick Mansfield 2003-07-08 20:47 ` [PATCH] add " Christoph Hellwig ` (2 subsequent siblings) 3 siblings, 0 replies; 10+ messages in thread From: Patrick Mansfield @ 2003-07-08 20:41 UTC (permalink / raw) To: linux-scsi, James Bottomley Some sample usage of the delete and scan attributes. The system has one fastt200 (disk array) with 32 LUNs (4:0:0:*), 10 disk drives (4:0:1-10:0). [root@elm3b79 root]# ls -l /sysfs/bus/scsi total 0 --w------- 1 root root 0 Jul 8 13:28 delete drwxr-xr-x 2 root root 0 Jul 8 04:04 devices drwxr-xr-x 5 root root 0 Jul 8 04:04 drivers --w------- 1 root root 0 Jul 8 13:08 scan [root@elm3b79 root]# ls /sysfs/bus/scsi/devices 0:0:0:0 4:0:0:0 4:0:0:14 4:0:0:2 4:0:0:25 4:0:0:30 4:0:0:8 4:0:4:0 0:0:1:0 4:0:0:1 4:0:0:15 4:0:0:20 4:0:0:26 4:0:0:31 4:0:0:9 4:0:5:0 0:0:2:0 4:0:0:10 4:0:0:16 4:0:0:21 4:0:0:27 4:0:0:4 4:0:1:0 4:0:6:0 0:0:3:0 4:0:0:11 4:0:0:17 4:0:0:22 4:0:0:28 4:0:0:5 4:0:10:0 4:0:7:0 0:0:4:0 4:0:0:12 4:0:0:18 4:0:0:23 4:0:0:29 4:0:0:6 4:0:2:0 4:0:8:0 0:0:5:0 4:0:0:13 4:0:0:19 4:0:0:24 4:0:0:3 4:0:0:7 4:0:3:0 4:0:9:0 # delete a few scsi_devices from the disk array [root@elm3b79 root]# echo "4 0 0 25" > /root/xx; dd if=/root/xx of=/sysfs/bus/scsi/delete 0+1 records in 0+1 records out [root@elm3b79 root]# echo "4 0 0 1" > /root/xx; dd if=/root/xx of=/sysfs/bus/scsi/delete 0+1 records in 0+1 records out [root@elm3b79 root]# echo "4 0 0 3" > /root/xx; dd if=/root/xx of=/sysfs/bus/scsi/delete 0+1 records in 0+1 records out [root@elm3b79 root]# ls /sysfs/bus/scsi/devices 0:0:0:0 4:0:0:0 4:0:0:15 4:0:0:20 4:0:0:27 4:0:0:5 4:0:10:0 4:0:7:0 0:0:1:0 4:0:0:10 4:0:0:16 4:0:0:21 4:0:0:28 4:0:0:6 4:0:2:0 4:0:8:0 0:0:2:0 4:0:0:11 4:0:0:17 4:0:0:22 4:0:0:29 4:0:0:7 4:0:3:0 4:0:9:0 0:0:3:0 4:0:0:12 4:0:0:18 4:0:0:23 4:0:0:30 4:0:0:8 4:0:4:0 0:0:4:0 4:0:0:13 4:0:0:19 4:0:0:24 4:0:0:31 4:0:0:9 4:0:5:0 0:0:5:0 4:0:0:14 4:0:0:2 4:0:0:26 4:0:0:4 4:0:1:0 4:0:6:0 # Rescan a target, in this particular case a REPORT LUN scan occurs [root@elm3b79 root]# echo "4 0 0 -" > /root/xx; dd if=/root/xx of=/sysfs/bus/scsi/scan 0+1 records in 0+1 records out [root@elm3b79 root]# ls /sysfs/bus/scsi delete devices drivers scan [root@elm3b79 root]# ls /sysfs/bus/scsi/devices 0:0:0:0 4:0:0:0 4:0:0:14 4:0:0:2 4:0:0:25 4:0:0:30 4:0:0:8 4:0:4:0 0:0:1:0 4:0:0:1 4:0:0:15 4:0:0:20 4:0:0:26 4:0:0:31 4:0:0:9 4:0:5:0 0:0:2:0 4:0:0:10 4:0:0:16 4:0:0:21 4:0:0:27 4:0:0:4 4:0:1:0 4:0:6:0 0:0:3:0 4:0:0:11 4:0:0:17 4:0:0:22 4:0:0:28 4:0:0:5 4:0:10:0 4:0:7:0 0:0:4:0 4:0:0:12 4:0:0:18 4:0:0:23 4:0:0:29 4:0:0:6 4:0:2:0 4:0:8:0 0:0:5:0 4:0:0:13 4:0:0:19 4:0:0:24 4:0:0:3 4:0:0:7 4:0:3:0 4:0:9:0 # Rescan an entire adapter [root@elm3b79 root]# echo "4 - - -" > /root/xx; dd if=/root/xx of=/sysfs/bus/scsi/scan 0+1 records in 0+1 records out # some failure cases [root@elm3b79 root]# echo "4 0 0 88" > /root/xx; dd if=/root/xx of=/sysfs/bus/scsi/delete dd: writing `/sysfs/bus/scsi/delete': No such device 0+1 records in 0+0 records out [root@elm3b79 root]# echo "4 0 88" > /root/xx; dd if=/root/xx of=/sysfs/bus/scsi/delete dd: writing `/sysfs/bus/scsi/delete': Invalid argument 0+1 records in 0+0 records out -- Patrick Mansfield ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] add sysfs attributes to scan and delete scsi_devices 2003-07-08 20:40 [PATCH] add sysfs attributes to scan and delete scsi_devices Patrick Mansfield 2003-07-08 20:41 ` examples using " Patrick Mansfield @ 2003-07-08 20:47 ` Christoph Hellwig 2003-07-08 22:36 ` Patrick Mansfield 2003-07-08 20:50 ` James Bottomley 2003-07-09 20:27 ` [PATCH] take 2 " Patrick Mansfield 3 siblings, 1 reply; 10+ messages in thread From: Christoph Hellwig @ 2003-07-08 20:47 UTC (permalink / raw) To: Patrick Mansfield; +Cc: linux-scsi, James Bottomley On Tue, Jul 08, 2003 at 01:40:16PM -0700, Patrick Mansfield wrote: > This patch against recent 2.5 bk adds a sysfs attribute to allow scanning > (or rescanning) and deletion of scsi_devices. > > It also allows scanning of entire hosts, channels, or targets. Looks good so far but please keep the string parsing in scsi_sysfs.c instead of scsi_scan.c. Also doesn't want this some code sharing with the old procfs code? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] add sysfs attributes to scan and delete scsi_devices 2003-07-08 20:47 ` [PATCH] add " Christoph Hellwig @ 2003-07-08 22:36 ` Patrick Mansfield 0 siblings, 0 replies; 10+ messages in thread From: Patrick Mansfield @ 2003-07-08 22:36 UTC (permalink / raw) To: Christoph Hellwig; +Cc: linux-scsi, James Bottomley On Tue, Jul 08, 2003 at 09:47:27PM +0100, Christoph Hellwig wrote: > Looks good so far but please keep the string parsing in scsi_sysfs.c > instead of scsi_scan.c. Also doesn't want this some code sharing with > the old procfs code? I can change procfs to use scsi_scan_host_selected(), it will be externed for use in scsi_sysfs.c. But is it worth propagating through the call chain whether a new device was found (i.e. scsi_add_device returns -ENODEV)? -- Patrick Mansfield ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] add sysfs attributes to scan and delete scsi_devices 2003-07-08 20:40 [PATCH] add sysfs attributes to scan and delete scsi_devices Patrick Mansfield 2003-07-08 20:41 ` examples using " Patrick Mansfield 2003-07-08 20:47 ` [PATCH] add " Christoph Hellwig @ 2003-07-08 20:50 ` James Bottomley 2003-07-08 21:13 ` Christoph Hellwig 2003-07-09 20:27 ` [PATCH] take 2 " Patrick Mansfield 3 siblings, 1 reply; 10+ messages in thread From: James Bottomley @ 2003-07-08 20:50 UTC (permalink / raw) To: Patrick Mansfield; +Cc: SCSI Mailing List On Tue, 2003-07-08 at 15:40, Patrick Mansfield wrote: > This patch against recent 2.5 bk adds a sysfs attribute to allow scanning > (or rescanning) and deletion of scsi_devices. > > It also allows scanning of entire hosts, channels, or targets. I'm not convinced we need a bus file for this. What's the reason we can't have a per host file instead? I'm thinking of the hotplug case where you know the sysfs path to the card just inserted. Translating that to a hostid will be rather hard. James ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] add sysfs attributes to scan and delete scsi_devices 2003-07-08 20:50 ` James Bottomley @ 2003-07-08 21:13 ` Christoph Hellwig 2003-07-08 22:24 ` Patrick Mansfield 0 siblings, 1 reply; 10+ messages in thread From: Christoph Hellwig @ 2003-07-08 21:13 UTC (permalink / raw) To: James Bottomley; +Cc: Patrick Mansfield, SCSI Mailing List On Tue, Jul 08, 2003 at 03:50:15PM -0500, James Bottomley wrote: > I'm not convinced we need a bus file for this. What's the reason we > can't have a per host file instead? > > I'm thinking of the hotplug case where you know the sysfs path to the > card just inserted. Translating that to a hostid will be rather hard. After thinking about this again I tend to agree with you that a per-host file sounds like the better idea. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] add sysfs attributes to scan and delete scsi_devices 2003-07-08 21:13 ` Christoph Hellwig @ 2003-07-08 22:24 ` Patrick Mansfield 2003-07-13 13:43 ` Christoph Hellwig 0 siblings, 1 reply; 10+ messages in thread From: Patrick Mansfield @ 2003-07-08 22:24 UTC (permalink / raw) To: Christoph Hellwig; +Cc: James Bottomley, SCSI Mailing List On Tue, Jul 08, 2003 at 10:13:51PM +0100, Christoph Hellwig wrote: > On Tue, Jul 08, 2003 at 03:50:15PM -0500, James Bottomley wrote: > > I'm not convinced we need a bus file for this. What's the reason we > > can't have a per host file instead? > > > > I'm thinking of the hotplug case where you know the sysfs path to the > > card just inserted. Translating that to a hostid will be rather hard. > > After thinking about this again I tend to agree with you that a per-host > file sounds like the better idea. James/Christoph - There is not much of a difference either way. Scanning makes more sense as a host attribute (or as a target attribute, but we don't have a target device today). Deletion of a scsi_device makes more sense as a /sysfs/bus/scsi (or even scsi_device) attribute that takes a bus_id. But we should be symmetrical for a user space interface. (And it is easier to catch sscanf errors using spaces as a separator.) I'll go ahead and redo it as per-host, and move string parsing into scsi_sysfs.c. Thanks for the feedback. -- Patrick Mansfield ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] add sysfs attributes to scan and delete scsi_devices 2003-07-08 22:24 ` Patrick Mansfield @ 2003-07-13 13:43 ` Christoph Hellwig 0 siblings, 0 replies; 10+ messages in thread From: Christoph Hellwig @ 2003-07-13 13:43 UTC (permalink / raw) To: Patrick Mansfield; +Cc: James Bottomley, SCSI Mailing List On Tue, Jul 08, 2003 at 03:24:40PM -0700, Patrick Mansfield wrote: > Scanning makes more sense as a host attribute (or as a target attribute, > but we don't have a target device today). So we should have a scan host attribute for that. > Deletion of a scsi_device makes > more sense as a /sysfs/bus/scsi (or even scsi_device) attribute that takes > a bus_id. I don't think it makes sense as a /sysfs/bus/scsi attribute. Having it as a scsi_device attribute makes lots of sense, I just wonder whether the non-symmetric interface would confuse users. Probably not too much as scannaing a bus an deleting a device isn't really a symmetric interface anyway.` ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH] take 2 add sysfs attributes to scan and delete scsi_devices 2003-07-08 20:40 [PATCH] add sysfs attributes to scan and delete scsi_devices Patrick Mansfield ` (2 preceding siblings ...) 2003-07-08 20:50 ` James Bottomley @ 2003-07-09 20:27 ` Patrick Mansfield 2003-07-09 20:29 ` and some example usage of the attributes Patrick Mansfield 3 siblings, 1 reply; 10+ messages in thread From: Patrick Mansfield @ 2003-07-09 20:27 UTC (permalink / raw) To: linux-scsi, James Bottomley This patch against scsi-misc-2.5 adds a sysfs attribute to allow scanning (or rescanning) and deletion of scsi_devices. It also allows scanning of entire hosts, channels, or targets. Updated per comments received, mainly create the scan and delete attributes per host. The scsi_proc.c remove code was not changed, it and this patch still need changes based on Mike A's patches. diff -purN -X /home/patman/dontdiff scsi-misc-2.5-pure/drivers/scsi/scsi_priv.h scan-del-attr-sm-2.5/drivers/scsi/scsi_priv.h --- scsi-misc-2.5-pure/drivers/scsi/scsi_priv.h Wed Jul 9 09:12:38 2003 +++ scan-del-attr-sm-2.5/drivers/scsi/scsi_priv.h Wed Jul 9 09:22:42 2003 @@ -42,6 +42,12 @@ (((scmd)->sense_buffer[0] & 0x70) == 0x70) /* + * Special value for scanning to specify scanning or rescanning of all + * possible channels, (target) ids, or luns on a given shost. + */ +#define SCAN_WILD_CARD ~0 + +/* * scsi_target: representation of a scsi target, for now, this is only * used for single_lun devices. If no one has active IO to the target, * starget_sdev_user is NULL, else it points to the active sdev. @@ -102,6 +108,8 @@ extern void scsi_exit_procfs(void); #endif /* CONFIG_PROC_FS */ /* scsi_scan.c */ +int scsi_scan_host_selected(struct Scsi_Host *, unsigned int, unsigned int, + unsigned int, int); extern void scsi_forget_host(struct Scsi_Host *); extern void scsi_free_sdev(struct scsi_device *); extern void scsi_free_shost(struct Scsi_Host *); diff -purN -X /home/patman/dontdiff scsi-misc-2.5-pure/drivers/scsi/scsi_proc.c scan-del-attr-sm-2.5/drivers/scsi/scsi_proc.c --- scsi-misc-2.5-pure/drivers/scsi/scsi_proc.c Thu Jun 12 02:50:06 2003 +++ scan-del-attr-sm-2.5/drivers/scsi/scsi_proc.c Wed Jul 9 12:05:37 2003 @@ -174,21 +174,11 @@ static int proc_print_scsidevice(struct static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) { struct Scsi_Host *shost; - struct scsi_device *sdev; - int error = -ENODEV; - + int error; shost = scsi_host_lookup(host); if (!shost) return -ENODEV; - - if (!scsi_find_device(shost, channel, id, lun)) { - sdev = scsi_add_device(shost, channel, id, lun); - if (IS_ERR(sdev)) - error = PTR_ERR(sdev); - else - error = 0; - } - + error = scsi_scan_host_selected(shost, channel, id, lun, 1); scsi_host_put(shost); return error; } diff -purN -X /home/patman/dontdiff scsi-misc-2.5-pure/drivers/scsi/scsi_scan.c scan-del-attr-sm-2.5/drivers/scsi/scsi_scan.c --- scsi-misc-2.5-pure/drivers/scsi/scsi_scan.c Wed Jul 9 09:12:38 2003 +++ scan-del-attr-sm-2.5/drivers/scsi/scsi_scan.c Wed Jul 9 09:19:41 2003 @@ -678,13 +678,32 @@ static int scsi_add_lun(struct scsi_devi **/ static int scsi_probe_and_add_lun(struct Scsi_Host *host, uint channel, uint id, uint lun, int *bflagsp, - struct scsi_device **sdevp) + struct scsi_device **sdevp, int rescan) { struct scsi_device *sdev; struct scsi_request *sreq; unsigned char *result; int bflags, res = SCSI_SCAN_NO_RESPONSE; + /* + * The rescan flag is used as an optimization, the first scan of a + * host adapter calls into here with rescan == 0. + */ + if (rescan) { + sdev = scsi_find_device(host, channel, id, lun); + if (sdev) { + SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO + "scsi scan: device exists on <%d:%d:%d:%d>\n", + host->host_no, channel, id, lun)); + if (sdevp) + *sdevp = sdev; + if (bflagsp) + *bflagsp = scsi_get_device_flags(sdev->vendor, + sdev->model); + return SCSI_SCAN_LUN_PRESENT; + } + } + sdev = scsi_alloc_sdev(host, channel, id, lun); if (!sdev) goto out; @@ -759,7 +778,7 @@ static int scsi_probe_and_add_lun(struct * Modifies sdevscan->lun. **/ static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel, - uint id, int bflags, int lun0_res, int scsi_level) + uint id, int bflags, int lun0_res, int scsi_level, int rescan) { unsigned int sparse_lun, lun, max_dev_lun; @@ -828,7 +847,8 @@ static void scsi_sequential_lun_scan(str */ for (lun = 1; lun < max_dev_lun; ++lun) if ((scsi_probe_and_add_lun(shost, channel, id, lun, - NULL, NULL) != SCSI_SCAN_LUN_PRESENT) && !sparse_lun) + NULL, NULL, rescan) != SCSI_SCAN_LUN_PRESENT) && + !sparse_lun) return; } @@ -879,7 +899,8 @@ static int scsilun_to_int(struct scsi_lu * 0: scan completed (or no memory, so further scanning is futile) * 1: no report lun scan, or not configured **/ -static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags) +static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, + int rescan) { char devname[64]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; @@ -1033,7 +1054,7 @@ static int scsi_report_lun_scan(struct s int res; res = scsi_probe_and_add_lun(sdev->host, sdev->channel, - sdev->id, lun, NULL, NULL); + sdev->id, lun, NULL, NULL, rescan); if (res == SCSI_SCAN_NO_RESPONSE) { /* * Got some results, but now none, abort. @@ -1059,7 +1080,7 @@ static int scsi_report_lun_scan(struct s return 0; } #else -# define scsi_report_lun_scan(sdev, blags) (1) +# define scsi_report_lun_scan(sdev, blags, rescan) (1) #endif /* CONFIG_SCSI_REPORT_LUNS */ struct scsi_device *scsi_add_device(struct Scsi_Host *shost, @@ -1068,7 +1089,11 @@ struct scsi_device *scsi_add_device(stru struct scsi_device *sdev; int res; - res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev); + /* + * Caller already checked if sdev exists, but be paranoid and call + * with rescan of 1. + */ + res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev, 1); if (res != SCSI_SCAN_LUN_PRESENT) sdev = ERR_PTR(-ENODEV); return sdev; @@ -1111,7 +1136,7 @@ void scsi_rescan_device(struct device *d * sequential scan of LUNs on the target id. **/ static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel, - unsigned int id) + unsigned int id, unsigned int lun, int rescan) { int bflags = 0; int res; @@ -1123,19 +1148,29 @@ static void scsi_scan_target(struct Scsi */ return; + if (lun != SCAN_WILD_CARD) { + /* + * Scan for a specific host/chan/id/lun. + */ + scsi_probe_and_add_lun(shost, channel, id, lun, NULL, NULL, + rescan); + return; + } + /* * Scan LUN 0, if there is some response, scan further. Ideally, we * would not configure LUN 0 until all LUNs are scanned. */ - res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev); + res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev, + rescan); if (res == SCSI_SCAN_LUN_PRESENT) { - if (scsi_report_lun_scan(sdev, bflags) != 0) + if (scsi_report_lun_scan(sdev, bflags, rescan) != 0) /* * The REPORT LUN did not scan the target, * do a sequential scan. */ scsi_sequential_lun_scan(shost, channel, id, bflags, - res, sdev->scsi_level); + res, sdev->scsi_level, rescan); } else if (res == SCSI_SCAN_TARGET_PRESENT) { /* * There's a target here, but lun 0 is offline so we @@ -1144,37 +1179,26 @@ static void scsi_scan_target(struct Scsi * a default scsi level of SCSI_2 */ scsi_sequential_lun_scan(shost, channel, id, BLIST_SPARSELUN, - SCSI_SCAN_TARGET_PRESENT, SCSI_2); + SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan); } } -/** - * scsi_scan_host - scan the given adapter - * @shost: adapter to scan - * - * Description: - * Iterate and call scsi_scan_target to scan all possible target id's - * on all possible channels. - **/ -void scsi_scan_host(struct Scsi_Host *shost) +static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel, + unsigned int id, unsigned int lun, int rescan) { - uint channel, id, order_id; + uint order_id; - /* - * The sdevscan host, channel, id and lun are filled in as - * needed to scan. - */ - for (channel = 0; channel <= shost->max_channel; channel++) { - /* - * XXX adapter drivers when possible (FCP, iSCSI) - * could modify max_id to match the current max, - * not the absolute max. - * - * XXX add a shost id iterator, so for example, - * the FC ID can be the same as a target id - * without a huge overhead of sparse id's. - */ + if (id == SCAN_WILD_CARD) for (id = 0; id < shost->max_id; ++id) { + /* + * XXX adapter drivers when possible (FCP, iSCSI) + * could modify max_id to match the current max, + * not the absolute max. + * + * XXX add a shost id iterator, so for example, + * the FC ID can be the same as a target id + * without a huge overhead of sparse id's. + */ if (shost->reverse_ordering) /* * Scan from high to low id. @@ -1182,9 +1206,36 @@ void scsi_scan_host(struct Scsi_Host *sh order_id = shost->max_id - id - 1; else order_id = id; - scsi_scan_target(shost, channel, order_id); + scsi_scan_target(shost, channel, order_id, lun, rescan); } - } + else + scsi_scan_target(shost, channel, id, lun, rescan); +} + +int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, + unsigned int id, unsigned int lun, int rescan) +{ + if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || + ((id != SCAN_WILD_CARD) && (id > shost->max_id)) || + ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) + return -EINVAL; + + if (channel == SCAN_WILD_CARD) + for (channel = 0; channel <= shost->max_channel; channel++) + scsi_scan_channel(shost, channel, id, lun, rescan); + else + scsi_scan_channel(shost, channel, id, lun, rescan); + return 0; +} + +/** + * scsi_scan_host - scan the given adapter + * @shost: adapter to scan + **/ +void scsi_scan_host(struct Scsi_Host *shost) +{ + scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, + SCAN_WILD_CARD, 0); } void scsi_forget_host(struct Scsi_Host *shost) diff -purN -X /home/patman/dontdiff scsi-misc-2.5-pure/drivers/scsi/scsi_sysfs.c scan-del-attr-sm-2.5/drivers/scsi/scsi_sysfs.c --- scsi-misc-2.5-pure/drivers/scsi/scsi_sysfs.c Wed Jul 9 09:12:38 2003 +++ scan-del-attr-sm-2.5/drivers/scsi/scsi_sysfs.c Wed Jul 9 12:04:45 2003 @@ -15,6 +15,85 @@ #include "hosts.h" #include "scsi_priv.h" +#include "scsi_logging.h" + +static int check_set(unsigned int *val, char *src, char *wild) +{ + char *last; + + if (wild && strncmp(src, wild, 20) == 0) { + *val = SCAN_WILD_CARD; + } else { + /* + * Doesn't check for int overflow + */ + *val = simple_strtoul(src, &last, 0); + if (*last != '\0') + return 1; + } + return 0; +} + +static int scsi_scan(struct Scsi_Host *shost, const char *str) +{ + char s1[15], s2[15], s3[15], junk; + unsigned int channel, id, lun; + int res; + + res = sscanf(str, "%10s %10s %10s %c", s1, s2, s3, &junk); + if (res != 3) + return -EINVAL; + if (check_set(&channel, s1, "-")) + return -EINVAL; + if (check_set(&id, s2, "-")) + return -EINVAL; + if (check_set(&lun, s3, "-")) + return -EINVAL; + + SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n", + __FUNCTION__, shost->host_no, channel, id, lun)); + res = scsi_scan_host_selected(shost, channel, id, lun, 1); + return res; +} + +static int scsi_remove(struct Scsi_Host *shost, const char *str) +{ + struct scsi_device *sdev; + char s1[15], s2[15], s3[15], junk; + unsigned int channel, id, lun; + int res; + + res = sscanf(str, "%10s %10s %10s %c", s1, s2, s3, &junk); + if (res != 3) + return -EINVAL; + if (check_set(&channel, s1, NULL)) + return -EINVAL; + if (check_set(&id, s2, NULL)) + return -EINVAL; + if (check_set(&lun, s3, NULL)) + return -EINVAL; + + SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n", + __FUNCTION__, shost->host_no, channel, id, lun)); + sdev = scsi_find_device(shost, channel, id, lun); + if (!sdev) { + res = -ENODEV; + goto out; + } + + if (sdev->access_count) { + /* + * FIXME andmike patch + */ + res = -EBUSY; + goto out; + } + + res = 0; + scsi_remove_device(sdev); +out: + return res; +} /* * shost_show_function: macro to create an attr function that can be used to @@ -39,6 +118,33 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO, /* * Create the actual show/store functions and data structures. */ + +static ssize_t store_scan(struct class_device *class_dev, const char *buf, + size_t count) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + int res; + + res = scsi_scan(shost, buf); + if (res == 0) + res = count; + return res; +}; +static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); + +static ssize_t store_delete(struct class_device *class_dev, const char *buf, + size_t count) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + int res; + + res = scsi_remove(shost, buf); + if (res == 0) + res = count; + return res; +}; +static CLASS_DEVICE_ATTR(delete, S_IWUSR, NULL, store_delete); + shost_rd_attr(unique_id, "%u\n"); shost_rd_attr(host_busy, "%hu\n"); shost_rd_attr(cmd_per_lun, "%hd\n"); @@ -51,6 +157,8 @@ static struct class_device_attribute *sc &class_device_attr_cmd_per_lun, &class_device_attr_sg_tablesize, &class_device_attr_unchecked_isa_dma, + &class_device_attr_scan, + &class_device_attr_delete, NULL }; @@ -73,7 +181,6 @@ struct bus_type scsi_bus_type = { .match = scsi_bus_match, }; - int scsi_sysfs_register(void) { int error; ^ permalink raw reply [flat|nested] 10+ messages in thread
* and some example usage of the attributes 2003-07-09 20:27 ` [PATCH] take 2 " Patrick Mansfield @ 2003-07-09 20:29 ` Patrick Mansfield 0 siblings, 0 replies; 10+ messages in thread From: Patrick Mansfield @ 2003-07-09 20:29 UTC (permalink / raw) To: linux-scsi, James Bottomley Some example uses of the delete and scan attribute. [root@elm3b79 root]# ls -l /sysfs/class/scsi_host/host2 total 0 -r--r--r-- 1 root root 4096 Jul 9 12:30 cmd_per_lun --w------- 1 root root 0 Jul 9 12:34 delete lrwxrwxrwx 1 root root 46 Jul 9 12:30 device -> ../../../devices/pci0000:01/0000:01:0c.0/host2 -r--r--r-- 1 root root 4096 Jul 9 12:30 host_busy --w------- 1 root root 0 Jul 9 12:36 scan -r--r--r-- 1 root root 4096 Jul 9 12:30 sg_tablesize -r--r--r-- 1 root root 4096 Jul 9 12:30 unchecked_isa_dma -r--r--r-- 1 root root 4096 Jul 9 12:30 unique_id [root@elm3b79 root]# ls /sysfs/class/scsi_host/host2/device 2:0:0:0 2:0:0:14 2:0:0:2 2:0:0:25 2:0:0:30 2:0:0:8 2:0:4:0 name 2:0:0:1 2:0:0:15 2:0:0:20 2:0:0:26 2:0:0:31 2:0:0:9 2:0:5:0 power 2:0:0:10 2:0:0:16 2:0:0:21 2:0:0:27 2:0:0:4 2:0:1:0 2:0:6:0 2:0:0:11 2:0:0:17 2:0:0:22 2:0:0:28 2:0:0:5 2:0:10:0 2:0:7:0 2:0:0:12 2:0:0:18 2:0:0:23 2:0:0:29 2:0:0:6 2:0:2:0 2:0:8:0 2:0:0:13 2:0:0:19 2:0:0:24 2:0:0:3 2:0:0:7 2:0:3:0 2:0:9:0 # Delete some devices [root@elm3b79 root]# echo "0 9 0" > /root/xx; dd if=/root/xx of=/sysfs/class/scsi_host/host2/delete 0+1 records in 0+1 records out [root@elm3b79 root]# echo "0 0 0" > /root/xx; dd if=/root/xx of=/sysfs/class/scsi_host/host2/delete 0+1 records in 0+1 records out [root@elm3b79 root]# echo "0 0 22" > /root/xx; dd if=/root/xx of=/sysfs/class/scsi_host/host2/delete 0+1 records in 0+1 records out # Scan a target - for this target REPORT LUN is used [root@elm3b79 root]# echo "0 0 -" > /root/xx; dd if=/root/xx of=/sysfs/class/scsi_host/host2/scan 0+1 records in 0+1 records out # Scan the entire host [root@elm3b79 root]# echo "- - -" > /root/xx; dd if=/root/xx of=/sysfs/class/scsi_host/host2/scan 0+1 records in 0+1 records out -- Patrick Mansfield ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2003-07-13 13:28 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2003-07-08 20:40 [PATCH] add sysfs attributes to scan and delete scsi_devices Patrick Mansfield 2003-07-08 20:41 ` examples using " Patrick Mansfield 2003-07-08 20:47 ` [PATCH] add " Christoph Hellwig 2003-07-08 22:36 ` Patrick Mansfield 2003-07-08 20:50 ` James Bottomley 2003-07-08 21:13 ` Christoph Hellwig 2003-07-08 22:24 ` Patrick Mansfield 2003-07-13 13:43 ` Christoph Hellwig 2003-07-09 20:27 ` [PATCH] take 2 " Patrick Mansfield 2003-07-09 20:29 ` and some example usage of the attributes Patrick Mansfield
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox