Skip to content

Commit 7973cbd

Browse files
Patrick MansfieldJames Bottomley
authored andcommitted
[PATCH] add sysfs attributes to scan and delete scsi_devices
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. It adds a per-host scan attribute, and a per scsi_device delete attribute.
1 parent 8e47b96 commit 7973cbd

File tree

4 files changed

+168
-48
lines changed

4 files changed

+168
-48
lines changed

drivers/scsi/scsi_priv.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@
4141
#define SCSI_SENSE_VALID(scmd) \
4242
(((scmd)->sense_buffer[0] & 0x70) == 0x70)
4343

44+
/*
45+
* Special value for scanning to specify scanning or rescanning of all
46+
* possible channels, (target) ids, or luns on a given shost.
47+
*/
48+
#define SCAN_WILD_CARD ~0
49+
4450
/*
4551
* scsi_target: representation of a scsi target, for now, this is only
4652
* used for single_lun devices. If no one has active IO to the target,
@@ -109,6 +115,8 @@ extern void scsi_exit_procfs(void);
109115
#endif /* CONFIG_PROC_FS */
110116

111117
/* scsi_scan.c */
118+
int scsi_scan_host_selected(struct Scsi_Host *, unsigned int, unsigned int,
119+
unsigned int, int);
112120
extern void scsi_forget_host(struct Scsi_Host *);
113121
extern void scsi_free_sdev(struct scsi_device *);
114122
extern void scsi_rescan_device(struct device *);

drivers/scsi/scsi_proc.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,21 +189,13 @@ static int proc_print_scsidevice(struct device *dev, void *data)
189189
static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
190190
{
191191
struct Scsi_Host *shost;
192-
struct scsi_device *sdev;
193192
int error = -ENXIO;
194193

195194
shost = scsi_host_lookup(host);
196195
if (IS_ERR(shost))
197196
return PTR_ERR(shost);
198197

199-
if (!scsi_find_device(shost, channel, id, lun)) {
200-
sdev = scsi_add_device(shost, channel, id, lun);
201-
if (IS_ERR(sdev))
202-
error = PTR_ERR(sdev);
203-
else
204-
error = 0;
205-
}
206-
198+
error = scsi_scan_host_selected(shost, channel, id, lun, 1);
207199
scsi_host_put(shost);
208200
return error;
209201
}

drivers/scsi/scsi_scan.c

Lines changed: 88 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -676,13 +676,32 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
676676
**/
677677
static int scsi_probe_and_add_lun(struct Scsi_Host *host,
678678
uint channel, uint id, uint lun, int *bflagsp,
679-
struct scsi_device **sdevp)
679+
struct scsi_device **sdevp, int rescan)
680680
{
681681
struct scsi_device *sdev;
682682
struct scsi_request *sreq;
683683
unsigned char *result;
684684
int bflags, res = SCSI_SCAN_NO_RESPONSE;
685685

686+
/*
687+
* The rescan flag is used as an optimization, the first scan of a
688+
* host adapter calls into here with rescan == 0.
689+
*/
690+
if (rescan) {
691+
sdev = scsi_find_device(host, channel, id, lun);
692+
if (sdev) {
693+
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
694+
"scsi scan: device exists on <%d:%d:%d:%d>\n",
695+
host->host_no, channel, id, lun));
696+
if (sdevp)
697+
*sdevp = sdev;
698+
if (bflagsp)
699+
*bflagsp = scsi_get_device_flags(sdev->vendor,
700+
sdev->model);
701+
return SCSI_SCAN_LUN_PRESENT;
702+
}
703+
}
704+
686705
sdev = scsi_alloc_sdev(host, channel, id, lun);
687706
if (!sdev)
688707
goto out;
@@ -757,7 +776,7 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
757776
* Modifies sdevscan->lun.
758777
**/
759778
static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel,
760-
uint id, int bflags, int lun0_res, int scsi_level)
779+
uint id, int bflags, int lun0_res, int scsi_level, int rescan)
761780
{
762781
unsigned int sparse_lun, lun, max_dev_lun;
763782

@@ -826,7 +845,8 @@ static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel,
826845
*/
827846
for (lun = 1; lun < max_dev_lun; ++lun)
828847
if ((scsi_probe_and_add_lun(shost, channel, id, lun,
829-
NULL, NULL) != SCSI_SCAN_LUN_PRESENT) && !sparse_lun)
848+
NULL, NULL, rescan) != SCSI_SCAN_LUN_PRESENT) &&
849+
!sparse_lun)
830850
return;
831851
}
832852

@@ -877,7 +897,8 @@ static int scsilun_to_int(struct scsi_lun *scsilun)
877897
* 0: scan completed (or no memory, so further scanning is futile)
878898
* 1: no report lun scan, or not configured
879899
**/
880-
static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
900+
static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
901+
int rescan)
881902
{
882903
char devname[64];
883904
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -1031,7 +1052,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
10311052
int res;
10321053

10331054
res = scsi_probe_and_add_lun(sdev->host, sdev->channel,
1034-
sdev->id, lun, NULL, NULL);
1055+
sdev->id, lun, NULL, NULL, rescan);
10351056
if (res == SCSI_SCAN_NO_RESPONSE) {
10361057
/*
10371058
* Got some results, but now none, abort.
@@ -1057,7 +1078,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
10571078
return 0;
10581079
}
10591080
#else
1060-
# define scsi_report_lun_scan(sdev, blags) (1)
1081+
# define scsi_report_lun_scan(sdev, blags, rescan) (1)
10611082
#endif /* CONFIG_SCSI_REPORT_LUNS */
10621083

10631084
struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
@@ -1066,7 +1087,7 @@ struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
10661087
struct scsi_device *sdev;
10671088
int res;
10681089

1069-
res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev);
1090+
res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev, 1);
10701091
if (res != SCSI_SCAN_LUN_PRESENT)
10711092
sdev = ERR_PTR(-ENODEV);
10721093
return sdev;
@@ -1103,7 +1124,7 @@ void scsi_rescan_device(struct device *dev)
11031124
* sequential scan of LUNs on the target id.
11041125
**/
11051126
static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
1106-
unsigned int id)
1127+
unsigned int id, unsigned int lun, int rescan)
11071128
{
11081129
int bflags = 0;
11091130
int res;
@@ -1115,19 +1136,29 @@ static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
11151136
*/
11161137
return;
11171138

1139+
if (lun != SCAN_WILD_CARD) {
1140+
/*
1141+
* Scan for a specific host/chan/id/lun.
1142+
*/
1143+
scsi_probe_and_add_lun(shost, channel, id, lun, NULL, NULL,
1144+
rescan);
1145+
return;
1146+
}
1147+
11181148
/*
11191149
* Scan LUN 0, if there is some response, scan further. Ideally, we
11201150
* would not configure LUN 0 until all LUNs are scanned.
11211151
*/
1122-
res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev);
1152+
res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev,
1153+
rescan);
11231154
if (res == SCSI_SCAN_LUN_PRESENT) {
1124-
if (scsi_report_lun_scan(sdev, bflags) != 0)
1155+
if (scsi_report_lun_scan(sdev, bflags, rescan) != 0)
11251156
/*
11261157
* The REPORT LUN did not scan the target,
11271158
* do a sequential scan.
11281159
*/
11291160
scsi_sequential_lun_scan(shost, channel, id, bflags,
1130-
res, sdev->scsi_level);
1161+
res, sdev->scsi_level, rescan);
11311162
} else if (res == SCSI_SCAN_TARGET_PRESENT) {
11321163
/*
11331164
* There's a target here, but lun 0 is offline so we
@@ -1136,47 +1167,66 @@ static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
11361167
* a default scsi level of SCSI_2
11371168
*/
11381169
scsi_sequential_lun_scan(shost, channel, id, BLIST_SPARSELUN,
1139-
SCSI_SCAN_TARGET_PRESENT, SCSI_2);
1170+
SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan);
11401171
}
11411172
}
11421173

1143-
/**
1144-
* scsi_scan_host - scan the given adapter
1145-
* @shost: adapter to scan
1146-
*
1147-
* Description:
1148-
* Iterate and call scsi_scan_target to scan all possible target id's
1149-
* on all possible channels.
1150-
**/
1151-
void scsi_scan_host(struct Scsi_Host *shost)
1174+
static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
1175+
unsigned int id, unsigned int lun, int rescan)
11521176
{
1153-
uint channel, id, order_id;
1177+
uint order_id;
11541178

1155-
/*
1156-
* The sdevscan host, channel, id and lun are filled in as
1157-
* needed to scan.
1158-
*/
1159-
for (channel = 0; channel <= shost->max_channel; channel++) {
1160-
/*
1161-
* XXX adapter drivers when possible (FCP, iSCSI)
1162-
* could modify max_id to match the current max,
1163-
* not the absolute max.
1164-
*
1165-
* XXX add a shost id iterator, so for example,
1166-
* the FC ID can be the same as a target id
1167-
* without a huge overhead of sparse id's.
1168-
*/
1179+
if (id == SCAN_WILD_CARD)
11691180
for (id = 0; id < shost->max_id; ++id) {
1181+
/*
1182+
* XXX adapter drivers when possible (FCP, iSCSI)
1183+
* could modify max_id to match the current max,
1184+
* not the absolute max.
1185+
*
1186+
* XXX add a shost id iterator, so for example,
1187+
* the FC ID can be the same as a target id
1188+
* without a huge overhead of sparse id's.
1189+
*/
11701190
if (shost->reverse_ordering)
11711191
/*
11721192
* Scan from high to low id.
11731193
*/
11741194
order_id = shost->max_id - id - 1;
11751195
else
11761196
order_id = id;
1177-
scsi_scan_target(shost, channel, order_id);
1197+
scsi_scan_target(shost, channel, order_id, lun, rescan);
11781198
}
1179-
}
1199+
else
1200+
scsi_scan_target(shost, channel, id, lun, rescan);
1201+
}
1202+
1203+
int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
1204+
unsigned int id, unsigned int lun, int rescan)
1205+
{
1206+
SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n",
1207+
__FUNCTION__, shost->host_no, channel, id, lun));
1208+
1209+
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
1210+
((id != SCAN_WILD_CARD) && (id > shost->max_id)) ||
1211+
((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
1212+
return -EINVAL;
1213+
1214+
if (channel == SCAN_WILD_CARD)
1215+
for (channel = 0; channel <= shost->max_channel; channel++)
1216+
scsi_scan_channel(shost, channel, id, lun, rescan);
1217+
else
1218+
scsi_scan_channel(shost, channel, id, lun, rescan);
1219+
return 0;
1220+
}
1221+
1222+
/**
1223+
* scsi_scan_host - scan the given adapter
1224+
* @shost: adapter to scan
1225+
**/
1226+
void scsi_scan_host(struct Scsi_Host *shost)
1227+
{
1228+
scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
1229+
SCAN_WILD_CARD, 0);
11801230
}
11811231

11821232
void scsi_forget_host(struct Scsi_Host *shost)

drivers/scsi/scsi_sysfs.c

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,43 @@
1515
#include "hosts.h"
1616

1717
#include "scsi_priv.h"
18+
#include "scsi_logging.h"
19+
20+
static int check_set(unsigned int *val, char *src)
21+
{
22+
char *last;
23+
24+
if (strncmp(src, "-", 20) == 0) {
25+
*val = SCAN_WILD_CARD;
26+
} else {
27+
/*
28+
* Doesn't check for int overflow
29+
*/
30+
*val = simple_strtoul(src, &last, 0);
31+
if (*last != '\0')
32+
return 1;
33+
}
34+
return 0;
35+
}
36+
37+
static int scsi_scan(struct Scsi_Host *shost, const char *str)
38+
{
39+
char s1[15], s2[15], s3[15], junk;
40+
unsigned int channel, id, lun;
41+
int res;
42+
43+
res = sscanf(str, "%10s %10s %10s %c", s1, s2, s3, &junk);
44+
if (res != 3)
45+
return -EINVAL;
46+
if (check_set(&channel, s1))
47+
return -EINVAL;
48+
if (check_set(&id, s2))
49+
return -EINVAL;
50+
if (check_set(&lun, s3))
51+
return -EINVAL;
52+
res = scsi_scan_host_selected(shost, channel, id, lun, 1);
53+
return res;
54+
}
1855

1956
/*
2057
* shost_show_function: macro to create an attr function that can be used to
@@ -39,6 +76,20 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
3976
/*
4077
* Create the actual show/store functions and data structures.
4178
*/
79+
80+
static ssize_t store_scan(struct class_device *class_dev, const char *buf,
81+
size_t count)
82+
{
83+
struct Scsi_Host *shost = class_to_shost(class_dev);
84+
int res;
85+
86+
res = scsi_scan(shost, buf);
87+
if (res == 0)
88+
res = count;
89+
return res;
90+
};
91+
static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
92+
4293
shost_rd_attr(unique_id, "%u\n");
4394
shost_rd_attr(host_busy, "%hu\n");
4495
shost_rd_attr(cmd_per_lun, "%hd\n");
@@ -51,6 +102,7 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
51102
&class_device_attr_cmd_per_lun,
52103
&class_device_attr_sg_tablesize,
53104
&class_device_attr_unchecked_isa_dma,
105+
&class_device_attr_scan,
54106
NULL
55107
};
56108

@@ -89,7 +141,6 @@ struct bus_type scsi_bus_type = {
89141
.match = scsi_bus_match,
90142
};
91143

92-
93144
int scsi_sysfs_register(void)
94145
{
95146
int error;
@@ -210,6 +261,24 @@ store_rescan_field (struct device *dev, const char *buf, size_t count)
210261

211262
static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field)
212263

264+
static ssize_t sdev_store_delete(struct device *dev, const char *buf,
265+
size_t count)
266+
{
267+
struct scsi_device *sdev = to_scsi_device(dev);
268+
int res = count;
269+
270+
if (sdev->access_count)
271+
/*
272+
* FIXME and scsi_proc.c: racey use of access_count,
273+
* possibly add a new arg to scsi_remove_device.
274+
*/
275+
res = -EBUSY;
276+
else
277+
scsi_remove_device(sdev);
278+
return res;
279+
};
280+
static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
281+
213282
/* Default template for device attributes. May NOT be modified */
214283
static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
215284
&dev_attr_device_blocked,
@@ -222,6 +291,7 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
222291
&dev_attr_rev,
223292
&dev_attr_online,
224293
&dev_attr_rescan,
294+
&dev_attr_delete,
225295
NULL
226296
};
227297

0 commit comments

Comments
 (0)