Blame view

drivers/scsi/scsi_sysfs.c 28.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   * scsi_sysfs.c
   *
   * SCSI sysfs interface routines.
   *
   * Created to pull SCSI mid layer sysfs routines into one file.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
9
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
  #include <linux/init.h>
  #include <linux/blkdev.h>
  #include <linux/device.h>
bc4f24014   Alan Stern   [SCSI] implement ...
13
  #include <linux/pm_runtime.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
  
  #include <scsi/scsi.h>
  #include <scsi/scsi_device.h>
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_tcq.h>
  #include <scsi/scsi_transport.h>
44818efba   Adrian Bunk   [SCSI] small clea...
20
  #include <scsi/scsi_driver.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
  
  #include "scsi_priv.h"
  #include "scsi_logging.h"
b0ed43360   Hannes Reinecke   [SCSI] add scsi_h...
24
  static struct device_type scsi_dev_type;
0ad78200b   Arjan van de Ven   [SCSI] Mark some ...
25
  static const struct {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
31
32
33
34
35
  	enum scsi_device_state	value;
  	char			*name;
  } sdev_states[] = {
  	{ SDEV_CREATED, "created" },
  	{ SDEV_RUNNING, "running" },
  	{ SDEV_CANCEL, "cancel" },
  	{ SDEV_DEL, "deleted" },
  	{ SDEV_QUIESCE, "quiesce" },
  	{ SDEV_OFFLINE,	"offline" },
  	{ SDEV_BLOCK,	"blocked" },
6f4267e3b   James Bottomley   [SCSI] Update the...
36
  	{ SDEV_CREATED_BLOCK, "created-blocked" },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
42
  };
  
  const char *scsi_device_state_name(enum scsi_device_state state)
  {
  	int i;
  	char *name = NULL;
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
43
  	for (i = 0; i < ARRAY_SIZE(sdev_states); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
  		if (sdev_states[i].value == state) {
  			name = sdev_states[i].name;
  			break;
  		}
  	}
  	return name;
  }
0ad78200b   Arjan van de Ven   [SCSI] Mark some ...
51
  static const struct {
d33018740   Mike Anderson   [SCSI] host state...
52
53
54
55
56
57
58
59
  	enum scsi_host_state	value;
  	char			*name;
  } shost_states[] = {
  	{ SHOST_CREATED, "created" },
  	{ SHOST_RUNNING, "running" },
  	{ SHOST_CANCEL, "cancel" },
  	{ SHOST_DEL, "deleted" },
  	{ SHOST_RECOVERY, "recovery" },
939647ee3   James Bottomley   [SCSI] fix oops o...
60
61
  	{ SHOST_CANCEL_RECOVERY, "cancel/recovery" },
  	{ SHOST_DEL_RECOVERY, "deleted/recovery", },
d33018740   Mike Anderson   [SCSI] host state...
62
63
64
65
66
  };
  const char *scsi_host_state_name(enum scsi_host_state state)
  {
  	int i;
  	char *name = NULL;
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
67
  	for (i = 0; i < ARRAY_SIZE(shost_states); i++) {
d33018740   Mike Anderson   [SCSI] host state...
68
69
70
71
72
73
74
  		if (shost_states[i].value == state) {
  			name = shost_states[i].name;
  			break;
  		}
  	}
  	return name;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  static int check_set(unsigned int *val, char *src)
  {
  	char *last;
  
  	if (strncmp(src, "-", 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;
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
107
108
109
110
  	if (shost->transportt->user_scan)
  		res = shost->transportt->user_scan(shost, channel, id, lun);
  	else
  		res = scsi_scan_host_selected(shost, channel, id, lun, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
116
117
118
119
  	return res;
  }
  
  /*
   * shost_show_function: macro to create an attr function that can be used to
   * show a non-bit field.
   */
  #define shost_show_function(name, field, format_string)			\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
120
121
  show_##name (struct device *dev, struct device_attribute *attr, 	\
  	     char *buf)							\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
123
  	struct Scsi_Host *shost = class_to_shost(dev);			\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
128
129
130
131
132
  	return snprintf (buf, 20, format_string, shost->field);		\
  }
  
  /*
   * shost_rd_attr: macro to create a function and attribute variable for a
   * read only field.
   */
  #define shost_rd_attr2(name, field, format_string)			\
  	shost_show_function(name, field, format_string)			\
ee959b00c   Tony Jones   SCSI: convert str...
133
  static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
138
139
140
  
  #define shost_rd_attr(field, format_string) \
  shost_rd_attr2(field, field, format_string)
  
  /*
   * Create the actual show/store functions and data structures.
   */
ee959b00c   Tony Jones   SCSI: convert str...
141
142
143
  static ssize_t
  store_scan(struct device *dev, struct device_attribute *attr,
  	   const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  {
ee959b00c   Tony Jones   SCSI: convert str...
145
  	struct Scsi_Host *shost = class_to_shost(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
152
  	int res;
  
  	res = scsi_scan(shost, buf);
  	if (res == 0)
  		res = count;
  	return res;
  };
ee959b00c   Tony Jones   SCSI: convert str...
153
  static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154

d33018740   Mike Anderson   [SCSI] host state...
155
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
156
157
  store_shost_state(struct device *dev, struct device_attribute *attr,
  		  const char *buf, size_t count)
d33018740   Mike Anderson   [SCSI] host state...
158
159
  {
  	int i;
ee959b00c   Tony Jones   SCSI: convert str...
160
  	struct Scsi_Host *shost = class_to_shost(dev);
d33018740   Mike Anderson   [SCSI] host state...
161
  	enum scsi_host_state state = 0;
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
162
  	for (i = 0; i < ARRAY_SIZE(shost_states); i++) {
d33018740   Mike Anderson   [SCSI] host state...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  		const int len = strlen(shost_states[i].name);
  		if (strncmp(shost_states[i].name, buf, len) == 0 &&
  		   buf[len] == '
  ') {
  			state = shost_states[i].value;
  			break;
  		}
  	}
  	if (!state)
  		return -EINVAL;
  
  	if (scsi_host_set_state(shost, state))
  		return -EINVAL;
  	return count;
  }
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
180
  show_shost_state(struct device *dev, struct device_attribute *attr, char *buf)
d33018740   Mike Anderson   [SCSI] host state...
181
  {
ee959b00c   Tony Jones   SCSI: convert str...
182
  	struct Scsi_Host *shost = class_to_shost(dev);
d33018740   Mike Anderson   [SCSI] host state...
183
184
185
186
187
188
189
190
  	const char *name = scsi_host_state_name(shost->shost_state);
  
  	if (!name)
  		return -EINVAL;
  
  	return snprintf(buf, 20, "%s
  ", name);
  }
ee959b00c   Tony Jones   SCSI: convert str...
191
192
193
  /* DEVICE_ATTR(state) clashes with dev_attr_state for sdev */
  struct device_attribute dev_attr_hstate =
  	__ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state);
d33018740   Mike Anderson   [SCSI] host state...
194

5dc2b89e1   FUJITA Tomonori   [SCSI] add suppor...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  static ssize_t
  show_shost_mode(unsigned int mode, char *buf)
  {
  	ssize_t len = 0;
  
  	if (mode & MODE_INITIATOR)
  		len = sprintf(buf, "%s", "Initiator");
  
  	if (mode & MODE_TARGET)
  		len += sprintf(buf + len, "%s%s", len ? ", " : "", "Target");
  
  	len += sprintf(buf + len, "
  ");
  
  	return len;
  }
ee959b00c   Tony Jones   SCSI: convert str...
211
212
213
  static ssize_t
  show_shost_supported_mode(struct device *dev, struct device_attribute *attr,
  			  char *buf)
5dc2b89e1   FUJITA Tomonori   [SCSI] add suppor...
214
  {
ee959b00c   Tony Jones   SCSI: convert str...
215
  	struct Scsi_Host *shost = class_to_shost(dev);
7a39ac3f2   James Bottomley   [SCSI] make suppo...
216
  	unsigned int supported_mode = shost->hostt->supported_mode;
5dc2b89e1   FUJITA Tomonori   [SCSI] add suppor...
217

7a39ac3f2   James Bottomley   [SCSI] make suppo...
218
219
220
221
222
  	if (supported_mode == MODE_UNKNOWN)
  		/* by default this should be initiator */
  		supported_mode = MODE_INITIATOR;
  
  	return show_shost_mode(supported_mode, buf);
5dc2b89e1   FUJITA Tomonori   [SCSI] add suppor...
223
  }
ee959b00c   Tony Jones   SCSI: convert str...
224
  static DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL);
5dc2b89e1   FUJITA Tomonori   [SCSI] add suppor...
225

ee959b00c   Tony Jones   SCSI: convert str...
226
227
228
  static ssize_t
  show_shost_active_mode(struct device *dev,
  		       struct device_attribute *attr, char *buf)
5dc2b89e1   FUJITA Tomonori   [SCSI] add suppor...
229
  {
ee959b00c   Tony Jones   SCSI: convert str...
230
  	struct Scsi_Host *shost = class_to_shost(dev);
5dc2b89e1   FUJITA Tomonori   [SCSI] add suppor...
231
232
233
234
235
236
237
  
  	if (shost->active_mode == MODE_UNKNOWN)
  		return snprintf(buf, 20, "unknown
  ");
  	else
  		return show_shost_mode(shost->active_mode, buf);
  }
ee959b00c   Tony Jones   SCSI: convert str...
238
  static DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL);
5dc2b89e1   FUJITA Tomonori   [SCSI] add suppor...
239

294436914   Vikas Chaudhary   [SCSI] scsi: Adde...
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  static int check_reset_type(char *str)
  {
  	if (strncmp(str, "adapter", 10) == 0)
  		return SCSI_ADAPTER_RESET;
  	else if (strncmp(str, "firmware", 10) == 0)
  		return SCSI_FIRMWARE_RESET;
  	else
  		return 0;
  }
  
  static ssize_t
  store_host_reset(struct device *dev, struct device_attribute *attr,
  		const char *buf, size_t count)
  {
  	struct Scsi_Host *shost = class_to_shost(dev);
  	struct scsi_host_template *sht = shost->hostt;
  	int ret = -EINVAL;
  	char str[10];
  	int type;
  
  	sscanf(buf, "%s", str);
  	type = check_reset_type(str);
  
  	if (!type)
  		goto exit_store_host_reset;
  
  	if (sht->host_reset)
  		ret = sht->host_reset(shost, type);
  
  exit_store_host_reset:
  	if (ret == 0)
  		ret = count;
  	return ret;
  }
  
  static DEVICE_ATTR(host_reset, S_IWUSR, NULL, store_host_reset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
281
  shost_rd_attr(unique_id, "%u
  ");
  shost_rd_attr(host_busy, "%hu
  ");
  shost_rd_attr(cmd_per_lun, "%hd
  ");
ed632da84   James Bottomley   [SCSI] add can_qu...
282
283
  shost_rd_attr(can_queue, "%hd
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  shost_rd_attr(sg_tablesize, "%hu
  ");
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
286
287
  shost_rd_attr(sg_prot_tablesize, "%hu
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
  shost_rd_attr(unchecked_isa_dma, "%d
  ");
4469f9878   Martin K. Petersen   [SCSI] Host prote...
290
291
292
293
  shost_rd_attr(prot_capabilities, "%u
  ");
  shost_rd_attr(prot_guard_type, "%hd
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
  shost_rd_attr2(proc_name, hostt->proc_name, "%s
  ");
f7120a4f7   Hannes Reinecke   [SCSI] use defaul...
296
297
298
299
300
301
  static struct attribute *scsi_sysfs_shost_attrs[] = {
  	&dev_attr_unique_id.attr,
  	&dev_attr_host_busy.attr,
  	&dev_attr_cmd_per_lun.attr,
  	&dev_attr_can_queue.attr,
  	&dev_attr_sg_tablesize.attr,
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
302
  	&dev_attr_sg_prot_tablesize.attr,
f7120a4f7   Hannes Reinecke   [SCSI] use defaul...
303
304
305
306
307
308
  	&dev_attr_unchecked_isa_dma.attr,
  	&dev_attr_proc_name.attr,
  	&dev_attr_scan.attr,
  	&dev_attr_hstate.attr,
  	&dev_attr_supported_mode.attr,
  	&dev_attr_active_mode.attr,
4469f9878   Martin K. Petersen   [SCSI] Host prote...
309
310
  	&dev_attr_prot_capabilities.attr,
  	&dev_attr_prot_guard_type.attr,
294436914   Vikas Chaudhary   [SCSI] scsi: Adde...
311
  	&dev_attr_host_reset.attr,
f7120a4f7   Hannes Reinecke   [SCSI] use defaul...
312
313
314
315
316
317
  	NULL
  };
  
  struct attribute_group scsi_shost_attr_group = {
  	.attrs =	scsi_sysfs_shost_attrs,
  };
a4dbd6740   David Brownell   driver model: con...
318
  const struct attribute_group *scsi_sysfs_shost_attr_groups[] = {
f7120a4f7   Hannes Reinecke   [SCSI] use defaul...
319
  	&scsi_shost_attr_group,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
  	NULL
  };
ee959b00c   Tony Jones   SCSI: convert str...
322
  static void scsi_device_cls_release(struct device *class_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
327
328
  {
  	struct scsi_device *sdev;
  
  	sdev = class_to_sdev(class_dev);
  	put_device(&sdev->sdev_gendev);
  }
65f27f384   David Howells   WorkStruct: Pass ...
329
  static void scsi_device_dev_release_usercontext(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
333
  {
  	struct scsi_device *sdev;
  	struct device *parent;
  	struct scsi_target *starget;
a341cd0f6   Jeff Garzik   SCSI: add asynchr...
334
  	struct list_head *this, *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  	unsigned long flags;
65f27f384   David Howells   WorkStruct: Pass ...
336
337
338
  	sdev = container_of(work, struct scsi_device, ew.work);
  
  	parent = sdev->sdev_gendev.parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
343
344
345
346
  	starget = to_scsi_target(parent);
  
  	spin_lock_irqsave(sdev->host->host_lock, flags);
  	starget->reap_ref++;
  	list_del(&sdev->siblings);
  	list_del(&sdev->same_target_siblings);
  	list_del(&sdev->starved_entry);
  	spin_unlock_irqrestore(sdev->host->host_lock, flags);
a341cd0f6   Jeff Garzik   SCSI: add asynchr...
347
348
349
350
351
352
353
354
355
  	cancel_work_sync(&sdev->event_work);
  
  	list_for_each_safe(this, tmp, &sdev->event_list) {
  		struct scsi_event *evt;
  
  		evt = list_entry(this, struct scsi_event, node);
  		list_del(&evt->node);
  		kfree(evt);
  	}
e73e079bf   James Bottomley   [SCSI] Fix oops c...
356
  	blk_put_queue(sdev->request_queue);
86cbfb560   James Bottomley   [SCSI] put strict...
357
358
  	/* NULL queue means the device can't be used */
  	sdev->request_queue = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
364
365
366
367
  
  	scsi_target_reap(scsi_target(sdev));
  
  	kfree(sdev->inquiry);
  	kfree(sdev);
  
  	if (parent)
  		put_device(parent);
  }
65110b216   James Bottomley   [SCSI] fix wrong ...
368
369
  static void scsi_device_dev_release(struct device *dev)
  {
ffedb4522   James Bottomley   [SCSI] fix scsi p...
370
  	struct scsi_device *sdp = to_scsi_device(dev);
65f27f384   David Howells   WorkStruct: Pass ...
371
  	execute_in_process_context(scsi_device_dev_release_usercontext,
ffedb4522   James Bottomley   [SCSI] fix scsi p...
372
  				   &sdp->ew);
65110b216   James Bottomley   [SCSI] fix wrong ...
373
  }
52c1da395   Adrian Bunk   [PATCH] make vari...
374
  static struct class sdev_class = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  	.name		= "scsi_device",
ee959b00c   Tony Jones   SCSI: convert str...
376
  	.dev_release	= scsi_device_cls_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
381
  };
  
  /* all probing is done in the individual ->probe routines */
  static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
  {
b0ed43360   Hannes Reinecke   [SCSI] add scsi_h...
382
383
384
385
386
387
  	struct scsi_device *sdp;
  
  	if (dev->type != &scsi_dev_type)
  		return 0;
  
  	sdp = to_scsi_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
390
391
  	if (sdp->no_uld_attach)
  		return 0;
  	return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
  }
7eff2e7a8   Kay Sievers   Driver core: chan...
392
  static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
d7b8bcb0a   Michael Tokarev   [SCSI] modalias f...
393
  {
1f42ea7bc   James Bottomley   [SCSI] fix interm...
394
395
396
397
398
399
  	struct scsi_device *sdev;
  
  	if (dev->type != &scsi_dev_type)
  		return 0;
  
  	sdev = to_scsi_device(dev);
d7b8bcb0a   Michael Tokarev   [SCSI] modalias f...
400

7eff2e7a8   Kay Sievers   Driver core: chan...
401
  	add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
d7b8bcb0a   Michael Tokarev   [SCSI] modalias f...
402
403
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
  struct bus_type scsi_bus_type = {
          .name		= "scsi",
          .match		= scsi_bus_match,
d7b8bcb0a   Michael Tokarev   [SCSI] modalias f...
407
  	.uevent		= scsi_bus_uevent,
aa3386015   Rafael J. Wysocki   PM: Remove CONFIG...
408
  #ifdef CONFIG_PM
db5bd1e0b   Alan Stern   [SCSI] convert to...
409
  	.pm		= &scsi_bus_pm_ops,
e6da54d84   Alan Stern   SCSI: remove fake...
410
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  };
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
412
  EXPORT_SYMBOL_GPL(scsi_bus_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
  
  int scsi_sysfs_register(void)
  {
  	int error;
  
  	error = bus_register(&scsi_bus_type);
  	if (!error) {
  		error = class_register(&sdev_class);
  		if (error)
  			bus_unregister(&scsi_bus_type);
  	}
  
  	return error;
  }
  
  void scsi_sysfs_unregister(void)
  {
  	class_unregister(&sdev_class);
  	bus_unregister(&scsi_bus_type);
  }
  
  /*
   * sdev_show_function: macro to create an attr function that can be used to
   * show a non-bit field.
   */
  #define sdev_show_function(field, format_string)				\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
440
441
  sdev_show_##field (struct device *dev, struct device_attribute *attr,	\
  		   char *buf)						\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  {									\
  	struct scsi_device *sdev;					\
  	sdev = to_scsi_device(dev);					\
  	return snprintf (buf, 20, format_string, sdev->field);		\
  }									\
  
  /*
   * sdev_rd_attr: macro to create a function and attribute variable for a
   * read only field.
   */
  #define sdev_rd_attr(field, format_string)				\
  	sdev_show_function(field, format_string)			\
  static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL);
  
  
  /*
160e7f671   Tomohiro Kusumi   [SCSI] fix sdev_r...
458
   * sdev_rw_attr: create a function and attribute variable for a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
463
464
   * read/write field.
   */
  #define sdev_rw_attr(field, format_string)				\
  	sdev_show_function(field, format_string)				\
  									\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
465
466
  sdev_store_##field (struct device *dev, struct device_attribute *attr,	\
  		    const char *buf, size_t count)			\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
  {									\
  	struct scsi_device *sdev;					\
  	sdev = to_scsi_device(dev);					\
160e7f671   Tomohiro Kusumi   [SCSI] fix sdev_r...
470
  	sscanf (buf, format_string, &sdev->field);			\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  	return count;							\
  }									\
  static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field);
  
  /* Currently we don't export bit fields, but we might in future,
   * so leave this code in */
  #if 0
  /*
   * sdev_rd_attr: create a function and attribute variable for a
   * read/write bit field.
   */
  #define sdev_rw_attr_bit(field)						\
  	sdev_show_function(field, "%d
  ")					\
  									\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
487
488
  sdev_store_##field (struct device *dev, struct device_attribute *attr,	\
  		    const char *buf, size_t count)			\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
  {									\
  	int ret;							\
  	struct scsi_device *sdev;					\
  	ret = scsi_sdev_check_buf_bit(buf);				\
  	if (ret >= 0)	{						\
  		sdev = to_scsi_device(dev);				\
  		sdev->field = ret;					\
  		ret = count;						\
  	}								\
  	return ret;							\
  }									\
  static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field);
  
  /*
   * scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
   * else return -EINVAL.
   */
  static int scsi_sdev_check_buf_bit(const char *buf)
  {
  	if ((buf[1] == '\0') || ((buf[1] == '
  ') && (buf[2] == '\0'))) {
  		if (buf[0] == '1')
  			return 1;
  		else if (buf[0] == '0')
  			return 0;
  		else 
  			return -EINVAL;
  	} else
  		return -EINVAL;
  }
  #endif
  /*
   * Create the actual show/store functions and data structures.
   */
  sdev_rd_attr (device_blocked, "%d
  ");
  sdev_rd_attr (queue_depth, "%d
  ");
  sdev_rd_attr (type, "%d
  ");
  sdev_rd_attr (scsi_level, "%d
  ");
  sdev_rd_attr (vendor, "%.8s
  ");
  sdev_rd_attr (model, "%.16s
  ");
  sdev_rd_attr (rev, "%.4s
  ");
242f9dcb8   Jens Axboe   block: unify requ...
537
538
539
  /*
   * TODO: can we make these symlinks to the block layer ones?
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
  static ssize_t
10523b3b8   Yani Ioannou   [PATCH] Driver Co...
541
  sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
  {
  	struct scsi_device *sdev;
  	sdev = to_scsi_device(dev);
242f9dcb8   Jens Axboe   block: unify requ...
545
546
  	return snprintf(buf, 20, "%d
  ", sdev->request_queue->rq_timeout / HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
549
  }
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
550
551
  sdev_store_timeout (struct device *dev, struct device_attribute *attr,
  		    const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
555
556
557
  {
  	struct scsi_device *sdev;
  	int timeout;
  	sdev = to_scsi_device(dev);
  	sscanf (buf, "%d
  ", &timeout);
242f9dcb8   Jens Axboe   block: unify requ...
558
  	blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
563
  	return count;
  }
  static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
564
565
  store_rescan_field (struct device *dev, struct device_attribute *attr,
  		    const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
570
  {
  	scsi_rescan_device(dev);
  	return count;
  }
  static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);
d9a9cdfb0   Alan Stern   [PATCH] sysfs and...
571
572
573
574
  static void sdev_store_delete_callback(struct device *dev)
  {
  	scsi_remove_device(to_scsi_device(dev));
  }
ee959b00c   Tony Jones   SCSI: convert str...
575
576
577
  static ssize_t
  sdev_store_delete(struct device *dev, struct device_attribute *attr,
  		  const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
  {
d9a9cdfb0   Alan Stern   [PATCH] sysfs and...
579
580
581
582
583
584
585
586
  	int rc;
  
  	/* An attribute cannot be unregistered by one of its own methods,
  	 * so we have to use this roundabout approach.
  	 */
  	rc = device_schedule_callback(dev, sdev_store_delete_callback);
  	if (rc)
  		count = rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
589
590
591
  	return count;
  };
  static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
592
593
  store_state_field(struct device *dev, struct device_attribute *attr,
  		  const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
597
  {
  	int i;
  	struct scsi_device *sdev = to_scsi_device(dev);
  	enum scsi_device_state state = 0;
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
598
  	for (i = 0; i < ARRAY_SIZE(sdev_states); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
  		const int len = strlen(sdev_states[i].name);
  		if (strncmp(sdev_states[i].name, buf, len) == 0 &&
  		   buf[len] == '
  ') {
  			state = sdev_states[i].value;
  			break;
  		}
  	}
  	if (!state)
  		return -EINVAL;
  
  	if (scsi_device_set_state(sdev, state))
  		return -EINVAL;
  	return count;
  }
  
  static ssize_t
10523b3b8   Yani Ioannou   [PATCH] Driver Co...
616
  show_state_field(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
619
620
621
622
623
624
625
626
627
628
629
630
  {
  	struct scsi_device *sdev = to_scsi_device(dev);
  	const char *name = scsi_device_state_name(sdev->sdev_state);
  
  	if (!name)
  		return -EINVAL;
  
  	return snprintf(buf, 20, "%s
  ", name);
  }
  
  static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_state_field, store_state_field);
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
631
632
  show_queue_type_field(struct device *dev, struct device_attribute *attr,
  		      char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  {
  	struct scsi_device *sdev = to_scsi_device(dev);
  	const char *name = "none";
  
  	if (sdev->ordered_tags)
  		name = "ordered";
  	else if (sdev->simple_tags)
  		name = "simple";
  
  	return snprintf(buf, 20, "%s
  ", name);
  }
  
  static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL);
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
649
  show_iostat_counterbits(struct device *dev, struct device_attribute *attr, 				char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
654
655
656
657
658
  {
  	return snprintf(buf, 20, "%d
  ", (int)sizeof(atomic_t) * 8);
  }
  
  static DEVICE_ATTR(iocounterbits, S_IRUGO, show_iostat_counterbits, NULL);
  
  #define show_sdev_iostat(field)						\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
659
660
  show_iostat_##field(struct device *dev, struct device_attribute *attr,	\
  		    char *buf)						\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
663
664
665
666
667
668
669
670
671
  {									\
  	struct scsi_device *sdev = to_scsi_device(dev);			\
  	unsigned long long count = atomic_read(&sdev->field);		\
  	return snprintf(buf, 20, "0x%llx
  ", count);			\
  }									\
  static DEVICE_ATTR(field, S_IRUGO, show_iostat_##field, NULL)
  
  show_sdev_iostat(iorequest_cnt);
  show_sdev_iostat(iodone_cnt);
  show_sdev_iostat(ioerr_cnt);
d7b8bcb0a   Michael Tokarev   [SCSI] modalias f...
672
673
674
675
676
677
678
679
680
  static ssize_t
  sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
  {
  	struct scsi_device *sdev;
  	sdev = to_scsi_device(dev);
  	return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "
  ", sdev->type);
  }
  static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681

a341cd0f6   Jeff Garzik   SCSI: add asynchr...
682
683
684
  #define DECLARE_EVT_SHOW(name, Cap_name)				\
  static ssize_t								\
  sdev_show_evt_##name(struct device *dev, struct device_attribute *attr,	\
ee959b00c   Tony Jones   SCSI: convert str...
685
  		     char *buf)						\
a341cd0f6   Jeff Garzik   SCSI: add asynchr...
686
687
688
689
690
691
692
693
694
  {									\
  	struct scsi_device *sdev = to_scsi_device(dev);			\
  	int val = test_bit(SDEV_EVT_##Cap_name, sdev->supported_events);\
  	return snprintf(buf, 20, "%d
  ", val);				\
  }
  
  #define DECLARE_EVT_STORE(name, Cap_name)				\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
695
  sdev_store_evt_##name(struct device *dev, struct device_attribute *attr,\
a341cd0f6   Jeff Garzik   SCSI: add asynchr...
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  		      const char *buf, size_t count)			\
  {									\
  	struct scsi_device *sdev = to_scsi_device(dev);			\
  	int val = simple_strtoul(buf, NULL, 0);				\
  	if (val == 0)							\
  		clear_bit(SDEV_EVT_##Cap_name, sdev->supported_events);	\
  	else if (val == 1)						\
  		set_bit(SDEV_EVT_##Cap_name, sdev->supported_events);	\
  	else								\
  		return -EINVAL;						\
  	return count;							\
  }
  
  #define DECLARE_EVT(name, Cap_name)					\
  	DECLARE_EVT_SHOW(name, Cap_name)				\
  	DECLARE_EVT_STORE(name, Cap_name)				\
  	static DEVICE_ATTR(evt_##name, S_IRUGO, sdev_show_evt_##name,	\
  			   sdev_store_evt_##name);
  #define REF_EVT(name) &dev_attr_evt_##name.attr
  
  DECLARE_EVT(media_change, MEDIA_CHANGE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
  /* Default template for device attributes.  May NOT be modified */
bfd129445   Kay Sievers   [SCSI] switch sde...
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
  static struct attribute *scsi_sdev_attrs[] = {
  	&dev_attr_device_blocked.attr,
  	&dev_attr_type.attr,
  	&dev_attr_scsi_level.attr,
  	&dev_attr_vendor.attr,
  	&dev_attr_model.attr,
  	&dev_attr_rev.attr,
  	&dev_attr_rescan.attr,
  	&dev_attr_delete.attr,
  	&dev_attr_state.attr,
  	&dev_attr_timeout.attr,
  	&dev_attr_iocounterbits.attr,
  	&dev_attr_iorequest_cnt.attr,
  	&dev_attr_iodone_cnt.attr,
  	&dev_attr_ioerr_cnt.attr,
  	&dev_attr_modalias.attr,
a341cd0f6   Jeff Garzik   SCSI: add asynchr...
734
  	REF_EVT(media_change),
bfd129445   Kay Sievers   [SCSI] switch sde...
735
736
737
738
739
740
  	NULL
  };
  
  static struct attribute_group scsi_sdev_attr_group = {
  	.attrs =	scsi_sdev_attrs,
  };
a4dbd6740   David Brownell   driver model: con...
741
  static const struct attribute_group *scsi_sdev_attr_groups[] = {
bfd129445   Kay Sievers   [SCSI] switch sde...
742
  	&scsi_sdev_attr_group,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
  	NULL
  };
ee959b00c   Tony Jones   SCSI: convert str...
745
746
747
  static ssize_t
  sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr,
  			  const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
749
750
751
752
753
754
755
756
757
758
759
  {
  	int depth, retval;
  	struct scsi_device *sdev = to_scsi_device(dev);
  	struct scsi_host_template *sht = sdev->host->hostt;
  
  	if (!sht->change_queue_depth)
  		return -EINVAL;
  
  	depth = simple_strtoul(buf, NULL, 0);
  
  	if (depth < 1)
  		return -EINVAL;
e881a172d   Mike Christie   [SCSI] modify cha...
760
761
  	retval = sht->change_queue_depth(sdev, depth,
  					 SCSI_QDEPTH_DEFAULT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
  	if (retval < 0)
  		return retval;
4a84067db   Vasu Dev   [SCSI] add queue_...
764
  	sdev->max_queue_depth = sdev->queue_depth;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
768
769
770
  	return count;
  }
  
  static struct device_attribute sdev_attr_queue_depth_rw =
  	__ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
  	       sdev_store_queue_depth_rw);
ee959b00c   Tony Jones   SCSI: convert str...
771
  static ssize_t
4a84067db   Vasu Dev   [SCSI] add queue_...
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
  sdev_show_queue_ramp_up_period(struct device *dev,
  			       struct device_attribute *attr,
  			       char *buf)
  {
  	struct scsi_device *sdev;
  	sdev = to_scsi_device(dev);
  	return snprintf(buf, 20, "%u
  ",
  			jiffies_to_msecs(sdev->queue_ramp_up_period));
  }
  
  static ssize_t
  sdev_store_queue_ramp_up_period(struct device *dev,
  				struct device_attribute *attr,
  				const char *buf, size_t count)
  {
  	struct scsi_device *sdev = to_scsi_device(dev);
  	unsigned long period;
  
  	if (strict_strtoul(buf, 10, &period))
  		return -EINVAL;
  
  	sdev->queue_ramp_up_period = msecs_to_jiffies(period);
  	return period;
  }
  
  static struct device_attribute sdev_attr_queue_ramp_up_period =
  	__ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
  	       sdev_show_queue_ramp_up_period,
  	       sdev_store_queue_ramp_up_period);
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
804
805
  sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr,
  			 const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
  {
  	struct scsi_device *sdev = to_scsi_device(dev);
  	struct scsi_host_template *sht = sdev->host->hostt;
  	int tag_type = 0, retval;
  	int prev_tag_type = scsi_get_tag_type(sdev);
  
  	if (!sdev->tagged_supported || !sht->change_queue_type)
  		return -EINVAL;
  
  	if (strncmp(buf, "ordered", 7) == 0)
  		tag_type = MSG_ORDERED_TAG;
  	else if (strncmp(buf, "simple", 6) == 0)
  		tag_type = MSG_SIMPLE_TAG;
  	else if (strncmp(buf, "none", 4) != 0)
  		return -EINVAL;
  
  	if (tag_type == prev_tag_type)
  		return count;
  
  	retval = sht->change_queue_type(sdev, tag_type);
  	if (retval < 0)
  		return retval;
  
  	return count;
  }
643eb2d93   James Bottomley   [SCSI] rework scs...
831
832
833
834
835
836
837
838
839
840
841
  static int scsi_target_add(struct scsi_target *starget)
  {
  	int error;
  
  	if (starget->state != STARGET_CREATED)
  		return 0;
  
  	error = device_add(&starget->dev);
  	if (error) {
  		dev_err(&starget->dev, "target device_add failed, error %d
  ", error);
643eb2d93   James Bottomley   [SCSI] rework scs...
842
843
844
845
  		return error;
  	}
  	transport_add_device(&starget->dev);
  	starget->state = STARGET_RUNNING;
bc4f24014   Alan Stern   [SCSI] implement ...
846
847
848
  	pm_runtime_set_active(&starget->dev);
  	pm_runtime_enable(&starget->dev);
  	device_enable_async_suspend(&starget->dev);
643eb2d93   James Bottomley   [SCSI] rework scs...
849
850
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
853
  static struct device_attribute sdev_attr_queue_type_rw =
  	__ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
  	       sdev_store_queue_type_rw);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
855
856
857
858
859
860
861
862
863
  /**
   * scsi_sysfs_add_sdev - add scsi device to sysfs
   * @sdev:	scsi_device to add
   *
   * Return value:
   * 	0 on Success / non-zero on Failure
   **/
  int scsi_sysfs_add_sdev(struct scsi_device *sdev)
  {
  	int error, i;
80ed71ce1   James Bottomley   [SCSI] bsg: separ...
864
  	struct request_queue *rq = sdev->request_queue;
643eb2d93   James Bottomley   [SCSI] rework scs...
865
  	struct scsi_target *starget = sdev->sdev_target;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866

ee37e09d8   Alan Stern   [SCSI] fix duplic...
867
868
  	error = scsi_device_set_state(sdev, SDEV_RUNNING);
  	if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
  		return error;
643eb2d93   James Bottomley   [SCSI] rework scs...
870
871
872
873
874
  	error = scsi_target_add(starget);
  	if (error)
  		return error;
  
  	transport_configure_device(&starget->dev);
bc4f24014   Alan Stern   [SCSI] implement ...
875

4cb077d93   Rafael J. Wysocki   PM: Allow SCSI de...
876
  	device_enable_async_suspend(&sdev->sdev_gendev);
bc4f24014   Alan Stern   [SCSI] implement ...
877
878
879
880
881
882
883
884
885
886
887
  	scsi_autopm_get_target(starget);
  	pm_runtime_set_active(&sdev->sdev_gendev);
  	pm_runtime_forbid(&sdev->sdev_gendev);
  	pm_runtime_enable(&sdev->sdev_gendev);
  	scsi_autopm_put_target(starget);
  
  	/* The following call will keep sdev active indefinitely, until
  	 * its driver does a corresponding scsi_autopm_pm_device().  Only
  	 * drivers supporting autosuspend will do this.
  	 */
  	scsi_autopm_get_device(sdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
889
  	error = device_add(&sdev->sdev_gendev);
  	if (error) {
73d8c34f3   Alan Stern   SCSI: improve two...
890
891
892
  		sdev_printk(KERN_INFO, sdev,
  				"failed to add device: %d
  ", error);
ee37e09d8   Alan Stern   [SCSI] fix duplic...
893
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
  	}
4cb077d93   Rafael J. Wysocki   PM: Allow SCSI de...
895
  	device_enable_async_suspend(&sdev->sdev_dev);
ee959b00c   Tony Jones   SCSI: convert str...
896
  	error = device_add(&sdev->sdev_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
  	if (error) {
73d8c34f3   Alan Stern   SCSI: improve two...
898
899
900
  		sdev_printk(KERN_INFO, sdev,
  				"failed to add class device: %d
  ", error);
860dc7360   James Bottomley   [SCSI] fix async ...
901
  		device_del(&sdev->sdev_gendev);
ee37e09d8   Alan Stern   [SCSI] fix duplic...
902
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  	}
860dc7360   James Bottomley   [SCSI] fix async ...
904
905
  	transport_add_device(&sdev->sdev_gendev);
  	sdev->is_visible = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906

bfd129445   Kay Sievers   [SCSI] switch sde...
907
  	/* create queue files, which may be writable, depending on the host */
4a84067db   Vasu Dev   [SCSI] add queue_...
908
909
910
911
912
913
  	if (sdev->host->hostt->change_queue_depth) {
  		error = device_create_file(&sdev->sdev_gendev,
  					   &sdev_attr_queue_depth_rw);
  		error = device_create_file(&sdev->sdev_gendev,
  					   &sdev_attr_queue_ramp_up_period);
  	}
bfd129445   Kay Sievers   [SCSI] switch sde...
914
915
  	else
  		error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
860dc7360   James Bottomley   [SCSI] fix async ...
916
  	if (error)
ee37e09d8   Alan Stern   [SCSI] fix duplic...
917
  		return error;
860dc7360   James Bottomley   [SCSI] fix async ...
918

bfd129445   Kay Sievers   [SCSI] switch sde...
919
920
921
922
  	if (sdev->host->hostt->change_queue_type)
  		error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
  	else
  		error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
860dc7360   James Bottomley   [SCSI] fix async ...
923
  	if (error)
ee37e09d8   Alan Stern   [SCSI] fix duplic...
924
  		return error;
bfd129445   Kay Sievers   [SCSI] switch sde...
925

97f46ae45   FUJITA Tomonori   [SCSI] bsg: add r...
926
  	error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
80ed71ce1   James Bottomley   [SCSI] bsg: separ...
927
928
  
  	if (error)
860dc7360   James Bottomley   [SCSI] fix async ...
929
930
  		/* we're treating error on bsg register as non-fatal,
  		 * so pretend nothing went wrong */
80ed71ce1   James Bottomley   [SCSI] bsg: separ...
931
932
933
  		sdev_printk(KERN_INFO, sdev,
  			    "Failed to register bsg queue, errno=%d
  ", error);
bfd129445   Kay Sievers   [SCSI] switch sde...
934
  	/* add additional host specific attributes */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
936
  	if (sdev->host->hostt->sdev_attrs) {
  		for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
bfd129445   Kay Sievers   [SCSI] switch sde...
937
  			error = device_create_file(&sdev->sdev_gendev,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
  					sdev->host->hostt->sdev_attrs[i]);
860dc7360   James Bottomley   [SCSI] fix async ...
939
  			if (error)
ee37e09d8   Alan Stern   [SCSI] fix duplic...
940
  				return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
942
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
  	return error;
  }
903f4fed8   Alan Stern   [SCSI] fix caller...
946
  void __scsi_remove_device(struct scsi_device *sdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
  {
df133c212   James Bottomley   [SCSI] Fix transp...
948
  	struct device *dev = &sdev->sdev_gendev;
860dc7360   James Bottomley   [SCSI] fix async ...
949
950
951
  	if (sdev->is_visible) {
  		if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952

860dc7360   James Bottomley   [SCSI] fix async ...
953
954
955
956
957
958
  		bsg_unregister_queue(sdev->request_queue);
  		device_unregister(&sdev->sdev_dev);
  		transport_remove_device(dev);
  		device_del(dev);
  	} else
  		put_device(&sdev->sdev_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
960
961
  	scsi_device_set_state(sdev, SDEV_DEL);
  	if (sdev->host->hostt->slave_destroy)
  		sdev->host->hostt->slave_destroy(sdev);
df133c212   James Bottomley   [SCSI] Fix transp...
962
  	transport_destroy_device(dev);
86cbfb560   James Bottomley   [SCSI] put strict...
963
964
965
966
967
968
  
  	/* cause the request function to reject all I/O requests */
  	sdev->request_queue->queuedata = NULL;
  
  	/* Freeing the queue signals to block that we're done */
  	scsi_free_queue(sdev->request_queue);
df133c212   James Bottomley   [SCSI] Fix transp...
969
  	put_device(dev);
903f4fed8   Alan Stern   [SCSI] fix caller...
970
971
972
973
974
975
976
977
  }
  
  /**
   * scsi_remove_device - unregister a device from the scsi bus
   * @sdev:	scsi_device to unregister
   **/
  void scsi_remove_device(struct scsi_device *sdev)
  {
541950027   Alan Stern   [SCSI] fix use af...
978
  	struct Scsi_Host *shost = sdev->host;
0b9506723   Arjan van de Ven   [SCSI] turn most ...
979
  	mutex_lock(&shost->scan_mutex);
903f4fed8   Alan Stern   [SCSI] fix caller...
980
  	__scsi_remove_device(sdev);
0b9506723   Arjan van de Ven   [SCSI] turn most ...
981
  	mutex_unlock(&shost->scan_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
  }
  EXPORT_SYMBOL(scsi_remove_device);
44818efba   Adrian Bunk   [SCSI] small clea...
984
  static void __scsi_remove_target(struct scsi_target *starget)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
986
987
  {
  	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
  	unsigned long flags;
a64358db1   Alan Stern   [SCSI] SCSI scann...
988
  	struct scsi_device *sdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
990
991
  
  	spin_lock_irqsave(shost->host_lock, flags);
  	starget->reap_ref++;
a64358db1   Alan Stern   [SCSI] SCSI scann...
992
993
   restart:
  	list_for_each_entry(sdev, &shost->__devices, siblings) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
  		if (sdev->channel != starget->channel ||
a64358db1   Alan Stern   [SCSI] SCSI scann...
995
  		    sdev->id != starget->id ||
546ae796b   Christof Schmitt   [SCSI] Fix race w...
996
  		    scsi_device_get(sdev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
998
999
  			continue;
  		spin_unlock_irqrestore(shost->host_lock, flags);
  		scsi_remove_device(sdev);
546ae796b   Christof Schmitt   [SCSI] Fix race w...
1000
  		scsi_device_put(sdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
  		spin_lock_irqsave(shost->host_lock, flags);
a64358db1   Alan Stern   [SCSI] SCSI scann...
1002
  		goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
1004
1005
1006
  	}
  	spin_unlock_irqrestore(shost->host_lock, flags);
  	scsi_target_reap(starget);
  }
20b1e6742   Patrick Mochel   [PATCH] Use devic...
1007
1008
1009
1010
1011
1012
  static int __remove_child (struct device * dev, void * data)
  {
  	if (scsi_is_target_device(dev))
  		__scsi_remove_target(to_scsi_target(dev));
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
  /**
   * scsi_remove_target - try to remove a target and all its devices
   * @dev: generic starget or parent of generic stargets to be removed
   *
   * Note: This is slightly racy.  It is possible that if the user
   * requests the addition of another device then the target won't be
   * removed.
   */
  void scsi_remove_target(struct device *dev)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
1026
  	if (scsi_is_target_device(dev)) {
  		__scsi_remove_target(to_scsi_target(dev));
  		return;
  	}
41511704b   Alan Stern   [SCSI] eliminate ...
1027
  	get_device(dev);
20b1e6742   Patrick Mochel   [PATCH] Use devic...
1028
  	device_for_each_child(dev, NULL, __remove_child);
41511704b   Alan Stern   [SCSI] eliminate ...
1029
  	put_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
  }
  EXPORT_SYMBOL(scsi_remove_target);
  
  int scsi_register_driver(struct device_driver *drv)
  {
  	drv->bus = &scsi_bus_type;
  
  	return driver_register(drv);
  }
  EXPORT_SYMBOL(scsi_register_driver);
  
  int scsi_register_interface(struct class_interface *intf)
  {
  	intf->class = &sdev_class;
  
  	return class_interface_register(intf);
  }
  EXPORT_SYMBOL(scsi_register_interface);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
1050
  /**
   * scsi_sysfs_add_host - add scsi host to subsystem
   * @shost:     scsi host struct to add to subsystem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
1052
1053
1054
   **/
  int scsi_sysfs_add_host(struct Scsi_Host *shost)
  {
  	int error, i;
f7120a4f7   Hannes Reinecke   [SCSI] use defaul...
1055
  	/* add host specific attributes */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
1057
  	if (shost->hostt->shost_attrs) {
  		for (i = 0; shost->hostt->shost_attrs[i]; i++) {
ee959b00c   Tony Jones   SCSI: convert str...
1058
  			error = device_create_file(&shost->shost_dev,
f7120a4f7   Hannes Reinecke   [SCSI] use defaul...
1059
  					shost->hostt->shost_attrs[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
1062
1063
1064
1065
  			if (error)
  				return error;
  		}
  	}
  
  	transport_register_device(&shost->shost_gendev);
d52b3815a   James Bottomley   [SCSI] add missin...
1066
  	transport_configure_device(&shost->shost_gendev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
  	return 0;
  }
bfd129445   Kay Sievers   [SCSI] switch sde...
1069
1070
1071
1072
1073
  static struct device_type scsi_dev_type = {
  	.name =		"scsi_device",
  	.release =	scsi_device_dev_release,
  	.groups =	scsi_sdev_attr_groups,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
1075
1076
1077
1078
1079
1080
1081
  void scsi_sysfs_device_initialize(struct scsi_device *sdev)
  {
  	unsigned long flags;
  	struct Scsi_Host *shost = sdev->host;
  	struct scsi_target  *starget = sdev->sdev_target;
  
  	device_initialize(&sdev->sdev_gendev);
  	sdev->sdev_gendev.bus = &scsi_bus_type;
bfd129445   Kay Sievers   [SCSI] switch sde...
1082
  	sdev->sdev_gendev.type = &scsi_dev_type;
71610f55f   Kay Sievers   [SCSI] struct dev...
1083
1084
  	dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%d",
  		     sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
ee959b00c   Tony Jones   SCSI: convert str...
1085
  	device_initialize(&sdev->sdev_dev);
37e6ba007   James Bottomley   [SCSI] fix memory...
1086
  	sdev->sdev_dev.parent = get_device(&sdev->sdev_gendev);
ee959b00c   Tony Jones   SCSI: convert str...
1087
  	sdev->sdev_dev.class = &sdev_class;
71610f55f   Kay Sievers   [SCSI] struct dev...
1088
1089
  	dev_set_name(&sdev->sdev_dev, "%d:%d:%d:%d",
  		     sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
7c9d6f16f   Alan Stern   [SCSI] SCSI core:...
1090
  	sdev->scsi_level = starget->scsi_level;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
1092
1093
1094
1095
1096
1097
1098
1099
  	transport_setup_device(&sdev->sdev_gendev);
  	spin_lock_irqsave(shost->host_lock, flags);
  	list_add_tail(&sdev->same_target_siblings, &starget->devices);
  	list_add_tail(&sdev->siblings, &shost->__devices);
  	spin_unlock_irqrestore(shost->host_lock, flags);
  }
  
  int scsi_is_sdev_device(const struct device *dev)
  {
13ba9bcbf   Kay Sievers   [SCSI] fix scsi_i...
1100
  	return dev->type == &scsi_dev_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
1103
1104
1105
1106
  }
  EXPORT_SYMBOL(scsi_is_sdev_device);
  
  /* A blank transport template that is used in drivers that don't
   * yet implement Transport Attributes */
  struct scsi_transport_template blank_transport_template = { { { {NULL, }, }, }, };