Blame view

drivers/scsi/hosts.c 13.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   *  hosts.c Copyright (C) 1992 Drew Eckhardt
   *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
   *          Copyright (C) 2002-2003 Christoph Hellwig
   *
   *  mid to lowlevel SCSI driver interface
   *      Initial versions: Drew Eckhardt
   *      Subsequent revisions: Eric Youngdale
   *
   *  <drew@colorado.edu>
   *
   *  Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
   *  Added QLOGIC QLA1280 SCSI controller kernel host support. 
   *     August 4, 1999 Fred Lewis, Intel DuPont
   *
   *  Updated to reflect the new initialization scheme for the higher 
   *  level of scsi drivers (sd/sr/st)
   *  September 17, 2000 Torben Mathiasen <tmm@image.dk>
   *
   *  Restructured scsi_host lists and associated functions.
   *  September 04, 2002 Mike Anderson (andmike@us.ibm.com)
   */
  
  #include <linux/module.h>
  #include <linux/blkdev.h>
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/slab.h>
c5478def7   Christoph Hellwig   [SCSI] switch EH ...
28
  #include <linux/kthread.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
  #include <linux/string.h>
  #include <linux/mm.h>
  #include <linux/init.h>
  #include <linux/completion.h>
  #include <linux/transport_class.h>
d052d1bef   Russell King   Create platform_d...
34
  #include <linux/platform_device.h>
bc4f24014   Alan Stern   [SCSI] implement ...
35
  #include <linux/pm_runtime.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
  
  #include <scsi/scsi_device.h>
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_transport.h>
  
  #include "scsi_priv.h"
  #include "scsi_logging.h"
30c9afa6c   Joe Eykholt   fix race that can...
43
  static atomic_t scsi_host_next_hn;	/* host_no for next new host */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

ee959b00c   Tony Jones   SCSI: convert str...
45
  static void scsi_host_cls_release(struct device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  {
ee959b00c   Tony Jones   SCSI: convert str...
47
  	put_device(&class_to_shost(dev)->shost_gendev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
  }
  
  static struct class shost_class = {
  	.name		= "scsi_host",
ee959b00c   Tony Jones   SCSI: convert str...
52
  	.dev_release	= scsi_host_cls_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
  };
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
56
   *	scsi_host_set_state - Take the given host through the host state model.
d33018740   Mike Anderson   [SCSI] host state...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
   *	@shost:	scsi host to change the state of.
   *	@state:	state to change to.
   *
   *	Returns zero if unsuccessful or an error if the requested
   *	transition is illegal.
   **/
  int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
  {
  	enum scsi_host_state oldstate = shost->shost_state;
  
  	if (state == oldstate)
  		return 0;
  
  	switch (state) {
  	case SHOST_CREATED:
  		/* There are no legal states that come back to
  		 * created.  This is the manually initialised start
  		 * state */
  		goto illegal;
  
  	case SHOST_RUNNING:
  		switch (oldstate) {
  		case SHOST_CREATED:
  		case SHOST_RECOVERY:
  			break;
  		default:
  			goto illegal;
  		}
  		break;
  
  	case SHOST_RECOVERY:
  		switch (oldstate) {
  		case SHOST_RUNNING:
  			break;
  		default:
  			goto illegal;
  		}
  		break;
  
  	case SHOST_CANCEL:
  		switch (oldstate) {
  		case SHOST_CREATED:
  		case SHOST_RUNNING:
939647ee3   James Bottomley   [SCSI] fix oops o...
100
  		case SHOST_CANCEL_RECOVERY:
d33018740   Mike Anderson   [SCSI] host state...
101
102
103
104
105
106
107
108
109
  			break;
  		default:
  			goto illegal;
  		}
  		break;
  
  	case SHOST_DEL:
  		switch (oldstate) {
  		case SHOST_CANCEL:
939647ee3   James Bottomley   [SCSI] fix oops o...
110
  		case SHOST_DEL_RECOVERY:
d33018740   Mike Anderson   [SCSI] host state...
111
112
113
114
115
  			break;
  		default:
  			goto illegal;
  		}
  		break;
939647ee3   James Bottomley   [SCSI] fix oops o...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  	case SHOST_CANCEL_RECOVERY:
  		switch (oldstate) {
  		case SHOST_CANCEL:
  		case SHOST_RECOVERY:
  			break;
  		default:
  			goto illegal;
  		}
  		break;
  
  	case SHOST_DEL_RECOVERY:
  		switch (oldstate) {
  		case SHOST_CANCEL_RECOVERY:
  			break;
  		default:
  			goto illegal;
  		}
  		break;
d33018740   Mike Anderson   [SCSI] host state...
134
135
136
137
138
139
  	}
  	shost->shost_state = state;
  	return 0;
  
   illegal:
  	SCSI_LOG_ERROR_RECOVERY(1,
9ccfc756a   James Bottomley   [SCSI] move the m...
140
141
142
143
144
145
  				shost_printk(KERN_ERR, shost,
  					     "Illegal host state transition"
  					     "%s->%s
  ",
  					     scsi_host_state_name(oldstate),
  					     scsi_host_state_name(state)));
d33018740   Mike Anderson   [SCSI] host state...
146
147
148
149
150
  	return -EINVAL;
  }
  EXPORT_SYMBOL(scsi_host_set_state);
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
155
   * scsi_remove_host - remove a scsi host
   * @shost:	a pointer to a scsi host to remove
   **/
  void scsi_remove_host(struct Scsi_Host *shost)
  {
939647ee3   James Bottomley   [SCSI] fix oops o...
156
  	unsigned long flags;
bc4f24014   Alan Stern   [SCSI] implement ...
157

0b9506723   Arjan van de Ven   [SCSI] turn most ...
158
  	mutex_lock(&shost->scan_mutex);
939647ee3   James Bottomley   [SCSI] fix oops o...
159
160
161
162
  	spin_lock_irqsave(shost->host_lock, flags);
  	if (scsi_host_set_state(shost, SHOST_CANCEL))
  		if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) {
  			spin_unlock_irqrestore(shost->host_lock, flags);
0b9506723   Arjan van de Ven   [SCSI] turn most ...
163
  			mutex_unlock(&shost->scan_mutex);
939647ee3   James Bottomley   [SCSI] fix oops o...
164
165
166
  			return;
  		}
  	spin_unlock_irqrestore(shost->host_lock, flags);
bc4f24014   Alan Stern   [SCSI] implement ...
167
168
  
  	scsi_autopm_get_host(shost);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  	scsi_forget_host(shost);
4e46bf899   Alexey Kuznetsov   [SCSI] fix crash ...
170
  	mutex_unlock(&shost->scan_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  	scsi_proc_host_rm(shost);
939647ee3   James Bottomley   [SCSI] fix oops o...
172
173
174
175
  	spin_lock_irqsave(shost->host_lock, flags);
  	if (scsi_host_set_state(shost, SHOST_DEL))
  		BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
  	spin_unlock_irqrestore(shost->host_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
  
  	transport_unregister_device(&shost->shost_gendev);
ee959b00c   Tony Jones   SCSI: convert str...
178
  	device_unregister(&shost->shost_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
  	device_del(&shost->shost_gendev);
  }
  EXPORT_SYMBOL(scsi_remove_host);
  
  /**
d139b9bd0   James Bottomley   [SCSI] scsi_lib_d...
184
   * scsi_add_host_with_dma - add a scsi host with dma device
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
   * @shost:	scsi host pointer to add
   * @dev:	a struct device of type scsi class
d139b9bd0   James Bottomley   [SCSI] scsi_lib_d...
187
188
189
190
191
   * @dma_dev:	dma device for the host
   *
   * Note: You rarely need to worry about this unless you're in a
   * virtualised host environments, so use the simpler scsi_add_host()
   * function instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
   *
   * Return value: 
   * 	0 on success / != 0 for error
   **/
d139b9bd0   James Bottomley   [SCSI] scsi_lib_d...
196
197
  int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
  			   struct device *dma_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
203
204
205
206
207
208
209
  {
  	struct scsi_host_template *sht = shost->hostt;
  	int error = -EINVAL;
  
  	printk(KERN_INFO "scsi%d : %s
  ", shost->host_no,
  			sht->info ? sht->info(shost) : sht->name);
  
  	if (!shost->can_queue) {
  		printk(KERN_ERR "%s: can_queue = 0 no longer supported
  ",
  				sht->name);
542bd1377   James Bottomley   [SCSI] fix SLUB W...
210
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  	}
542bd1377   James Bottomley   [SCSI] fix SLUB W...
212
213
214
  	error = scsi_setup_command_freelist(shost);
  	if (error)
  		goto fail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
  	if (!shost->shost_gendev.parent)
  		shost->shost_gendev.parent = dev ? dev : &platform_bus;
d139b9bd0   James Bottomley   [SCSI] scsi_lib_d...
217
  	shost->dma_dev = dma_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
  
  	error = device_add(&shost->shost_gendev);
  	if (error)
  		goto out;
bc4f24014   Alan Stern   [SCSI] implement ...
222
223
224
  	pm_runtime_set_active(&shost->shost_gendev);
  	pm_runtime_enable(&shost->shost_gendev);
  	device_enable_async_suspend(&shost->shost_gendev);
d33018740   Mike Anderson   [SCSI] host state...
225
  	scsi_host_set_state(shost, SHOST_RUNNING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  	get_device(shost->shost_gendev.parent);
4cb077d93   Rafael J. Wysocki   PM: Allow SCSI de...
227
  	device_enable_async_suspend(&shost->shost_dev);
ee959b00c   Tony Jones   SCSI: convert str...
228
  	error = device_add(&shost->shost_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
  	if (error)
  		goto out_del_gendev;
  
  	get_device(&shost->shost_gendev);
77cca462c   James Smart   [SCSI] hosts.c: f...
233
234
235
236
237
  	if (shost->transportt->host_size) {
  		shost->shost_data = kzalloc(shost->transportt->host_size,
  					 GFP_KERNEL);
  		if (shost->shost_data == NULL) {
  			error = -ENOMEM;
ee959b00c   Tony Jones   SCSI: convert str...
238
  			goto out_del_dev;
77cca462c   James Smart   [SCSI] hosts.c: f...
239
240
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
  
  	if (shost->transportt->create_work_queue) {
aab0de245   Kay Sievers   driver core: remo...
243
244
  		snprintf(shost->work_q_name, sizeof(shost->work_q_name),
  			 "scsi_wq_%d", shost->host_no);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
  		shost->work_q = create_singlethread_workqueue(
  					shost->work_q_name);
77cca462c   James Smart   [SCSI] hosts.c: f...
247
248
  		if (!shost->work_q) {
  			error = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  			goto out_free_shost_data;
77cca462c   James Smart   [SCSI] hosts.c: f...
250
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  	}
  
  	error = scsi_sysfs_add_host(shost);
  	if (error)
  		goto out_destroy_host;
  
  	scsi_proc_host_add(shost);
  	return error;
  
   out_destroy_host:
  	if (shost->work_q)
  		destroy_workqueue(shost->work_q);
   out_free_shost_data:
  	kfree(shost->shost_data);
ee959b00c   Tony Jones   SCSI: convert str...
265
266
   out_del_dev:
  	device_del(&shost->shost_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
   out_del_gendev:
  	device_del(&shost->shost_gendev);
   out:
542bd1377   James Bottomley   [SCSI] fix SLUB W...
270
271
  	scsi_destroy_command_freelist(shost);
   fail:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
  	return error;
  }
d139b9bd0   James Bottomley   [SCSI] scsi_lib_d...
274
  EXPORT_SYMBOL(scsi_add_host_with_dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
278
279
  
  static void scsi_host_dev_release(struct device *dev)
  {
  	struct Scsi_Host *shost = dev_to_shost(dev);
  	struct device *parent = dev->parent;
3308511c9   Bart Van Assche   [SCSI] Make scsi_...
280
  	struct request_queue *q;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281

77c019768   Alan Stern   [SCSI] fix /proc ...
282
  	scsi_proc_hostdir_rm(shost->hostt);
c5478def7   Christoph Hellwig   [SCSI] switch EH ...
283
284
  	if (shost->ehandler)
  		kthread_stop(shost->ehandler);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
  	if (shost->work_q)
  		destroy_workqueue(shost->work_q);
3308511c9   Bart Van Assche   [SCSI] Make scsi_...
287
288
289
290
291
  	q = shost->uspace_req_q;
  	if (q) {
  		kfree(q->queuedata);
  		q->queuedata = NULL;
  		scsi_free_queue(q);
b58d91547   FUJITA Tomonori   [SCSI] export scs...
292
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  	scsi_destroy_command_freelist(shost);
86e33a296   James Bottomley   [SCSI] add shared...
295
296
  	if (shost->bqt)
  		blk_free_tags(shost->bqt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  	kfree(shost->shost_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
301
  	if (parent)
  		put_device(parent);
  	kfree(shost);
  }
453cd0f3f   Adrian Bunk   [SCSI] make struc...
302
  static struct device_type scsi_host_type = {
b0ed43360   Hannes Reinecke   [SCSI] add scsi_h...
303
304
305
  	.name =		"scsi_host",
  	.release =	scsi_host_dev_release,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  /**
   * scsi_host_alloc - register a scsi host adapter instance.
   * @sht:	pointer to scsi host template
   * @privsize:	extra bytes to allocate for driver
   *
   * Note:
   * 	Allocate a new Scsi_Host and perform basic initialization.
   * 	The host is not published to the scsi midlayer until scsi_add_host
   * 	is called.
   *
   * Return value:
   * 	Pointer to a new Scsi_Host
   **/
  struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
  {
  	struct Scsi_Host *shost;
c53033f6b   Al Viro   [PATCH] gfp_t: dr...
322
  	gfp_t gfp_mask = GFP_KERNEL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
  
  	if (sht->unchecked_isa_dma && privsize)
  		gfp_mask |= __GFP_DMA;
24669f75a   Jes Sorensen   [SCSI] SCSI core ...
326
  	shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  	if (!shost)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329

4f777ed26   Christoph Hellwig   [SCSI] kill scsi_...
330
331
  	shost->host_lock = &shost->default_lock;
  	spin_lock_init(shost->host_lock);
d33018740   Mike Anderson   [SCSI] host state...
332
  	shost->shost_state = SHOST_CREATED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
  	INIT_LIST_HEAD(&shost->__devices);
  	INIT_LIST_HEAD(&shost->__targets);
  	INIT_LIST_HEAD(&shost->eh_cmd_q);
  	INIT_LIST_HEAD(&shost->starved_list);
  	init_waitqueue_head(&shost->host_wait);
0b9506723   Arjan van de Ven   [SCSI] turn most ...
338
  	mutex_init(&shost->scan_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339

30c9afa6c   Joe Eykholt   fix race that can...
340
341
342
343
344
  	/*
  	 * subtract one because we increment first then return, but we need to
  	 * know what the next host number was before increment
  	 */
  	shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  	shost->dma_channel = 0xff;
  
  	/* These three are default values which can be overridden */
  	shost->max_channel = 0;
  	shost->max_id = 8;
  	shost->max_lun = 8;
  
  	/* Give each shost a default transportt */
  	shost->transportt = &blank_transport_template;
  
  	/*
  	 * All drivers right now should be able to handle 12 byte
  	 * commands.  Every so often there are requests for 16 byte
  	 * commands, but individual low-level drivers need to certify that
  	 * they actually do something sensible with such commands.
  	 */
  	shost->max_cmd_len = 12;
  	shost->hostt = sht;
  	shost->this_id = sht->this_id;
  	shost->can_queue = sht->can_queue;
  	shost->sg_tablesize = sht->sg_tablesize;
13f05c8d8   Martin K. Petersen   block/scsi: Provi...
366
  	shost->sg_prot_tablesize = sht->sg_prot_tablesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
  	shost->cmd_per_lun = sht->cmd_per_lun;
  	shost->unchecked_isa_dma = sht->unchecked_isa_dma;
  	shost->use_clustering = sht->use_clustering;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  	shost->ordered_tag = sht->ordered_tag;
7a39ac3f2   James Bottomley   [SCSI] make suppo...
371
372
373
374
375
  	if (sht->supported_mode == MODE_UNKNOWN)
  		/* means we didn't set it ... default to INITIATOR */
  		shost->active_mode = MODE_INITIATOR;
  	else
  		shost->active_mode = sht->supported_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
  	if (sht->max_host_blocked)
  		shost->max_host_blocked = sht->max_host_blocked;
  	else
  		shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED;
  
  	/*
  	 * If the driver imposes no hard sector transfer limit, start at
  	 * machine infinity initially.
  	 */
  	if (sht->max_sectors)
  		shost->max_sectors = sht->max_sectors;
  	else
  		shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
  
  	/*
  	 * assume a 4GB boundary, if not set
  	 */
  	if (sht->dma_boundary)
  		shost->dma_boundary = sht->dma_boundary;
  	else
  		shost->dma_boundary = 0xffffffff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
  	device_initialize(&shost->shost_gendev);
71610f55f   Kay Sievers   [SCSI] struct dev...
398
  	dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
b0ed43360   Hannes Reinecke   [SCSI] add scsi_h...
399
  	shost->shost_gendev.bus = &scsi_bus_type;
b0ed43360   Hannes Reinecke   [SCSI] add scsi_h...
400
  	shost->shost_gendev.type = &scsi_host_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401

ee959b00c   Tony Jones   SCSI: convert str...
402
403
404
  	device_initialize(&shost->shost_dev);
  	shost->shost_dev.parent = &shost->shost_gendev;
  	shost->shost_dev.class = &shost_class;
71610f55f   Kay Sievers   [SCSI] struct dev...
405
  	dev_set_name(&shost->shost_dev, "host%d", shost->host_no);
f7120a4f7   Hannes Reinecke   [SCSI] use defaul...
406
  	shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407

c5478def7   Christoph Hellwig   [SCSI] switch EH ...
408
409
410
  	shost->ehandler = kthread_run(scsi_error_handler, shost,
  			"scsi_eh_%d", shost->host_no);
  	if (IS_ERR(shost->ehandler)) {
e4bf25fbc   Justin P. Mattock   [SCSI] scsi:hosts...
411
412
413
  		printk(KERN_WARNING "scsi%d: error handler thread failed to spawn, error = %ld
  ",
  			shost->host_no, PTR_ERR(shost->ehandler));
542bd1377   James Bottomley   [SCSI] fix SLUB W...
414
  		goto fail_kfree;
c5478def7   Christoph Hellwig   [SCSI] switch EH ...
415
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
  
  	scsi_proc_hostdir_add(shost->hostt);
  	return shost;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
   fail_kfree:
  	kfree(shost);
  	return NULL;
  }
  EXPORT_SYMBOL(scsi_host_alloc);
  
  struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize)
  {
  	struct Scsi_Host *shost = scsi_host_alloc(sht, privsize);
  
  	if (!sht->detect) {
  		printk(KERN_WARNING "scsi_register() called on new-style "
  				    "template for driver %s
  ", sht->name);
  		dump_stack();
  	}
  
  	if (shost)
  		list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts);
  	return shost;
  }
  EXPORT_SYMBOL(scsi_register);
  
  void scsi_unregister(struct Scsi_Host *shost)
  {
  	list_del(&shost->sht_legacy_list);
  	scsi_host_put(shost);
  }
  EXPORT_SYMBOL(scsi_unregister);
ee959b00c   Tony Jones   SCSI: convert str...
448
  static int __scsi_host_match(struct device *dev, void *data)
9c7701088   Dave Young   scsi: use class i...
449
450
451
  {
  	struct Scsi_Host *p;
  	unsigned short *hostnum = (unsigned short *)data;
ee959b00c   Tony Jones   SCSI: convert str...
452
  	p = class_to_shost(dev);
9c7701088   Dave Young   scsi: use class i...
453
454
  	return p->host_no == *hostnum;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
  /**
   * scsi_host_lookup - get a reference to a Scsi_Host by host no
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
460
   * @hostnum:	host number to locate
   *
   * Return value:
   *	A pointer to located Scsi_Host or NULL.
3ed789724   Mike Christie   [SCSI] scsi_host ...
461
462
463
464
   *
   *	The caller must do a scsi_host_put() to drop the reference
   *	that scsi_host_get() took. The put_device() below dropped
   *	the reference from class_find_device().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
   **/
  struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
  {
ee959b00c   Tony Jones   SCSI: convert str...
468
  	struct device *cdev;
315cb0ad1   James Smart   [SCSI] scsi_host_...
469
  	struct Scsi_Host *shost = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470

695794ae0   Greg Kroah-Hartman   Driver Core: add ...
471
472
  	cdev = class_find_device(&shost_class, NULL, &hostnum,
  				 __scsi_host_match);
3ed789724   Mike Christie   [SCSI] scsi_host ...
473
  	if (cdev) {
9c7701088   Dave Young   scsi: use class i...
474
  		shost = scsi_host_get(class_to_shost(cdev));
3ed789724   Mike Christie   [SCSI] scsi_host ...
475
476
  		put_device(cdev);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
479
480
481
482
483
484
485
486
  	return shost;
  }
  EXPORT_SYMBOL(scsi_host_lookup);
  
  /**
   * scsi_host_get - inc a Scsi_Host ref count
   * @shost:	Pointer to Scsi_Host to inc.
   **/
  struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
  {
d33018740   Mike Anderson   [SCSI] host state...
487
  	if ((shost->shost_state == SHOST_DEL) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
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
  		!get_device(&shost->shost_gendev))
  		return NULL;
  	return shost;
  }
  EXPORT_SYMBOL(scsi_host_get);
  
  /**
   * scsi_host_put - dec a Scsi_Host ref count
   * @shost:	Pointer to Scsi_Host to dec.
   **/
  void scsi_host_put(struct Scsi_Host *shost)
  {
  	put_device(&shost->shost_gendev);
  }
  EXPORT_SYMBOL(scsi_host_put);
  
  int scsi_init_hosts(void)
  {
  	return class_register(&shost_class);
  }
  
  void scsi_exit_hosts(void)
  {
  	class_unregister(&shost_class);
  }
  
  int scsi_is_host_device(const struct device *dev)
  {
b0ed43360   Hannes Reinecke   [SCSI] add scsi_h...
516
  	return dev->type == &scsi_host_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
520
521
522
523
524
525
  }
  EXPORT_SYMBOL(scsi_is_host_device);
  
  /**
   * scsi_queue_work - Queue work to the Scsi_Host workqueue.
   * @shost:	Pointer to Scsi_Host.
   * @work:	Work to queue for execution.
   *
   * Return value:
dd7e2f226   Michael Reed   [SCSI] scsi_queue...
526
527
528
   * 	1 - work queued for execution
   *	0 - work is already queued
   *	-EINVAL - work queue doesn't exist
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
   **/
  int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
  {
  	if (unlikely(!shost->work_q)) {
  		printk(KERN_ERR
  			"ERROR: Scsi host '%s' attempted to queue scsi-work, "
  			"when no workqueue created.
  ", shost->hostt->name);
  		dump_stack();
  
  		return -EINVAL;
  	}
  
  	return queue_work(shost->work_q, work);
  }
  EXPORT_SYMBOL_GPL(scsi_queue_work);
  
  /**
   * scsi_flush_work - Flush a Scsi_Host's workqueue.
   * @shost:	Pointer to Scsi_Host.
   **/
  void scsi_flush_work(struct Scsi_Host *shost)
  {
  	if (!shost->work_q) {
  		printk(KERN_ERR
  			"ERROR: Scsi host '%s' attempted to flush scsi-work, "
  			"when no workqueue created.
  ", shost->hostt->name);
  		dump_stack();
  		return;
  	}
  
  	flush_workqueue(shost->work_q);
  }
  EXPORT_SYMBOL_GPL(scsi_flush_work);