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