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 : flush_workqueue(shost->tmf_work_q);
173 : 0 : scsi_forget_host(shost);
174 : 0 : mutex_unlock(&shost->scan_mutex);
175 : 0 : scsi_proc_host_rm(shost);
176 : :
177 : 0 : spin_lock_irqsave(shost->host_lock, flags);
178 [ # # ]: 0 : if (scsi_host_set_state(shost, SHOST_DEL))
179 [ # # ]: 0 : BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
180 : 0 : spin_unlock_irqrestore(shost->host_lock, flags);
181 : :
182 : 0 : transport_unregister_device(&shost->shost_gendev);
183 : 0 : device_unregister(&shost->shost_dev);
184 : 0 : device_del(&shost->shost_gendev);
185 : : }
186 : : EXPORT_SYMBOL(scsi_remove_host);
187 : :
188 : : /**
189 : : * scsi_add_host_with_dma - add a scsi host with dma device
190 : : * @shost: scsi host pointer to add
191 : : * @dev: a struct device of type scsi class
192 : : * @dma_dev: dma device for the host
193 : : *
194 : : * Note: You rarely need to worry about this unless you're in a
195 : : * virtualised host environments, so use the simpler scsi_add_host()
196 : : * function instead.
197 : : *
198 : : * Return value:
199 : : * 0 on success / != 0 for error
200 : : **/
201 : 0 : int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
202 : : struct device *dma_dev)
203 : : {
204 : 0 : struct scsi_host_template *sht = shost->hostt;
205 : : int error = -EINVAL;
206 : :
207 [ # # ]: 0 : printk(KERN_INFO "scsi%d : %s\n", shost->host_no,
208 : 0 : sht->info ? sht->info(shost) : sht->name);
209 : :
210 [ # # ]: 0 : if (!shost->can_queue) {
211 : 0 : printk(KERN_ERR "%s: can_queue = 0 no longer supported\n",
212 : : sht->name);
213 : 0 : goto fail;
214 : : }
215 : :
216 : 0 : error = scsi_setup_command_freelist(shost);
217 [ # # ]: 0 : if (error)
218 : : goto fail;
219 : :
220 [ # # ]: 0 : if (!shost->shost_gendev.parent)
221 [ # # ]: 0 : shost->shost_gendev.parent = dev ? dev : &platform_bus;
222 [ # # ]: 0 : if (!dma_dev)
223 : 0 : dma_dev = shost->shost_gendev.parent;
224 : :
225 : 0 : shost->dma_dev = dma_dev;
226 : :
227 : 0 : error = device_add(&shost->shost_gendev);
228 [ # # ]: 0 : if (error)
229 : : goto out;
230 : :
231 : : pm_runtime_set_active(&shost->shost_gendev);
232 : : pm_runtime_enable(&shost->shost_gendev);
233 : : device_enable_async_suspend(&shost->shost_gendev);
234 : :
235 : 0 : scsi_host_set_state(shost, SHOST_RUNNING);
236 : 0 : get_device(shost->shost_gendev.parent);
237 : :
238 : : device_enable_async_suspend(&shost->shost_dev);
239 : :
240 : 0 : error = device_add(&shost->shost_dev);
241 [ # # ]: 0 : if (error)
242 : : goto out_del_gendev;
243 : :
244 : 0 : get_device(&shost->shost_gendev);
245 : :
246 [ # # ]: 0 : if (shost->transportt->host_size) {
247 : 0 : shost->shost_data = kzalloc(shost->transportt->host_size,
248 : : GFP_KERNEL);
249 [ # # ]: 0 : if (shost->shost_data == NULL) {
250 : : error = -ENOMEM;
251 : : goto out_del_dev;
252 : : }
253 : : }
254 : :
255 [ # # ]: 0 : if (shost->transportt->create_work_queue) {
256 : 0 : snprintf(shost->work_q_name, sizeof(shost->work_q_name),
257 : : "scsi_wq_%d", shost->host_no);
258 : 0 : shost->work_q = create_singlethread_workqueue(
259 : : shost->work_q_name);
260 [ # # ]: 0 : if (!shost->work_q) {
261 : : error = -EINVAL;
262 : : goto out_free_shost_data;
263 : : }
264 : : }
265 : :
266 : 0 : error = scsi_sysfs_add_host(shost);
267 [ # # ]: 0 : if (error)
268 : : goto out_destroy_host;
269 : :
270 : 0 : scsi_proc_host_add(shost);
271 : 0 : return error;
272 : :
273 : : out_destroy_host:
274 [ # # ]: 0 : if (shost->work_q)
275 : 0 : destroy_workqueue(shost->work_q);
276 : : out_free_shost_data:
277 : 0 : kfree(shost->shost_data);
278 : : out_del_dev:
279 : 0 : device_del(&shost->shost_dev);
280 : : out_del_gendev:
281 : 0 : device_del(&shost->shost_gendev);
282 : : out:
283 : 0 : scsi_destroy_command_freelist(shost);
284 : : fail:
285 : 0 : return error;
286 : : }
287 : : EXPORT_SYMBOL(scsi_add_host_with_dma);
288 : :
289 : 0 : static void scsi_host_dev_release(struct device *dev)
290 : : {
291 : : struct Scsi_Host *shost = dev_to_shost(dev);
292 : 0 : struct device *parent = dev->parent;
293 : : struct request_queue *q;
294 : : void *queuedata;
295 : :
296 : 0 : scsi_proc_hostdir_rm(shost->hostt);
297 : :
298 [ # # ]: 0 : if (shost->tmf_work_q)
299 : 0 : destroy_workqueue(shost->tmf_work_q);
300 [ # # ]: 0 : if (shost->ehandler)
301 : 0 : kthread_stop(shost->ehandler);
302 [ # # ]: 0 : if (shost->work_q)
303 : 0 : destroy_workqueue(shost->work_q);
304 : 0 : q = shost->uspace_req_q;
305 [ # # ]: 0 : if (q) {
306 : 0 : queuedata = q->queuedata;
307 : 0 : blk_cleanup_queue(q);
308 : 0 : kfree(queuedata);
309 : : }
310 : :
311 : 0 : scsi_destroy_command_freelist(shost);
312 [ # # ]: 0 : if (shost->bqt)
313 : 0 : blk_free_tags(shost->bqt);
314 : :
315 : 0 : kfree(shost->shost_data);
316 : :
317 [ # # ]: 0 : if (parent)
318 : 0 : put_device(parent);
319 : 0 : kfree(shost);
320 : 0 : }
321 : :
322 : : static int shost_eh_deadline = -1;
323 : :
324 : : module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR);
325 : : MODULE_PARM_DESC(eh_deadline,
326 : : "SCSI EH timeout in seconds (should be between 0 and 2^31-1)");
327 : :
328 : : static struct device_type scsi_host_type = {
329 : : .name = "scsi_host",
330 : : .release = scsi_host_dev_release,
331 : : };
332 : :
333 : : /**
334 : : * scsi_host_alloc - register a scsi host adapter instance.
335 : : * @sht: pointer to scsi host template
336 : : * @privsize: extra bytes to allocate for driver
337 : : *
338 : : * Note:
339 : : * Allocate a new Scsi_Host and perform basic initialization.
340 : : * The host is not published to the scsi midlayer until scsi_add_host
341 : : * is called.
342 : : *
343 : : * Return value:
344 : : * Pointer to a new Scsi_Host
345 : : **/
346 : 0 : struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
347 : : {
348 : : struct Scsi_Host *shost;
349 : : gfp_t gfp_mask = GFP_KERNEL;
350 : :
351 [ # # ][ # # ]: 0 : if (sht->unchecked_isa_dma && privsize)
352 : : gfp_mask |= __GFP_DMA;
353 : :
354 : 0 : shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
355 [ # # ]: 0 : if (!shost)
356 : : return NULL;
357 : :
358 : 0 : shost->host_lock = &shost->default_lock;
359 : 0 : spin_lock_init(shost->host_lock);
360 : 0 : shost->shost_state = SHOST_CREATED;
361 : 0 : INIT_LIST_HEAD(&shost->__devices);
362 : 0 : INIT_LIST_HEAD(&shost->__targets);
363 : 0 : INIT_LIST_HEAD(&shost->eh_cmd_q);
364 : 0 : INIT_LIST_HEAD(&shost->starved_list);
365 : 0 : init_waitqueue_head(&shost->host_wait);
366 : 0 : mutex_init(&shost->scan_mutex);
367 : :
368 : : /*
369 : : * subtract one because we increment first then return, but we need to
370 : : * know what the next host number was before increment
371 : : */
372 : 0 : shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1;
373 : 0 : shost->dma_channel = 0xff;
374 : :
375 : : /* These three are default values which can be overridden */
376 : 0 : shost->max_channel = 0;
377 : 0 : shost->max_id = 8;
378 : 0 : shost->max_lun = 8;
379 : :
380 : : /* Give each shost a default transportt */
381 : 0 : shost->transportt = &blank_transport_template;
382 : :
383 : : /*
384 : : * All drivers right now should be able to handle 12 byte
385 : : * commands. Every so often there are requests for 16 byte
386 : : * commands, but individual low-level drivers need to certify that
387 : : * they actually do something sensible with such commands.
388 : : */
389 : 0 : shost->max_cmd_len = 12;
390 : 0 : shost->hostt = sht;
391 : 0 : shost->this_id = sht->this_id;
392 : 0 : shost->can_queue = sht->can_queue;
393 : 0 : shost->sg_tablesize = sht->sg_tablesize;
394 : 0 : shost->sg_prot_tablesize = sht->sg_prot_tablesize;
395 : 0 : shost->cmd_per_lun = sht->cmd_per_lun;
396 : 0 : shost->unchecked_isa_dma = sht->unchecked_isa_dma;
397 : 0 : shost->use_clustering = sht->use_clustering;
398 : 0 : shost->ordered_tag = sht->ordered_tag;
399 : 0 : shost->no_write_same = sht->no_write_same;
400 : :
401 [ # # ]: 0 : if (shost_eh_deadline == -1)
402 : 0 : shost->eh_deadline = -1;
403 [ # # ]: 0 : else if ((ulong) shost_eh_deadline * HZ > INT_MAX) {
404 : 0 : shost_printk(KERN_WARNING, shost,
405 : : "eh_deadline %u too large, setting to %u\n",
406 : : shost_eh_deadline, INT_MAX / HZ);
407 : 0 : shost->eh_deadline = INT_MAX;
408 : : } else
409 : 0 : shost->eh_deadline = shost_eh_deadline * HZ;
410 : :
411 [ # # ]: 0 : if (sht->supported_mode == MODE_UNKNOWN)
412 : : /* means we didn't set it ... default to INITIATOR */
413 : 0 : shost->active_mode = MODE_INITIATOR;
414 : : else
415 : 0 : shost->active_mode = sht->supported_mode;
416 : :
417 [ # # ]: 0 : if (sht->max_host_blocked)
418 : 0 : shost->max_host_blocked = sht->max_host_blocked;
419 : : else
420 : 0 : shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED;
421 : :
422 : : /*
423 : : * If the driver imposes no hard sector transfer limit, start at
424 : : * machine infinity initially.
425 : : */
426 [ # # ]: 0 : if (sht->max_sectors)
427 : 0 : shost->max_sectors = sht->max_sectors;
428 : : else
429 : 0 : shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
430 : :
431 : : /*
432 : : * assume a 4GB boundary, if not set
433 : : */
434 [ # # ]: 0 : if (sht->dma_boundary)
435 : 0 : shost->dma_boundary = sht->dma_boundary;
436 : : else
437 : 0 : shost->dma_boundary = 0xffffffff;
438 : :
439 : 0 : device_initialize(&shost->shost_gendev);
440 : 0 : dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
441 : 0 : shost->shost_gendev.bus = &scsi_bus_type;
442 : 0 : shost->shost_gendev.type = &scsi_host_type;
443 : :
444 : 0 : device_initialize(&shost->shost_dev);
445 : 0 : shost->shost_dev.parent = &shost->shost_gendev;
446 : 0 : shost->shost_dev.class = &shost_class;
447 : 0 : dev_set_name(&shost->shost_dev, "host%d", shost->host_no);
448 : 0 : shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
449 : :
450 [ # # ]: 0 : shost->ehandler = kthread_run(scsi_error_handler, shost,
451 : : "scsi_eh_%d", shost->host_no);
452 [ # # ]: 0 : if (IS_ERR(shost->ehandler)) {
453 : 0 : printk(KERN_WARNING "scsi%d: error handler thread failed to spawn, error = %ld\n",
454 : : shost->host_no, PTR_ERR(shost->ehandler));
455 : 0 : goto fail_kfree;
456 : : }
457 : :
458 : 0 : shost->tmf_work_q = alloc_workqueue("scsi_tmf_%d",
459 : : WQ_UNBOUND | WQ_MEM_RECLAIM,
460 : : 1, shost->host_no);
461 [ # # ]: 0 : if (!shost->tmf_work_q) {
462 : 0 : printk(KERN_WARNING "scsi%d: failed to create tmf workq\n",
463 : : shost->host_no);
464 : : goto fail_kthread;
465 : : }
466 : 0 : scsi_proc_hostdir_add(shost->hostt);
467 : 0 : return shost;
468 : :
469 : : fail_kthread:
470 : 0 : kthread_stop(shost->ehandler);
471 : : fail_kfree:
472 : 0 : kfree(shost);
473 : 0 : return NULL;
474 : : }
475 : : EXPORT_SYMBOL(scsi_host_alloc);
476 : :
477 : 0 : struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize)
478 : : {
479 : 0 : struct Scsi_Host *shost = scsi_host_alloc(sht, privsize);
480 : :
481 [ # # ]: 0 : if (!sht->detect) {
482 : 0 : printk(KERN_WARNING "scsi_register() called on new-style "
483 : : "template for driver %s\n", sht->name);
484 : 0 : dump_stack();
485 : : }
486 : :
487 [ # # ]: 0 : if (shost)
488 : 0 : list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts);
489 : 0 : return shost;
490 : : }
491 : : EXPORT_SYMBOL(scsi_register);
492 : :
493 : 0 : void scsi_unregister(struct Scsi_Host *shost)
494 : : {
495 : : list_del(&shost->sht_legacy_list);
496 : : scsi_host_put(shost);
497 : 0 : }
498 : : EXPORT_SYMBOL(scsi_unregister);
499 : :
500 : 0 : static int __scsi_host_match(struct device *dev, const void *data)
501 : : {
502 : : struct Scsi_Host *p;
503 : : const unsigned short *hostnum = data;
504 : :
505 : : p = class_to_shost(dev);
506 : 0 : return p->host_no == *hostnum;
507 : : }
508 : :
509 : : /**
510 : : * scsi_host_lookup - get a reference to a Scsi_Host by host no
511 : : * @hostnum: host number to locate
512 : : *
513 : : * Return value:
514 : : * A pointer to located Scsi_Host or NULL.
515 : : *
516 : : * The caller must do a scsi_host_put() to drop the reference
517 : : * that scsi_host_get() took. The put_device() below dropped
518 : : * the reference from class_find_device().
519 : : **/
520 : 0 : struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
521 : : {
522 : : struct device *cdev;
523 : : struct Scsi_Host *shost = NULL;
524 : :
525 : 0 : cdev = class_find_device(&shost_class, NULL, &hostnum,
526 : : __scsi_host_match);
527 [ # # ]: 0 : if (cdev) {
528 : 0 : shost = scsi_host_get(class_to_shost(cdev));
529 : 0 : put_device(cdev);
530 : : }
531 : 0 : return shost;
532 : : }
533 : : EXPORT_SYMBOL(scsi_host_lookup);
534 : :
535 : : /**
536 : : * scsi_host_get - inc a Scsi_Host ref count
537 : : * @shost: Pointer to Scsi_Host to inc.
538 : : **/
539 : 0 : struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
540 : : {
541 [ # # # # ]: 0 : if ((shost->shost_state == SHOST_DEL) ||
[ # # # # ]
542 : 0 : !get_device(&shost->shost_gendev))
543 : : return NULL;
544 : 0 : return shost;
545 : : }
546 : : EXPORT_SYMBOL(scsi_host_get);
547 : :
548 : : /**
549 : : * scsi_host_put - dec a Scsi_Host ref count
550 : : * @shost: Pointer to Scsi_Host to dec.
551 : : **/
552 : 0 : void scsi_host_put(struct Scsi_Host *shost)
553 : : {
554 : 0 : put_device(&shost->shost_gendev);
555 : 0 : }
556 : : EXPORT_SYMBOL(scsi_host_put);
557 : :
558 : 0 : int scsi_init_hosts(void)
559 : : {
560 : 0 : return class_register(&shost_class);
561 : : }
562 : :
563 : 0 : void scsi_exit_hosts(void)
564 : : {
565 : 0 : class_unregister(&shost_class);
566 : 0 : }
567 : :
568 : 0 : int scsi_is_host_device(const struct device *dev)
569 : : {
570 : 0 : return dev->type == &scsi_host_type;
571 : : }
572 : : EXPORT_SYMBOL(scsi_is_host_device);
573 : :
574 : : /**
575 : : * scsi_queue_work - Queue work to the Scsi_Host workqueue.
576 : : * @shost: Pointer to Scsi_Host.
577 : : * @work: Work to queue for execution.
578 : : *
579 : : * Return value:
580 : : * 1 - work queued for execution
581 : : * 0 - work is already queued
582 : : * -EINVAL - work queue doesn't exist
583 : : **/
584 : 0 : int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
585 : : {
586 [ # # ]: 0 : if (unlikely(!shost->work_q)) {
587 : 0 : printk(KERN_ERR
588 : : "ERROR: Scsi host '%s' attempted to queue scsi-work, "
589 : 0 : "when no workqueue created.\n", shost->hostt->name);
590 : 0 : dump_stack();
591 : :
592 : 0 : return -EINVAL;
593 : : }
594 : :
595 : 0 : return queue_work(shost->work_q, work);
596 : : }
597 : : EXPORT_SYMBOL_GPL(scsi_queue_work);
598 : :
599 : : /**
600 : : * scsi_flush_work - Flush a Scsi_Host's workqueue.
601 : : * @shost: Pointer to Scsi_Host.
602 : : **/
603 : 0 : void scsi_flush_work(struct Scsi_Host *shost)
604 : : {
605 [ # # ]: 0 : if (!shost->work_q) {
606 : 0 : printk(KERN_ERR
607 : : "ERROR: Scsi host '%s' attempted to flush scsi-work, "
608 : 0 : "when no workqueue created.\n", shost->hostt->name);
609 : 0 : dump_stack();
610 : 0 : return;
611 : : }
612 : :
613 : 0 : flush_workqueue(shost->work_q);
614 : : }
615 : : EXPORT_SYMBOL_GPL(scsi_flush_work);
|