Branch data Line data Source code
1 : : /*
2 : : * hosts.c Copyright (C) 1992 Drew Eckhardt
3 : : * Copyright (C) 1993, 1994, 1995 Eric Youngdale
4 : : * Copyright (C) 2002-2003 Christoph Hellwig
5 : : *
6 : : * mid to lowlevel SCSI driver interface
7 : : * Initial versions: Drew Eckhardt
8 : : * Subsequent revisions: Eric Youngdale
9 : : *
10 : : * <drew@colorado.edu>
11 : : *
12 : : * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
13 : : * Added QLOGIC QLA1280 SCSI controller kernel host support.
14 : : * August 4, 1999 Fred Lewis, Intel DuPont
15 : : *
16 : : * Updated to reflect the new initialization scheme for the higher
17 : : * level of scsi drivers (sd/sr/st)
18 : : * September 17, 2000 Torben Mathiasen <tmm@image.dk>
19 : : *
20 : : * Restructured scsi_host lists and associated functions.
21 : : * September 04, 2002 Mike Anderson (andmike@us.ibm.com)
22 : : */
23 : :
24 : : #include <linux/module.h>
25 : : #include <linux/blkdev.h>
26 : : #include <linux/kernel.h>
27 : : #include <linux/slab.h>
28 : : #include <linux/kthread.h>
29 : : #include <linux/string.h>
30 : : #include <linux/mm.h>
31 : : #include <linux/init.h>
32 : : #include <linux/completion.h>
33 : : #include <linux/transport_class.h>
34 : : #include <linux/platform_device.h>
35 : : #include <linux/pm_runtime.h>
36 : :
37 : : #include <scsi/scsi_device.h>
38 : : #include <scsi/scsi_host.h>
39 : : #include <scsi/scsi_transport.h>
40 : :
41 : : #include "scsi_priv.h"
42 : : #include "scsi_logging.h"
43 : :
44 : :
45 : : static atomic_t scsi_host_next_hn = ATOMIC_INIT(0); /* host_no for next new host */
46 : :
47 : :
48 : 0 : static void scsi_host_cls_release(struct device *dev)
49 : : {
50 : 0 : put_device(&class_to_shost(dev)->shost_gendev);
51 : 0 : }
52 : :
53 : : static struct class shost_class = {
54 : : .name = "scsi_host",
55 : : .dev_release = scsi_host_cls_release,
56 : : };
57 : :
58 : : /**
59 : : * scsi_host_set_state - Take the given host through the host state model.
60 : : * @shost: scsi host to change the state of.
61 : : * @state: state to change to.
62 : : *
63 : : * Returns zero if unsuccessful or an error if the requested
64 : : * transition is illegal.
65 : : **/
66 : 0 : int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
67 : : {
68 : 0 : enum scsi_host_state oldstate = shost->shost_state;
69 : :
70 [ # # ]: 0 : if (state == oldstate)
71 : : return 0;
72 : :
73 [ # # # # : 0 : switch (state) {
# # # # ]
74 : : case SHOST_CREATED:
75 : : /* There are no legal states that come back to
76 : : * created. This is the manually initialised start
77 : : * state */
78 : : goto illegal;
79 : :
80 : : case SHOST_RUNNING:
81 [ # # ]: 0 : switch (oldstate) {
82 : : case SHOST_CREATED:
83 : : case SHOST_RECOVERY:
84 : : break;
85 : : default:
86 : : goto illegal;
87 : : }
88 : : break;
89 : :
90 : : case SHOST_RECOVERY:
91 [ # # ][ # # ]: 0 : switch (oldstate) {
[ # # ]
92 : : case SHOST_RUNNING:
93 : : break;
94 : : default:
95 : : goto illegal;
96 : : }
97 : : break;
98 : :
99 : : case SHOST_CANCEL:
100 : : switch (oldstate) {
101 : : case SHOST_CREATED:
102 : : case SHOST_RUNNING:
103 : : case SHOST_CANCEL_RECOVERY:
104 : : break;
105 : : default:
106 : : goto illegal;
107 : : }
108 : : break;
109 : :
110 : : case SHOST_DEL:
111 [ # # ]: 0 : switch (oldstate) {
112 : : case SHOST_CANCEL:
113 : : case SHOST_DEL_RECOVERY:
114 : : break;
115 : : default:
116 : : goto illegal;
117 : : }
118 : : break;
119 : :
120 : : case SHOST_CANCEL_RECOVERY:
121 [ # # ]: 0 : switch (oldstate) {
122 : : case SHOST_CANCEL:
123 : : case SHOST_RECOVERY:
124 : : break;
125 : : default:
126 : : goto illegal;
127 : : }
128 : : break;
129 : :
130 : : case SHOST_DEL_RECOVERY:
131 [ # # ]: 0 : switch (oldstate) {
132 : : case SHOST_CANCEL_RECOVERY:
133 : : break;
134 : : default:
135 : : goto illegal;
136 : : }
137 : : break;
138 : : }
139 : 0 : shost->shost_state = state;
140 : 0 : return 0;
141 : :
142 : : illegal:
143 : : SCSI_LOG_ERROR_RECOVERY(1,
144 : : shost_printk(KERN_ERR, shost,
145 : : "Illegal host state transition"
146 : : "%s->%s\n",
147 : : scsi_host_state_name(oldstate),
148 : : scsi_host_state_name(state)));
149 : : return -EINVAL;
150 : : }
151 : : EXPORT_SYMBOL(scsi_host_set_state);
152 : :
153 : : /**
154 : : * scsi_remove_host - remove a scsi host
155 : : * @shost: a pointer to a scsi host to remove
156 : : **/
157 : 0 : void scsi_remove_host(struct Scsi_Host *shost)
158 : : {
159 : : unsigned long flags;
160 : :
161 : 0 : mutex_lock(&shost->scan_mutex);
162 : 0 : spin_lock_irqsave(shost->host_lock, flags);
163 [ # # ]: 0 : if (scsi_host_set_state(shost, SHOST_CANCEL))
164 [ # # ]: 0 : if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) {
165 : 0 : spin_unlock_irqrestore(shost->host_lock, flags);
166 : 0 : mutex_unlock(&shost->scan_mutex);
167 : 0 : return;
168 : : }
169 : 0 : spin_unlock_irqrestore(shost->host_lock, flags);
170 : :
171 : : scsi_autopm_get_host(shost);
172 : 0 : scsi_forget_host(shost);
173 : 0 : mutex_unlock(&shost->scan_mutex);
174 : 0 : scsi_proc_host_rm(shost);
175 : :
176 : 0 : spin_lock_irqsave(shost->host_lock, flags);
177 [ # # ]: 0 : if (scsi_host_set_state(shost, SHOST_DEL))
178 [ # # ]: 0 : BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
179 : 0 : spin_unlock_irqrestore(shost->host_lock, flags);
180 : :
181 : 0 : transport_unregister_device(&shost->shost_gendev);
182 : 0 : device_unregister(&shost->shost_dev);
183 : 0 : device_del(&shost->shost_gendev);
184 : : }
185 : : EXPORT_SYMBOL(scsi_remove_host);
186 : :
187 : : /**
188 : : * scsi_add_host_with_dma - add a scsi host with dma device
189 : : * @shost: scsi host pointer to add
190 : : * @dev: a struct device of type scsi class
191 : : * @dma_dev: dma device for the host
192 : : *
193 : : * Note: You rarely need to worry about this unless you're in a
194 : : * virtualised host environments, so use the simpler scsi_add_host()
195 : : * function instead.
196 : : *
197 : : * Return value:
198 : : * 0 on success / != 0 for error
199 : : **/
200 : 0 : int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
201 : : struct device *dma_dev)
202 : : {
203 : 0 : struct scsi_host_template *sht = shost->hostt;
204 : : int error = -EINVAL;
205 : :
206 [ # # ]: 0 : printk(KERN_INFO "scsi%d : %s\n", shost->host_no,
207 : 0 : sht->info ? sht->info(shost) : sht->name);
208 : :
209 [ # # ]: 0 : if (!shost->can_queue) {
210 : 0 : printk(KERN_ERR "%s: can_queue = 0 no longer supported\n",
211 : : sht->name);
212 : 0 : goto fail;
213 : : }
214 : :
215 : 0 : error = scsi_setup_command_freelist(shost);
216 [ # # ]: 0 : if (error)
217 : : goto fail;
218 : :
219 [ # # ]: 0 : if (!shost->shost_gendev.parent)
220 [ # # ]: 0 : shost->shost_gendev.parent = dev ? dev : &platform_bus;
221 [ # # ]: 0 : if (!dma_dev)
222 : 0 : dma_dev = shost->shost_gendev.parent;
223 : :
224 : 0 : shost->dma_dev = dma_dev;
225 : :
226 : 0 : error = device_add(&shost->shost_gendev);
227 [ # # ]: 0 : if (error)
228 : : goto out;
229 : :
230 : : pm_runtime_set_active(&shost->shost_gendev);
231 : : pm_runtime_enable(&shost->shost_gendev);
232 : : device_enable_async_suspend(&shost->shost_gendev);
233 : :
234 : 0 : scsi_host_set_state(shost, SHOST_RUNNING);
235 : 0 : get_device(shost->shost_gendev.parent);
236 : :
237 : : device_enable_async_suspend(&shost->shost_dev);
238 : :
239 : 0 : error = device_add(&shost->shost_dev);
240 [ # # ]: 0 : if (error)
241 : : goto out_del_gendev;
242 : :
243 : 0 : get_device(&shost->shost_gendev);
244 : :
245 [ # # ]: 0 : if (shost->transportt->host_size) {
246 : 0 : shost->shost_data = kzalloc(shost->transportt->host_size,
247 : : GFP_KERNEL);
248 [ # # ]: 0 : if (shost->shost_data == NULL) {
249 : : error = -ENOMEM;
250 : : goto out_del_dev;
251 : : }
252 : : }
253 : :
254 [ # # ]: 0 : if (shost->transportt->create_work_queue) {
255 : 0 : snprintf(shost->work_q_name, sizeof(shost->work_q_name),
256 : : "scsi_wq_%d", shost->host_no);
257 : 0 : shost->work_q = create_singlethread_workqueue(
258 : : shost->work_q_name);
259 [ # # ]: 0 : if (!shost->work_q) {
260 : : error = -EINVAL;
261 : : goto out_free_shost_data;
262 : : }
263 : : }
264 : :
265 : 0 : error = scsi_sysfs_add_host(shost);
266 [ # # ]: 0 : if (error)
267 : : goto out_destroy_host;
268 : :
269 : 0 : scsi_proc_host_add(shost);
270 : 0 : return error;
271 : :
272 : : out_destroy_host:
273 [ # # ]: 0 : if (shost->work_q)
274 : 0 : destroy_workqueue(shost->work_q);
275 : : out_free_shost_data:
276 : 0 : kfree(shost->shost_data);
277 : : out_del_dev:
278 : 0 : device_del(&shost->shost_dev);
279 : : out_del_gendev:
280 : 0 : device_del(&shost->shost_gendev);
281 : : out:
282 : 0 : scsi_destroy_command_freelist(shost);
283 : : fail:
284 : 0 : return error;
285 : : }
286 : : EXPORT_SYMBOL(scsi_add_host_with_dma);
287 : :
288 : 0 : static void scsi_host_dev_release(struct device *dev)
289 : : {
290 : : struct Scsi_Host *shost = dev_to_shost(dev);
291 : 0 : struct device *parent = dev->parent;
292 : : struct request_queue *q;
293 : : void *queuedata;
294 : :
295 : 0 : scsi_proc_hostdir_rm(shost->hostt);
296 : :
297 [ # # ]: 0 : if (shost->ehandler)
298 : 0 : kthread_stop(shost->ehandler);
299 [ # # ]: 0 : if (shost->work_q)
300 : 0 : destroy_workqueue(shost->work_q);
301 : 0 : q = shost->uspace_req_q;
302 [ # # ]: 0 : if (q) {
303 : 0 : queuedata = q->queuedata;
304 : 0 : blk_cleanup_queue(q);
305 : 0 : kfree(queuedata);
306 : : }
307 : :
308 : 0 : scsi_destroy_command_freelist(shost);
309 [ # # ]: 0 : if (shost->bqt)
310 : 0 : blk_free_tags(shost->bqt);
311 : :
312 : 0 : kfree(shost->shost_data);
313 : :
314 [ # # ]: 0 : if (parent)
315 : 0 : put_device(parent);
316 : 0 : kfree(shost);
317 : 0 : }
318 : :
319 : : static unsigned int shost_eh_deadline;
320 : :
321 : : module_param_named(eh_deadline, shost_eh_deadline, uint, S_IRUGO|S_IWUSR);
322 : : MODULE_PARM_DESC(eh_deadline,
323 : : "SCSI EH timeout in seconds (should be between 1 and 2^32-1)");
324 : :
325 : : static struct device_type scsi_host_type = {
326 : : .name = "scsi_host",
327 : : .release = scsi_host_dev_release,
328 : : };
329 : :
330 : : /**
331 : : * scsi_host_alloc - register a scsi host adapter instance.
332 : : * @sht: pointer to scsi host template
333 : : * @privsize: extra bytes to allocate for driver
334 : : *
335 : : * Note:
336 : : * Allocate a new Scsi_Host and perform basic initialization.
337 : : * The host is not published to the scsi midlayer until scsi_add_host
338 : : * is called.
339 : : *
340 : : * Return value:
341 : : * Pointer to a new Scsi_Host
342 : : **/
343 : 0 : struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
344 : : {
345 : : struct Scsi_Host *shost;
346 : : gfp_t gfp_mask = GFP_KERNEL;
347 : :
348 [ # # ][ # # ]: 0 : if (sht->unchecked_isa_dma && privsize)
349 : : gfp_mask |= __GFP_DMA;
350 : :
351 : 0 : shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
352 [ # # ]: 0 : if (!shost)
353 : : return NULL;
354 : :
355 : 0 : shost->host_lock = &shost->default_lock;
356 : 0 : spin_lock_init(shost->host_lock);
357 : 0 : shost->shost_state = SHOST_CREATED;
358 : 0 : INIT_LIST_HEAD(&shost->__devices);
359 : 0 : INIT_LIST_HEAD(&shost->__targets);
360 : 0 : INIT_LIST_HEAD(&shost->eh_cmd_q);
361 : 0 : INIT_LIST_HEAD(&shost->starved_list);
362 : 0 : init_waitqueue_head(&shost->host_wait);
363 : :
364 : 0 : mutex_init(&shost->scan_mutex);
365 : :
366 : : /*
367 : : * subtract one because we increment first then return, but we need to
368 : : * know what the next host number was before increment
369 : : */
370 : 0 : shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1;
371 : 0 : shost->dma_channel = 0xff;
372 : :
373 : : /* These three are default values which can be overridden */
374 : 0 : shost->max_channel = 0;
375 : 0 : shost->max_id = 8;
376 : 0 : shost->max_lun = 8;
377 : :
378 : : /* Give each shost a default transportt */
379 : 0 : shost->transportt = &blank_transport_template;
380 : :
381 : : /*
382 : : * All drivers right now should be able to handle 12 byte
383 : : * commands. Every so often there are requests for 16 byte
384 : : * commands, but individual low-level drivers need to certify that
385 : : * they actually do something sensible with such commands.
386 : : */
387 : 0 : shost->max_cmd_len = 12;
388 : 0 : shost->hostt = sht;
389 : 0 : shost->this_id = sht->this_id;
390 : 0 : shost->can_queue = sht->can_queue;
391 : 0 : shost->sg_tablesize = sht->sg_tablesize;
392 : 0 : shost->sg_prot_tablesize = sht->sg_prot_tablesize;
393 : 0 : shost->cmd_per_lun = sht->cmd_per_lun;
394 : 0 : shost->unchecked_isa_dma = sht->unchecked_isa_dma;
395 : 0 : shost->use_clustering = sht->use_clustering;
396 : 0 : shost->ordered_tag = sht->ordered_tag;
397 : 0 : shost->eh_deadline = shost_eh_deadline * HZ;
398 : 0 : shost->no_write_same = sht->no_write_same;
399 : :
400 [ # # ]: 0 : if (sht->supported_mode == MODE_UNKNOWN)
401 : : /* means we didn't set it ... default to INITIATOR */
402 : 0 : shost->active_mode = MODE_INITIATOR;
403 : : else
404 : 0 : shost->active_mode = sht->supported_mode;
405 : :
406 [ # # ]: 0 : if (sht->max_host_blocked)
407 : 0 : shost->max_host_blocked = sht->max_host_blocked;
408 : : else
409 : 0 : shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED;
410 : :
411 : : /*
412 : : * If the driver imposes no hard sector transfer limit, start at
413 : : * machine infinity initially.
414 : : */
415 [ # # ]: 0 : if (sht->max_sectors)
416 : 0 : shost->max_sectors = sht->max_sectors;
417 : : else
418 : 0 : shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
419 : :
420 : : /*
421 : : * assume a 4GB boundary, if not set
422 : : */
423 [ # # ]: 0 : if (sht->dma_boundary)
424 : 0 : shost->dma_boundary = sht->dma_boundary;
425 : : else
426 : 0 : shost->dma_boundary = 0xffffffff;
427 : :
428 : 0 : device_initialize(&shost->shost_gendev);
429 : 0 : dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
430 : 0 : shost->shost_gendev.bus = &scsi_bus_type;
431 : 0 : shost->shost_gendev.type = &scsi_host_type;
432 : :
433 : 0 : device_initialize(&shost->shost_dev);
434 : 0 : shost->shost_dev.parent = &shost->shost_gendev;
435 : 0 : shost->shost_dev.class = &shost_class;
436 : 0 : dev_set_name(&shost->shost_dev, "host%d", shost->host_no);
437 : 0 : shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
438 : :
439 [ # # ]: 0 : shost->ehandler = kthread_run(scsi_error_handler, shost,
440 : : "scsi_eh_%d", shost->host_no);
441 [ # # ]: 0 : if (IS_ERR(shost->ehandler)) {
442 : 0 : printk(KERN_WARNING "scsi%d: error handler thread failed to spawn, error = %ld\n",
443 : : shost->host_no, PTR_ERR(shost->ehandler));
444 : : goto fail_kfree;
445 : : }
446 : :
447 : 0 : scsi_proc_hostdir_add(shost->hostt);
448 : 0 : return shost;
449 : :
450 : : fail_kfree:
451 : 0 : kfree(shost);
452 : 0 : return NULL;
453 : : }
454 : : EXPORT_SYMBOL(scsi_host_alloc);
455 : :
456 : 0 : struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize)
457 : : {
458 : 0 : struct Scsi_Host *shost = scsi_host_alloc(sht, privsize);
459 : :
460 [ # # ]: 0 : if (!sht->detect) {
461 : 0 : printk(KERN_WARNING "scsi_register() called on new-style "
462 : : "template for driver %s\n", sht->name);
463 : 0 : dump_stack();
464 : : }
465 : :
466 [ # # ]: 0 : if (shost)
467 : 0 : list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts);
468 : 0 : return shost;
469 : : }
470 : : EXPORT_SYMBOL(scsi_register);
471 : :
472 : 0 : void scsi_unregister(struct Scsi_Host *shost)
473 : : {
474 : : list_del(&shost->sht_legacy_list);
475 : : scsi_host_put(shost);
476 : 0 : }
477 : : EXPORT_SYMBOL(scsi_unregister);
478 : :
479 : 0 : static int __scsi_host_match(struct device *dev, const void *data)
480 : : {
481 : : struct Scsi_Host *p;
482 : : const unsigned short *hostnum = data;
483 : :
484 : : p = class_to_shost(dev);
485 : 0 : return p->host_no == *hostnum;
486 : : }
487 : :
488 : : /**
489 : : * scsi_host_lookup - get a reference to a Scsi_Host by host no
490 : : * @hostnum: host number to locate
491 : : *
492 : : * Return value:
493 : : * A pointer to located Scsi_Host or NULL.
494 : : *
495 : : * The caller must do a scsi_host_put() to drop the reference
496 : : * that scsi_host_get() took. The put_device() below dropped
497 : : * the reference from class_find_device().
498 : : **/
499 : 0 : struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
500 : : {
501 : : struct device *cdev;
502 : : struct Scsi_Host *shost = NULL;
503 : :
504 : 0 : cdev = class_find_device(&shost_class, NULL, &hostnum,
505 : : __scsi_host_match);
506 [ # # ]: 0 : if (cdev) {
507 : 0 : shost = scsi_host_get(class_to_shost(cdev));
508 : 0 : put_device(cdev);
509 : : }
510 : 0 : return shost;
511 : : }
512 : : EXPORT_SYMBOL(scsi_host_lookup);
513 : :
514 : : /**
515 : : * scsi_host_get - inc a Scsi_Host ref count
516 : : * @shost: Pointer to Scsi_Host to inc.
517 : : **/
518 : 0 : struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
519 : : {
520 [ # # # # ]: 0 : if ((shost->shost_state == SHOST_DEL) ||
[ # # # # ]
521 : 0 : !get_device(&shost->shost_gendev))
522 : : return NULL;
523 : 0 : return shost;
524 : : }
525 : : EXPORT_SYMBOL(scsi_host_get);
526 : :
527 : : /**
528 : : * scsi_host_put - dec a Scsi_Host ref count
529 : : * @shost: Pointer to Scsi_Host to dec.
530 : : **/
531 : 0 : void scsi_host_put(struct Scsi_Host *shost)
532 : : {
533 : 0 : put_device(&shost->shost_gendev);
534 : 0 : }
535 : : EXPORT_SYMBOL(scsi_host_put);
536 : :
537 : 0 : int scsi_init_hosts(void)
538 : : {
539 : 0 : return class_register(&shost_class);
540 : : }
541 : :
542 : 0 : void scsi_exit_hosts(void)
543 : : {
544 : 0 : class_unregister(&shost_class);
545 : 0 : }
546 : :
547 : 0 : int scsi_is_host_device(const struct device *dev)
548 : : {
549 : 0 : return dev->type == &scsi_host_type;
550 : : }
551 : : EXPORT_SYMBOL(scsi_is_host_device);
552 : :
553 : : /**
554 : : * scsi_queue_work - Queue work to the Scsi_Host workqueue.
555 : : * @shost: Pointer to Scsi_Host.
556 : : * @work: Work to queue for execution.
557 : : *
558 : : * Return value:
559 : : * 1 - work queued for execution
560 : : * 0 - work is already queued
561 : : * -EINVAL - work queue doesn't exist
562 : : **/
563 : 0 : int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
564 : : {
565 [ # # ]: 0 : if (unlikely(!shost->work_q)) {
566 : 0 : printk(KERN_ERR
567 : : "ERROR: Scsi host '%s' attempted to queue scsi-work, "
568 : 0 : "when no workqueue created.\n", shost->hostt->name);
569 : 0 : dump_stack();
570 : :
571 : 0 : return -EINVAL;
572 : : }
573 : :
574 : 0 : return queue_work(shost->work_q, work);
575 : : }
576 : : EXPORT_SYMBOL_GPL(scsi_queue_work);
577 : :
578 : : /**
579 : : * scsi_flush_work - Flush a Scsi_Host's workqueue.
580 : : * @shost: Pointer to Scsi_Host.
581 : : **/
582 : 0 : void scsi_flush_work(struct Scsi_Host *shost)
583 : : {
584 [ # # ]: 0 : if (!shost->work_q) {
585 : 0 : printk(KERN_ERR
586 : : "ERROR: Scsi host '%s' attempted to flush scsi-work, "
587 : 0 : "when no workqueue created.\n", shost->hostt->name);
588 : 0 : dump_stack();
589 : 0 : return;
590 : : }
591 : :
592 : 0 : flush_workqueue(shost->work_q);
593 : : }
594 : : EXPORT_SYMBOL_GPL(scsi_flush_work);
|