diff options
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r-- | drivers/s390/block/dasd.c | 2065 |
1 files changed, 2065 insertions, 0 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c new file mode 100644 index 000000000000..b755bac6ccbc --- /dev/null +++ b/drivers/s390/block/dasd.c | |||
@@ -0,0 +1,2065 @@ | |||
1 | /* | ||
2 | * File...........: linux/drivers/s390/block/dasd.c | ||
3 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> | ||
4 | * Horst Hummel <Horst.Hummel@de.ibm.com> | ||
5 | * Carsten Otte <Cotte@de.ibm.com> | ||
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
7 | * Bugreports.to..: <Linux390@de.ibm.com> | ||
8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 | ||
9 | * | ||
10 | * $Revision: 1.158 $ | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/kmod.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/ctype.h> | ||
18 | #include <linux/major.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/buffer_head.h> | ||
21 | |||
22 | #include <asm/ccwdev.h> | ||
23 | #include <asm/ebcdic.h> | ||
24 | #include <asm/idals.h> | ||
25 | #include <asm/todclk.h> | ||
26 | |||
27 | /* This is ugly... */ | ||
28 | #define PRINTK_HEADER "dasd:" | ||
29 | |||
30 | #include "dasd_int.h" | ||
31 | /* | ||
32 | * SECTION: Constant definitions to be used within this file | ||
33 | */ | ||
34 | #define DASD_CHANQ_MAX_SIZE 4 | ||
35 | |||
36 | /* | ||
37 | * SECTION: exported variables of dasd.c | ||
38 | */ | ||
39 | debug_info_t *dasd_debug_area; | ||
40 | struct dasd_discipline *dasd_diag_discipline_pointer; | ||
41 | |||
42 | MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>"); | ||
43 | MODULE_DESCRIPTION("Linux on S/390 DASD device driver," | ||
44 | " Copyright 2000 IBM Corporation"); | ||
45 | MODULE_SUPPORTED_DEVICE("dasd"); | ||
46 | MODULE_PARM(dasd, "1-" __MODULE_STRING(256) "s"); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | |||
49 | /* | ||
50 | * SECTION: prototypes for static functions of dasd.c | ||
51 | */ | ||
52 | static int dasd_alloc_queue(struct dasd_device * device); | ||
53 | static void dasd_setup_queue(struct dasd_device * device); | ||
54 | static void dasd_free_queue(struct dasd_device * device); | ||
55 | static void dasd_flush_request_queue(struct dasd_device *); | ||
56 | static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); | ||
57 | static void dasd_flush_ccw_queue(struct dasd_device *, int); | ||
58 | static void dasd_tasklet(struct dasd_device *); | ||
59 | static void do_kick_device(void *data); | ||
60 | |||
61 | /* | ||
62 | * SECTION: Operations on the device structure. | ||
63 | */ | ||
64 | static wait_queue_head_t dasd_init_waitq; | ||
65 | |||
66 | /* | ||
67 | * Allocate memory for a new device structure. | ||
68 | */ | ||
69 | struct dasd_device * | ||
70 | dasd_alloc_device(void) | ||
71 | { | ||
72 | struct dasd_device *device; | ||
73 | |||
74 | device = kmalloc(sizeof (struct dasd_device), GFP_ATOMIC); | ||
75 | if (device == NULL) | ||
76 | return ERR_PTR(-ENOMEM); | ||
77 | memset(device, 0, sizeof (struct dasd_device)); | ||
78 | /* open_count = 0 means device online but not in use */ | ||
79 | atomic_set(&device->open_count, -1); | ||
80 | |||
81 | /* Get two pages for normal block device operations. */ | ||
82 | device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1); | ||
83 | if (device->ccw_mem == NULL) { | ||
84 | kfree(device); | ||
85 | return ERR_PTR(-ENOMEM); | ||
86 | } | ||
87 | /* Get one page for error recovery. */ | ||
88 | device->erp_mem = (void *) get_zeroed_page(GFP_ATOMIC | GFP_DMA); | ||
89 | if (device->erp_mem == NULL) { | ||
90 | free_pages((unsigned long) device->ccw_mem, 1); | ||
91 | kfree(device); | ||
92 | return ERR_PTR(-ENOMEM); | ||
93 | } | ||
94 | |||
95 | dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2); | ||
96 | dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE); | ||
97 | spin_lock_init(&device->mem_lock); | ||
98 | spin_lock_init(&device->request_queue_lock); | ||
99 | atomic_set (&device->tasklet_scheduled, 0); | ||
100 | tasklet_init(&device->tasklet, | ||
101 | (void (*)(unsigned long)) dasd_tasklet, | ||
102 | (unsigned long) device); | ||
103 | INIT_LIST_HEAD(&device->ccw_queue); | ||
104 | init_timer(&device->timer); | ||
105 | INIT_WORK(&device->kick_work, do_kick_device, device); | ||
106 | device->state = DASD_STATE_NEW; | ||
107 | device->target = DASD_STATE_NEW; | ||
108 | |||
109 | return device; | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Free memory of a device structure. | ||
114 | */ | ||
115 | void | ||
116 | dasd_free_device(struct dasd_device *device) | ||
117 | { | ||
118 | if (device->private) | ||
119 | kfree(device->private); | ||
120 | free_page((unsigned long) device->erp_mem); | ||
121 | free_pages((unsigned long) device->ccw_mem, 1); | ||
122 | kfree(device); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Make a new device known to the system. | ||
127 | */ | ||
128 | static inline int | ||
129 | dasd_state_new_to_known(struct dasd_device *device) | ||
130 | { | ||
131 | int rc; | ||
132 | |||
133 | /* | ||
134 | * As long as the device is not in state DASD_STATE_NEW we want to | ||
135 | * keep the reference count > 0. | ||
136 | */ | ||
137 | dasd_get_device(device); | ||
138 | |||
139 | rc = dasd_alloc_queue(device); | ||
140 | if (rc) { | ||
141 | dasd_put_device(device); | ||
142 | return rc; | ||
143 | } | ||
144 | |||
145 | device->state = DASD_STATE_KNOWN; | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * Let the system forget about a device. | ||
151 | */ | ||
152 | static inline void | ||
153 | dasd_state_known_to_new(struct dasd_device * device) | ||
154 | { | ||
155 | /* Forget the discipline information. */ | ||
156 | device->discipline = NULL; | ||
157 | device->state = DASD_STATE_NEW; | ||
158 | |||
159 | dasd_free_queue(device); | ||
160 | |||
161 | /* Give up reference we took in dasd_state_new_to_known. */ | ||
162 | dasd_put_device(device); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Request the irq line for the device. | ||
167 | */ | ||
168 | static inline int | ||
169 | dasd_state_known_to_basic(struct dasd_device * device) | ||
170 | { | ||
171 | int rc; | ||
172 | |||
173 | /* Allocate and register gendisk structure. */ | ||
174 | rc = dasd_gendisk_alloc(device); | ||
175 | if (rc) | ||
176 | return rc; | ||
177 | |||
178 | /* register 'device' debug area, used for all DBF_DEV_XXX calls */ | ||
179 | device->debug_area = debug_register(device->cdev->dev.bus_id, 0, 2, | ||
180 | 8 * sizeof (long)); | ||
181 | debug_register_view(device->debug_area, &debug_sprintf_view); | ||
182 | debug_set_level(device->debug_area, DBF_EMERG); | ||
183 | DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created"); | ||
184 | |||
185 | device->state = DASD_STATE_BASIC; | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Release the irq line for the device. Terminate any running i/o. | ||
191 | */ | ||
192 | static inline void | ||
193 | dasd_state_basic_to_known(struct dasd_device * device) | ||
194 | { | ||
195 | dasd_gendisk_free(device); | ||
196 | dasd_flush_ccw_queue(device, 1); | ||
197 | DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); | ||
198 | if (device->debug_area != NULL) { | ||
199 | debug_unregister(device->debug_area); | ||
200 | device->debug_area = NULL; | ||
201 | } | ||
202 | device->state = DASD_STATE_KNOWN; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Do the initial analysis. The do_analysis function may return | ||
207 | * -EAGAIN in which case the device keeps the state DASD_STATE_BASIC | ||
208 | * until the discipline decides to continue the startup sequence | ||
209 | * by calling the function dasd_change_state. The eckd disciplines | ||
210 | * uses this to start a ccw that detects the format. The completion | ||
211 | * interrupt for this detection ccw uses the kernel event daemon to | ||
212 | * trigger the call to dasd_change_state. All this is done in the | ||
213 | * discipline code, see dasd_eckd.c. | ||
214 | * After the analysis ccw is done (do_analysis returned 0 or error) | ||
215 | * the block device is setup. Either a fake disk is added to allow | ||
216 | * formatting or a proper device request queue is created. | ||
217 | */ | ||
218 | static inline int | ||
219 | dasd_state_basic_to_ready(struct dasd_device * device) | ||
220 | { | ||
221 | int rc; | ||
222 | |||
223 | rc = 0; | ||
224 | if (device->discipline->do_analysis != NULL) | ||
225 | rc = device->discipline->do_analysis(device); | ||
226 | if (rc) | ||
227 | return rc; | ||
228 | dasd_setup_queue(device); | ||
229 | device->state = DASD_STATE_READY; | ||
230 | if (dasd_scan_partitions(device) != 0) | ||
231 | device->state = DASD_STATE_BASIC; | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * Remove device from block device layer. Destroy dirty buffers. | ||
237 | * Forget format information. Check if the target level is basic | ||
238 | * and if it is create fake disk for formatting. | ||
239 | */ | ||
240 | static inline void | ||
241 | dasd_state_ready_to_basic(struct dasd_device * device) | ||
242 | { | ||
243 | dasd_flush_ccw_queue(device, 0); | ||
244 | dasd_destroy_partitions(device); | ||
245 | dasd_flush_request_queue(device); | ||
246 | device->blocks = 0; | ||
247 | device->bp_block = 0; | ||
248 | device->s2b_shift = 0; | ||
249 | device->state = DASD_STATE_BASIC; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * Make the device online and schedule the bottom half to start | ||
254 | * the requeueing of requests from the linux request queue to the | ||
255 | * ccw queue. | ||
256 | */ | ||
257 | static inline int | ||
258 | dasd_state_ready_to_online(struct dasd_device * device) | ||
259 | { | ||
260 | device->state = DASD_STATE_ONLINE; | ||
261 | dasd_schedule_bh(device); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Stop the requeueing of requests again. | ||
267 | */ | ||
268 | static inline void | ||
269 | dasd_state_online_to_ready(struct dasd_device * device) | ||
270 | { | ||
271 | device->state = DASD_STATE_READY; | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * Device startup state changes. | ||
276 | */ | ||
277 | static inline int | ||
278 | dasd_increase_state(struct dasd_device *device) | ||
279 | { | ||
280 | int rc; | ||
281 | |||
282 | rc = 0; | ||
283 | if (device->state == DASD_STATE_NEW && | ||
284 | device->target >= DASD_STATE_KNOWN) | ||
285 | rc = dasd_state_new_to_known(device); | ||
286 | |||
287 | if (!rc && | ||
288 | device->state == DASD_STATE_KNOWN && | ||
289 | device->target >= DASD_STATE_BASIC) | ||
290 | rc = dasd_state_known_to_basic(device); | ||
291 | |||
292 | if (!rc && | ||
293 | device->state == DASD_STATE_BASIC && | ||
294 | device->target >= DASD_STATE_READY) | ||
295 | rc = dasd_state_basic_to_ready(device); | ||
296 | |||
297 | if (!rc && | ||
298 | device->state == DASD_STATE_READY && | ||
299 | device->target >= DASD_STATE_ONLINE) | ||
300 | rc = dasd_state_ready_to_online(device); | ||
301 | |||
302 | return rc; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * Device shutdown state changes. | ||
307 | */ | ||
308 | static inline int | ||
309 | dasd_decrease_state(struct dasd_device *device) | ||
310 | { | ||
311 | if (device->state == DASD_STATE_ONLINE && | ||
312 | device->target <= DASD_STATE_READY) | ||
313 | dasd_state_online_to_ready(device); | ||
314 | |||
315 | if (device->state == DASD_STATE_READY && | ||
316 | device->target <= DASD_STATE_BASIC) | ||
317 | dasd_state_ready_to_basic(device); | ||
318 | |||
319 | if (device->state == DASD_STATE_BASIC && | ||
320 | device->target <= DASD_STATE_KNOWN) | ||
321 | dasd_state_basic_to_known(device); | ||
322 | |||
323 | if (device->state == DASD_STATE_KNOWN && | ||
324 | device->target <= DASD_STATE_NEW) | ||
325 | dasd_state_known_to_new(device); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * This is the main startup/shutdown routine. | ||
332 | */ | ||
333 | static void | ||
334 | dasd_change_state(struct dasd_device *device) | ||
335 | { | ||
336 | int rc; | ||
337 | |||
338 | if (device->state == device->target) | ||
339 | /* Already where we want to go today... */ | ||
340 | return; | ||
341 | if (device->state < device->target) | ||
342 | rc = dasd_increase_state(device); | ||
343 | else | ||
344 | rc = dasd_decrease_state(device); | ||
345 | if (rc && rc != -EAGAIN) | ||
346 | device->target = device->state; | ||
347 | |||
348 | if (device->state == device->target) | ||
349 | wake_up(&dasd_init_waitq); | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Kick starter for devices that did not complete the startup/shutdown | ||
354 | * procedure or were sleeping because of a pending state. | ||
355 | * dasd_kick_device will schedule a call do do_kick_device to the kernel | ||
356 | * event daemon. | ||
357 | */ | ||
358 | static void | ||
359 | do_kick_device(void *data) | ||
360 | { | ||
361 | struct dasd_device *device; | ||
362 | |||
363 | device = (struct dasd_device *) data; | ||
364 | dasd_change_state(device); | ||
365 | dasd_schedule_bh(device); | ||
366 | dasd_put_device(device); | ||
367 | } | ||
368 | |||
369 | void | ||
370 | dasd_kick_device(struct dasd_device *device) | ||
371 | { | ||
372 | dasd_get_device(device); | ||
373 | /* queue call to dasd_kick_device to the kernel event daemon. */ | ||
374 | schedule_work(&device->kick_work); | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * Set the target state for a device and starts the state change. | ||
379 | */ | ||
380 | void | ||
381 | dasd_set_target_state(struct dasd_device *device, int target) | ||
382 | { | ||
383 | /* If we are in probeonly mode stop at DASD_STATE_READY. */ | ||
384 | if (dasd_probeonly && target > DASD_STATE_READY) | ||
385 | target = DASD_STATE_READY; | ||
386 | if (device->target != target) { | ||
387 | if (device->state == target) | ||
388 | wake_up(&dasd_init_waitq); | ||
389 | device->target = target; | ||
390 | } | ||
391 | if (device->state != device->target) | ||
392 | dasd_change_state(device); | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * Enable devices with device numbers in [from..to]. | ||
397 | */ | ||
398 | static inline int | ||
399 | _wait_for_device(struct dasd_device *device) | ||
400 | { | ||
401 | return (device->state == device->target); | ||
402 | } | ||
403 | |||
404 | void | ||
405 | dasd_enable_device(struct dasd_device *device) | ||
406 | { | ||
407 | dasd_set_target_state(device, DASD_STATE_ONLINE); | ||
408 | if (device->state <= DASD_STATE_KNOWN) | ||
409 | /* No discipline for device found. */ | ||
410 | dasd_set_target_state(device, DASD_STATE_NEW); | ||
411 | /* Now wait for the devices to come up. */ | ||
412 | wait_event(dasd_init_waitq, _wait_for_device(device)); | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | * SECTION: device operation (interrupt handler, start i/o, term i/o ...) | ||
417 | */ | ||
418 | #ifdef CONFIG_DASD_PROFILE | ||
419 | |||
420 | struct dasd_profile_info_t dasd_global_profile; | ||
421 | unsigned int dasd_profile_level = DASD_PROFILE_OFF; | ||
422 | |||
423 | /* | ||
424 | * Increments counter in global and local profiling structures. | ||
425 | */ | ||
426 | #define dasd_profile_counter(value, counter, device) \ | ||
427 | { \ | ||
428 | int index; \ | ||
429 | for (index = 0; index < 31 && value >> (2+index); index++); \ | ||
430 | dasd_global_profile.counter[index]++; \ | ||
431 | device->profile.counter[index]++; \ | ||
432 | } | ||
433 | |||
434 | /* | ||
435 | * Add profiling information for cqr before execution. | ||
436 | */ | ||
437 | static inline void | ||
438 | dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr, | ||
439 | struct request *req) | ||
440 | { | ||
441 | struct list_head *l; | ||
442 | unsigned int counter; | ||
443 | |||
444 | if (dasd_profile_level != DASD_PROFILE_ON) | ||
445 | return; | ||
446 | |||
447 | /* count the length of the chanq for statistics */ | ||
448 | counter = 0; | ||
449 | list_for_each(l, &device->ccw_queue) | ||
450 | if (++counter >= 31) | ||
451 | break; | ||
452 | dasd_global_profile.dasd_io_nr_req[counter]++; | ||
453 | device->profile.dasd_io_nr_req[counter]++; | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * Add profiling information for cqr after execution. | ||
458 | */ | ||
459 | static inline void | ||
460 | dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr, | ||
461 | struct request *req) | ||
462 | { | ||
463 | long strtime, irqtime, endtime, tottime; /* in microseconds */ | ||
464 | long tottimeps, sectors; | ||
465 | |||
466 | if (dasd_profile_level != DASD_PROFILE_ON) | ||
467 | return; | ||
468 | |||
469 | sectors = req->nr_sectors; | ||
470 | if (!cqr->buildclk || !cqr->startclk || | ||
471 | !cqr->stopclk || !cqr->endclk || | ||
472 | !sectors) | ||
473 | return; | ||
474 | |||
475 | strtime = ((cqr->startclk - cqr->buildclk) >> 12); | ||
476 | irqtime = ((cqr->stopclk - cqr->startclk) >> 12); | ||
477 | endtime = ((cqr->endclk - cqr->stopclk) >> 12); | ||
478 | tottime = ((cqr->endclk - cqr->buildclk) >> 12); | ||
479 | tottimeps = tottime / sectors; | ||
480 | |||
481 | if (!dasd_global_profile.dasd_io_reqs) | ||
482 | memset(&dasd_global_profile, 0, | ||
483 | sizeof (struct dasd_profile_info_t)); | ||
484 | dasd_global_profile.dasd_io_reqs++; | ||
485 | dasd_global_profile.dasd_io_sects += sectors; | ||
486 | |||
487 | if (!device->profile.dasd_io_reqs) | ||
488 | memset(&device->profile, 0, | ||
489 | sizeof (struct dasd_profile_info_t)); | ||
490 | device->profile.dasd_io_reqs++; | ||
491 | device->profile.dasd_io_sects += sectors; | ||
492 | |||
493 | dasd_profile_counter(sectors, dasd_io_secs, device); | ||
494 | dasd_profile_counter(tottime, dasd_io_times, device); | ||
495 | dasd_profile_counter(tottimeps, dasd_io_timps, device); | ||
496 | dasd_profile_counter(strtime, dasd_io_time1, device); | ||
497 | dasd_profile_counter(irqtime, dasd_io_time2, device); | ||
498 | dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, device); | ||
499 | dasd_profile_counter(endtime, dasd_io_time3, device); | ||
500 | } | ||
501 | #else | ||
502 | #define dasd_profile_start(device, cqr, req) do {} while (0) | ||
503 | #define dasd_profile_end(device, cqr, req) do {} while (0) | ||
504 | #endif /* CONFIG_DASD_PROFILE */ | ||
505 | |||
506 | /* | ||
507 | * Allocate memory for a channel program with 'cplength' channel | ||
508 | * command words and 'datasize' additional space. There are two | ||
509 | * variantes: 1) dasd_kmalloc_request uses kmalloc to get the needed | ||
510 | * memory and 2) dasd_smalloc_request uses the static ccw memory | ||
511 | * that gets allocated for each device. | ||
512 | */ | ||
513 | struct dasd_ccw_req * | ||
514 | dasd_kmalloc_request(char *magic, int cplength, int datasize, | ||
515 | struct dasd_device * device) | ||
516 | { | ||
517 | struct dasd_ccw_req *cqr; | ||
518 | |||
519 | /* Sanity checks */ | ||
520 | if ( magic == NULL || datasize > PAGE_SIZE || | ||
521 | (cplength*sizeof(struct ccw1)) > PAGE_SIZE) | ||
522 | BUG(); | ||
523 | |||
524 | cqr = kmalloc(sizeof(struct dasd_ccw_req), GFP_ATOMIC); | ||
525 | if (cqr == NULL) | ||
526 | return ERR_PTR(-ENOMEM); | ||
527 | memset(cqr, 0, sizeof(struct dasd_ccw_req)); | ||
528 | cqr->cpaddr = NULL; | ||
529 | if (cplength > 0) { | ||
530 | cqr->cpaddr = kmalloc(cplength*sizeof(struct ccw1), | ||
531 | GFP_ATOMIC | GFP_DMA); | ||
532 | if (cqr->cpaddr == NULL) { | ||
533 | kfree(cqr); | ||
534 | return ERR_PTR(-ENOMEM); | ||
535 | } | ||
536 | memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1)); | ||
537 | } | ||
538 | cqr->data = NULL; | ||
539 | if (datasize > 0) { | ||
540 | cqr->data = kmalloc(datasize, GFP_ATOMIC | GFP_DMA); | ||
541 | if (cqr->data == NULL) { | ||
542 | if (cqr->cpaddr != NULL) | ||
543 | kfree(cqr->cpaddr); | ||
544 | kfree(cqr); | ||
545 | return ERR_PTR(-ENOMEM); | ||
546 | } | ||
547 | memset(cqr->data, 0, datasize); | ||
548 | } | ||
549 | strncpy((char *) &cqr->magic, magic, 4); | ||
550 | ASCEBC((char *) &cqr->magic, 4); | ||
551 | set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | ||
552 | dasd_get_device(device); | ||
553 | return cqr; | ||
554 | } | ||
555 | |||
556 | struct dasd_ccw_req * | ||
557 | dasd_smalloc_request(char *magic, int cplength, int datasize, | ||
558 | struct dasd_device * device) | ||
559 | { | ||
560 | unsigned long flags; | ||
561 | struct dasd_ccw_req *cqr; | ||
562 | char *data; | ||
563 | int size; | ||
564 | |||
565 | /* Sanity checks */ | ||
566 | if ( magic == NULL || datasize > PAGE_SIZE || | ||
567 | (cplength*sizeof(struct ccw1)) > PAGE_SIZE) | ||
568 | BUG(); | ||
569 | |||
570 | size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; | ||
571 | if (cplength > 0) | ||
572 | size += cplength * sizeof(struct ccw1); | ||
573 | if (datasize > 0) | ||
574 | size += datasize; | ||
575 | spin_lock_irqsave(&device->mem_lock, flags); | ||
576 | cqr = (struct dasd_ccw_req *) | ||
577 | dasd_alloc_chunk(&device->ccw_chunks, size); | ||
578 | spin_unlock_irqrestore(&device->mem_lock, flags); | ||
579 | if (cqr == NULL) | ||
580 | return ERR_PTR(-ENOMEM); | ||
581 | memset(cqr, 0, sizeof(struct dasd_ccw_req)); | ||
582 | data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L); | ||
583 | cqr->cpaddr = NULL; | ||
584 | if (cplength > 0) { | ||
585 | cqr->cpaddr = (struct ccw1 *) data; | ||
586 | data += cplength*sizeof(struct ccw1); | ||
587 | memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1)); | ||
588 | } | ||
589 | cqr->data = NULL; | ||
590 | if (datasize > 0) { | ||
591 | cqr->data = data; | ||
592 | memset(cqr->data, 0, datasize); | ||
593 | } | ||
594 | strncpy((char *) &cqr->magic, magic, 4); | ||
595 | ASCEBC((char *) &cqr->magic, 4); | ||
596 | set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | ||
597 | dasd_get_device(device); | ||
598 | return cqr; | ||
599 | } | ||
600 | |||
601 | /* | ||
602 | * Free memory of a channel program. This function needs to free all the | ||
603 | * idal lists that might have been created by dasd_set_cda and the | ||
604 | * struct dasd_ccw_req itself. | ||
605 | */ | ||
606 | void | ||
607 | dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device) | ||
608 | { | ||
609 | #ifdef CONFIG_ARCH_S390X | ||
610 | struct ccw1 *ccw; | ||
611 | |||
612 | /* Clear any idals used for the request. */ | ||
613 | ccw = cqr->cpaddr; | ||
614 | do { | ||
615 | clear_normalized_cda(ccw); | ||
616 | } while (ccw++->flags & (CCW_FLAG_CC | CCW_FLAG_DC)); | ||
617 | #endif | ||
618 | if (cqr->cpaddr != NULL) | ||
619 | kfree(cqr->cpaddr); | ||
620 | if (cqr->data != NULL) | ||
621 | kfree(cqr->data); | ||
622 | kfree(cqr); | ||
623 | dasd_put_device(device); | ||
624 | } | ||
625 | |||
626 | void | ||
627 | dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device) | ||
628 | { | ||
629 | unsigned long flags; | ||
630 | |||
631 | spin_lock_irqsave(&device->mem_lock, flags); | ||
632 | dasd_free_chunk(&device->ccw_chunks, cqr); | ||
633 | spin_unlock_irqrestore(&device->mem_lock, flags); | ||
634 | dasd_put_device(device); | ||
635 | } | ||
636 | |||
637 | /* | ||
638 | * Check discipline magic in cqr. | ||
639 | */ | ||
640 | static inline int | ||
641 | dasd_check_cqr(struct dasd_ccw_req *cqr) | ||
642 | { | ||
643 | struct dasd_device *device; | ||
644 | |||
645 | if (cqr == NULL) | ||
646 | return -EINVAL; | ||
647 | device = cqr->device; | ||
648 | if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) { | ||
649 | DEV_MESSAGE(KERN_WARNING, device, | ||
650 | " dasd_ccw_req 0x%08x magic doesn't match" | ||
651 | " discipline 0x%08x", | ||
652 | cqr->magic, | ||
653 | *(unsigned int *) device->discipline->name); | ||
654 | return -EINVAL; | ||
655 | } | ||
656 | return 0; | ||
657 | } | ||
658 | |||
659 | /* | ||
660 | * Terminate the current i/o and set the request to clear_pending. | ||
661 | * Timer keeps device runnig. | ||
662 | * ccw_device_clear can fail if the i/o subsystem | ||
663 | * is in a bad mood. | ||
664 | */ | ||
665 | int | ||
666 | dasd_term_IO(struct dasd_ccw_req * cqr) | ||
667 | { | ||
668 | struct dasd_device *device; | ||
669 | int retries, rc; | ||
670 | |||
671 | /* Check the cqr */ | ||
672 | rc = dasd_check_cqr(cqr); | ||
673 | if (rc) | ||
674 | return rc; | ||
675 | retries = 0; | ||
676 | device = (struct dasd_device *) cqr->device; | ||
677 | while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) { | ||
678 | rc = ccw_device_clear(device->cdev, (long) cqr); | ||
679 | switch (rc) { | ||
680 | case 0: /* termination successful */ | ||
681 | if (cqr->retries > 0) { | ||
682 | cqr->retries--; | ||
683 | cqr->status = DASD_CQR_CLEAR; | ||
684 | } else | ||
685 | cqr->status = DASD_CQR_FAILED; | ||
686 | cqr->stopclk = get_clock(); | ||
687 | DBF_DEV_EVENT(DBF_DEBUG, device, | ||
688 | "terminate cqr %p successful", | ||
689 | cqr); | ||
690 | break; | ||
691 | case -ENODEV: | ||
692 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | ||
693 | "device gone, retry"); | ||
694 | break; | ||
695 | case -EIO: | ||
696 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | ||
697 | "I/O error, retry"); | ||
698 | break; | ||
699 | case -EINVAL: | ||
700 | case -EBUSY: | ||
701 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | ||
702 | "device busy, retry later"); | ||
703 | break; | ||
704 | default: | ||
705 | DEV_MESSAGE(KERN_ERR, device, | ||
706 | "line %d unknown RC=%d, please " | ||
707 | "report to linux390@de.ibm.com", | ||
708 | __LINE__, rc); | ||
709 | BUG(); | ||
710 | break; | ||
711 | } | ||
712 | retries++; | ||
713 | } | ||
714 | dasd_schedule_bh(device); | ||
715 | return rc; | ||
716 | } | ||
717 | |||
718 | /* | ||
719 | * Start the i/o. This start_IO can fail if the channel is really busy. | ||
720 | * In that case set up a timer to start the request later. | ||
721 | */ | ||
722 | int | ||
723 | dasd_start_IO(struct dasd_ccw_req * cqr) | ||
724 | { | ||
725 | struct dasd_device *device; | ||
726 | int rc; | ||
727 | |||
728 | /* Check the cqr */ | ||
729 | rc = dasd_check_cqr(cqr); | ||
730 | if (rc) | ||
731 | return rc; | ||
732 | device = (struct dasd_device *) cqr->device; | ||
733 | if (cqr->retries < 0) { | ||
734 | DEV_MESSAGE(KERN_DEBUG, device, | ||
735 | "start_IO: request %p (%02x/%i) - no retry left.", | ||
736 | cqr, cqr->status, cqr->retries); | ||
737 | cqr->status = DASD_CQR_FAILED; | ||
738 | return -EIO; | ||
739 | } | ||
740 | cqr->startclk = get_clock(); | ||
741 | cqr->starttime = jiffies; | ||
742 | cqr->retries--; | ||
743 | rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr, | ||
744 | cqr->lpm, 0); | ||
745 | switch (rc) { | ||
746 | case 0: | ||
747 | cqr->status = DASD_CQR_IN_IO; | ||
748 | DBF_DEV_EVENT(DBF_DEBUG, device, | ||
749 | "start_IO: request %p started successful", | ||
750 | cqr); | ||
751 | break; | ||
752 | case -EBUSY: | ||
753 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | ||
754 | "start_IO: device busy, retry later"); | ||
755 | break; | ||
756 | case -ETIMEDOUT: | ||
757 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | ||
758 | "start_IO: request timeout, retry later"); | ||
759 | break; | ||
760 | case -EACCES: | ||
761 | /* -EACCES indicates that the request used only a | ||
762 | * subset of the available pathes and all these | ||
763 | * pathes are gone. | ||
764 | * Do a retry with all available pathes. | ||
765 | */ | ||
766 | cqr->lpm = LPM_ANYPATH; | ||
767 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | ||
768 | "start_IO: selected pathes gone," | ||
769 | " retry on all pathes"); | ||
770 | break; | ||
771 | case -ENODEV: | ||
772 | case -EIO: | ||
773 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | ||
774 | "start_IO: device gone, retry"); | ||
775 | break; | ||
776 | default: | ||
777 | DEV_MESSAGE(KERN_ERR, device, | ||
778 | "line %d unknown RC=%d, please report" | ||
779 | " to linux390@de.ibm.com", __LINE__, rc); | ||
780 | BUG(); | ||
781 | break; | ||
782 | } | ||
783 | return rc; | ||
784 | } | ||
785 | |||
786 | /* | ||
787 | * Timeout function for dasd devices. This is used for different purposes | ||
788 | * 1) missing interrupt handler for normal operation | ||
789 | * 2) delayed start of request where start_IO failed with -EBUSY | ||
790 | * 3) timeout for missing state change interrupts | ||
791 | * The head of the ccw queue will have status DASD_CQR_IN_IO for 1), | ||
792 | * DASD_CQR_QUEUED for 2) and 3). | ||
793 | */ | ||
794 | static void | ||
795 | dasd_timeout_device(unsigned long ptr) | ||
796 | { | ||
797 | unsigned long flags; | ||
798 | struct dasd_device *device; | ||
799 | |||
800 | device = (struct dasd_device *) ptr; | ||
801 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
802 | /* re-activate request queue */ | ||
803 | device->stopped &= ~DASD_STOPPED_PENDING; | ||
804 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
805 | dasd_schedule_bh(device); | ||
806 | } | ||
807 | |||
808 | /* | ||
809 | * Setup timeout for a device in jiffies. | ||
810 | */ | ||
811 | void | ||
812 | dasd_set_timer(struct dasd_device *device, int expires) | ||
813 | { | ||
814 | if (expires == 0) { | ||
815 | if (timer_pending(&device->timer)) | ||
816 | del_timer(&device->timer); | ||
817 | return; | ||
818 | } | ||
819 | if (timer_pending(&device->timer)) { | ||
820 | if (mod_timer(&device->timer, jiffies + expires)) | ||
821 | return; | ||
822 | } | ||
823 | device->timer.function = dasd_timeout_device; | ||
824 | device->timer.data = (unsigned long) device; | ||
825 | device->timer.expires = jiffies + expires; | ||
826 | add_timer(&device->timer); | ||
827 | } | ||
828 | |||
829 | /* | ||
830 | * Clear timeout for a device. | ||
831 | */ | ||
832 | void | ||
833 | dasd_clear_timer(struct dasd_device *device) | ||
834 | { | ||
835 | if (timer_pending(&device->timer)) | ||
836 | del_timer(&device->timer); | ||
837 | } | ||
838 | |||
839 | static void | ||
840 | dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm) | ||
841 | { | ||
842 | struct dasd_ccw_req *cqr; | ||
843 | struct dasd_device *device; | ||
844 | |||
845 | cqr = (struct dasd_ccw_req *) intparm; | ||
846 | if (cqr->status != DASD_CQR_IN_IO) { | ||
847 | MESSAGE(KERN_DEBUG, | ||
848 | "invalid status in handle_killed_request: " | ||
849 | "bus_id %s, status %02x", | ||
850 | cdev->dev.bus_id, cqr->status); | ||
851 | return; | ||
852 | } | ||
853 | |||
854 | device = (struct dasd_device *) cqr->device; | ||
855 | if (device == NULL || | ||
856 | device != dasd_device_from_cdev(cdev) || | ||
857 | strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { | ||
858 | MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", | ||
859 | cdev->dev.bus_id); | ||
860 | return; | ||
861 | } | ||
862 | |||
863 | /* Schedule request to be retried. */ | ||
864 | cqr->status = DASD_CQR_QUEUED; | ||
865 | |||
866 | dasd_clear_timer(device); | ||
867 | dasd_schedule_bh(device); | ||
868 | dasd_put_device(device); | ||
869 | } | ||
870 | |||
871 | static void | ||
872 | dasd_handle_state_change_pending(struct dasd_device *device) | ||
873 | { | ||
874 | struct dasd_ccw_req *cqr; | ||
875 | struct list_head *l, *n; | ||
876 | |||
877 | device->stopped &= ~DASD_STOPPED_PENDING; | ||
878 | |||
879 | /* restart all 'running' IO on queue */ | ||
880 | list_for_each_safe(l, n, &device->ccw_queue) { | ||
881 | cqr = list_entry(l, struct dasd_ccw_req, list); | ||
882 | if (cqr->status == DASD_CQR_IN_IO) { | ||
883 | cqr->status = DASD_CQR_QUEUED; | ||
884 | } | ||
885 | } | ||
886 | dasd_clear_timer(device); | ||
887 | dasd_schedule_bh(device); | ||
888 | } | ||
889 | |||
890 | /* | ||
891 | * Interrupt handler for "normal" ssch-io based dasd devices. | ||
892 | */ | ||
893 | void | ||
894 | dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | ||
895 | struct irb *irb) | ||
896 | { | ||
897 | struct dasd_ccw_req *cqr, *next; | ||
898 | struct dasd_device *device; | ||
899 | unsigned long long now; | ||
900 | int expires; | ||
901 | dasd_era_t era; | ||
902 | char mask; | ||
903 | |||
904 | if (IS_ERR(irb)) { | ||
905 | switch (PTR_ERR(irb)) { | ||
906 | case -EIO: | ||
907 | dasd_handle_killed_request(cdev, intparm); | ||
908 | break; | ||
909 | case -ETIMEDOUT: | ||
910 | printk(KERN_WARNING"%s(%s): request timed out\n", | ||
911 | __FUNCTION__, cdev->dev.bus_id); | ||
912 | //FIXME - dasd uses own timeout interface... | ||
913 | break; | ||
914 | default: | ||
915 | printk(KERN_WARNING"%s(%s): unknown error %ld\n", | ||
916 | __FUNCTION__, cdev->dev.bus_id, PTR_ERR(irb)); | ||
917 | } | ||
918 | return; | ||
919 | } | ||
920 | |||
921 | now = get_clock(); | ||
922 | |||
923 | DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x", | ||
924 | cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat), | ||
925 | (unsigned int) intparm); | ||
926 | |||
927 | /* first of all check for state change pending interrupt */ | ||
928 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; | ||
929 | if ((irb->scsw.dstat & mask) == mask) { | ||
930 | device = dasd_device_from_cdev(cdev); | ||
931 | if (!IS_ERR(device)) { | ||
932 | dasd_handle_state_change_pending(device); | ||
933 | dasd_put_device(device); | ||
934 | } | ||
935 | return; | ||
936 | } | ||
937 | |||
938 | cqr = (struct dasd_ccw_req *) intparm; | ||
939 | |||
940 | /* check for unsolicited interrupts */ | ||
941 | if (cqr == NULL) { | ||
942 | MESSAGE(KERN_DEBUG, | ||
943 | "unsolicited interrupt received: bus_id %s", | ||
944 | cdev->dev.bus_id); | ||
945 | return; | ||
946 | } | ||
947 | |||
948 | device = (struct dasd_device *) cqr->device; | ||
949 | if (device == NULL || | ||
950 | strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { | ||
951 | MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", | ||
952 | cdev->dev.bus_id); | ||
953 | return; | ||
954 | } | ||
955 | |||
956 | /* Check for clear pending */ | ||
957 | if (cqr->status == DASD_CQR_CLEAR && | ||
958 | irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { | ||
959 | cqr->status = DASD_CQR_QUEUED; | ||
960 | dasd_clear_timer(device); | ||
961 | dasd_schedule_bh(device); | ||
962 | return; | ||
963 | } | ||
964 | |||
965 | /* check status - the request might have been killed by dyn detach */ | ||
966 | if (cqr->status != DASD_CQR_IN_IO) { | ||
967 | MESSAGE(KERN_DEBUG, | ||
968 | "invalid status: bus_id %s, status %02x", | ||
969 | cdev->dev.bus_id, cqr->status); | ||
970 | return; | ||
971 | } | ||
972 | DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p", | ||
973 | ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr); | ||
974 | |||
975 | /* Find out the appropriate era_action. */ | ||
976 | if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) | ||
977 | era = dasd_era_fatal; | ||
978 | else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && | ||
979 | irb->scsw.cstat == 0 && | ||
980 | !irb->esw.esw0.erw.cons) | ||
981 | era = dasd_era_none; | ||
982 | else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) | ||
983 | era = dasd_era_fatal; /* don't recover this request */ | ||
984 | else if (irb->esw.esw0.erw.cons) | ||
985 | era = device->discipline->examine_error(cqr, irb); | ||
986 | else | ||
987 | era = dasd_era_recover; | ||
988 | |||
989 | DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era); | ||
990 | expires = 0; | ||
991 | if (era == dasd_era_none) { | ||
992 | cqr->status = DASD_CQR_DONE; | ||
993 | cqr->stopclk = now; | ||
994 | /* Start first request on queue if possible -> fast_io. */ | ||
995 | if (cqr->list.next != &device->ccw_queue) { | ||
996 | next = list_entry(cqr->list.next, | ||
997 | struct dasd_ccw_req, list); | ||
998 | if ((next->status == DASD_CQR_QUEUED) && | ||
999 | (!device->stopped)) { | ||
1000 | if (device->discipline->start_IO(next) == 0) | ||
1001 | expires = next->expires; | ||
1002 | else | ||
1003 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | ||
1004 | "Interrupt fastpath " | ||
1005 | "failed!"); | ||
1006 | } | ||
1007 | } | ||
1008 | } else { /* error */ | ||
1009 | memcpy(&cqr->irb, irb, sizeof (struct irb)); | ||
1010 | #ifdef ERP_DEBUG | ||
1011 | /* dump sense data */ | ||
1012 | dasd_log_sense(cqr, irb); | ||
1013 | #endif | ||
1014 | switch (era) { | ||
1015 | case dasd_era_fatal: | ||
1016 | cqr->status = DASD_CQR_FAILED; | ||
1017 | cqr->stopclk = now; | ||
1018 | break; | ||
1019 | case dasd_era_recover: | ||
1020 | cqr->status = DASD_CQR_ERROR; | ||
1021 | break; | ||
1022 | default: | ||
1023 | BUG(); | ||
1024 | } | ||
1025 | } | ||
1026 | if (expires != 0) | ||
1027 | dasd_set_timer(device, expires); | ||
1028 | else | ||
1029 | dasd_clear_timer(device); | ||
1030 | dasd_schedule_bh(device); | ||
1031 | } | ||
1032 | |||
1033 | /* | ||
1034 | * posts the buffer_cache about a finalized request | ||
1035 | */ | ||
1036 | static inline void | ||
1037 | dasd_end_request(struct request *req, int uptodate) | ||
1038 | { | ||
1039 | if (end_that_request_first(req, uptodate, req->hard_nr_sectors)) | ||
1040 | BUG(); | ||
1041 | add_disk_randomness(req->rq_disk); | ||
1042 | end_that_request_last(req); | ||
1043 | } | ||
1044 | |||
1045 | /* | ||
1046 | * Process finished error recovery ccw. | ||
1047 | */ | ||
1048 | static inline void | ||
1049 | __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr) | ||
1050 | { | ||
1051 | dasd_erp_fn_t erp_fn; | ||
1052 | |||
1053 | if (cqr->status == DASD_CQR_DONE) | ||
1054 | DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful"); | ||
1055 | else | ||
1056 | DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful"); | ||
1057 | erp_fn = device->discipline->erp_postaction(cqr); | ||
1058 | erp_fn(cqr); | ||
1059 | } | ||
1060 | |||
1061 | /* | ||
1062 | * Process ccw request queue. | ||
1063 | */ | ||
1064 | static inline void | ||
1065 | __dasd_process_ccw_queue(struct dasd_device * device, | ||
1066 | struct list_head *final_queue) | ||
1067 | { | ||
1068 | struct list_head *l, *n; | ||
1069 | struct dasd_ccw_req *cqr; | ||
1070 | dasd_erp_fn_t erp_fn; | ||
1071 | |||
1072 | restart: | ||
1073 | /* Process request with final status. */ | ||
1074 | list_for_each_safe(l, n, &device->ccw_queue) { | ||
1075 | cqr = list_entry(l, struct dasd_ccw_req, list); | ||
1076 | /* Stop list processing at the first non-final request. */ | ||
1077 | if (cqr->status != DASD_CQR_DONE && | ||
1078 | cqr->status != DASD_CQR_FAILED && | ||
1079 | cqr->status != DASD_CQR_ERROR) | ||
1080 | break; | ||
1081 | /* Process requests with DASD_CQR_ERROR */ | ||
1082 | if (cqr->status == DASD_CQR_ERROR) { | ||
1083 | if (cqr->irb.scsw.fctl & SCSW_FCTL_HALT_FUNC) { | ||
1084 | cqr->status = DASD_CQR_FAILED; | ||
1085 | cqr->stopclk = get_clock(); | ||
1086 | } else { | ||
1087 | if (cqr->irb.esw.esw0.erw.cons) { | ||
1088 | erp_fn = device->discipline-> | ||
1089 | erp_action(cqr); | ||
1090 | erp_fn(cqr); | ||
1091 | } else | ||
1092 | dasd_default_erp_action(cqr); | ||
1093 | } | ||
1094 | goto restart; | ||
1095 | } | ||
1096 | /* Process finished ERP request. */ | ||
1097 | if (cqr->refers) { | ||
1098 | __dasd_process_erp(device, cqr); | ||
1099 | goto restart; | ||
1100 | } | ||
1101 | |||
1102 | /* Rechain finished requests to final queue */ | ||
1103 | cqr->endclk = get_clock(); | ||
1104 | list_move_tail(&cqr->list, final_queue); | ||
1105 | } | ||
1106 | } | ||
1107 | |||
1108 | static void | ||
1109 | dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data) | ||
1110 | { | ||
1111 | struct request *req; | ||
1112 | struct dasd_device *device; | ||
1113 | int status; | ||
1114 | |||
1115 | req = (struct request *) data; | ||
1116 | device = cqr->device; | ||
1117 | dasd_profile_end(device, cqr, req); | ||
1118 | status = cqr->device->discipline->free_cp(cqr,req); | ||
1119 | spin_lock_irq(&device->request_queue_lock); | ||
1120 | dasd_end_request(req, status); | ||
1121 | spin_unlock_irq(&device->request_queue_lock); | ||
1122 | } | ||
1123 | |||
1124 | |||
1125 | /* | ||
1126 | * Fetch requests from the block device queue. | ||
1127 | */ | ||
1128 | static inline void | ||
1129 | __dasd_process_blk_queue(struct dasd_device * device) | ||
1130 | { | ||
1131 | request_queue_t *queue; | ||
1132 | struct request *req; | ||
1133 | struct dasd_ccw_req *cqr; | ||
1134 | int nr_queued; | ||
1135 | |||
1136 | queue = device->request_queue; | ||
1137 | /* No queue ? Then there is nothing to do. */ | ||
1138 | if (queue == NULL) | ||
1139 | return; | ||
1140 | |||
1141 | /* | ||
1142 | * We requeue request from the block device queue to the ccw | ||
1143 | * queue only in two states. In state DASD_STATE_READY the | ||
1144 | * partition detection is done and we need to requeue requests | ||
1145 | * for that. State DASD_STATE_ONLINE is normal block device | ||
1146 | * operation. | ||
1147 | */ | ||
1148 | if (device->state != DASD_STATE_READY && | ||
1149 | device->state != DASD_STATE_ONLINE) | ||
1150 | return; | ||
1151 | nr_queued = 0; | ||
1152 | /* Now we try to fetch requests from the request queue */ | ||
1153 | list_for_each_entry(cqr, &device->ccw_queue, list) | ||
1154 | if (cqr->status == DASD_CQR_QUEUED) | ||
1155 | nr_queued++; | ||
1156 | while (!blk_queue_plugged(queue) && | ||
1157 | elv_next_request(queue) && | ||
1158 | nr_queued < DASD_CHANQ_MAX_SIZE) { | ||
1159 | req = elv_next_request(queue); | ||
1160 | if (test_bit(DASD_FLAG_RO, &device->flags) && | ||
1161 | rq_data_dir(req) == WRITE) { | ||
1162 | DBF_DEV_EVENT(DBF_ERR, device, | ||
1163 | "Rejecting write request %p", | ||
1164 | req); | ||
1165 | blkdev_dequeue_request(req); | ||
1166 | dasd_end_request(req, 0); | ||
1167 | continue; | ||
1168 | } | ||
1169 | if (device->stopped & DASD_STOPPED_DC_EIO) { | ||
1170 | blkdev_dequeue_request(req); | ||
1171 | dasd_end_request(req, 0); | ||
1172 | continue; | ||
1173 | } | ||
1174 | cqr = device->discipline->build_cp(device, req); | ||
1175 | if (IS_ERR(cqr)) { | ||
1176 | if (PTR_ERR(cqr) == -ENOMEM) | ||
1177 | break; /* terminate request queue loop */ | ||
1178 | DBF_DEV_EVENT(DBF_ERR, device, | ||
1179 | "CCW creation failed (rc=%ld) " | ||
1180 | "on request %p", | ||
1181 | PTR_ERR(cqr), req); | ||
1182 | blkdev_dequeue_request(req); | ||
1183 | dasd_end_request(req, 0); | ||
1184 | continue; | ||
1185 | } | ||
1186 | cqr->callback = dasd_end_request_cb; | ||
1187 | cqr->callback_data = (void *) req; | ||
1188 | cqr->status = DASD_CQR_QUEUED; | ||
1189 | blkdev_dequeue_request(req); | ||
1190 | list_add_tail(&cqr->list, &device->ccw_queue); | ||
1191 | dasd_profile_start(device, cqr, req); | ||
1192 | nr_queued++; | ||
1193 | } | ||
1194 | } | ||
1195 | |||
1196 | /* | ||
1197 | * Take a look at the first request on the ccw queue and check | ||
1198 | * if it reached its expire time. If so, terminate the IO. | ||
1199 | */ | ||
1200 | static inline void | ||
1201 | __dasd_check_expire(struct dasd_device * device) | ||
1202 | { | ||
1203 | struct dasd_ccw_req *cqr; | ||
1204 | |||
1205 | if (list_empty(&device->ccw_queue)) | ||
1206 | return; | ||
1207 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); | ||
1208 | if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) { | ||
1209 | if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) { | ||
1210 | if (device->discipline->term_IO(cqr) != 0) | ||
1211 | /* Hmpf, try again in 1/10 sec */ | ||
1212 | dasd_set_timer(device, 10); | ||
1213 | } | ||
1214 | } | ||
1215 | } | ||
1216 | |||
1217 | /* | ||
1218 | * Take a look at the first request on the ccw queue and check | ||
1219 | * if it needs to be started. | ||
1220 | */ | ||
1221 | static inline void | ||
1222 | __dasd_start_head(struct dasd_device * device) | ||
1223 | { | ||
1224 | struct dasd_ccw_req *cqr; | ||
1225 | int rc; | ||
1226 | |||
1227 | if (list_empty(&device->ccw_queue)) | ||
1228 | return; | ||
1229 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); | ||
1230 | if ((cqr->status == DASD_CQR_QUEUED) && | ||
1231 | (!device->stopped)) { | ||
1232 | /* try to start the first I/O that can be started */ | ||
1233 | rc = device->discipline->start_IO(cqr); | ||
1234 | if (rc == 0) | ||
1235 | dasd_set_timer(device, cqr->expires); | ||
1236 | else if (rc == -EACCES) { | ||
1237 | dasd_schedule_bh(device); | ||
1238 | } else | ||
1239 | /* Hmpf, try again in 1/2 sec */ | ||
1240 | dasd_set_timer(device, 50); | ||
1241 | } | ||
1242 | } | ||
1243 | |||
1244 | /* | ||
1245 | * Remove requests from the ccw queue. | ||
1246 | */ | ||
1247 | static void | ||
1248 | dasd_flush_ccw_queue(struct dasd_device * device, int all) | ||
1249 | { | ||
1250 | struct list_head flush_queue; | ||
1251 | struct list_head *l, *n; | ||
1252 | struct dasd_ccw_req *cqr; | ||
1253 | |||
1254 | INIT_LIST_HEAD(&flush_queue); | ||
1255 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
1256 | list_for_each_safe(l, n, &device->ccw_queue) { | ||
1257 | cqr = list_entry(l, struct dasd_ccw_req, list); | ||
1258 | /* Flush all request or only block device requests? */ | ||
1259 | if (all == 0 && cqr->callback == dasd_end_request_cb) | ||
1260 | continue; | ||
1261 | if (cqr->status == DASD_CQR_IN_IO) | ||
1262 | device->discipline->term_IO(cqr); | ||
1263 | if (cqr->status != DASD_CQR_DONE || | ||
1264 | cqr->status != DASD_CQR_FAILED) { | ||
1265 | cqr->status = DASD_CQR_FAILED; | ||
1266 | cqr->stopclk = get_clock(); | ||
1267 | } | ||
1268 | /* Process finished ERP request. */ | ||
1269 | if (cqr->refers) { | ||
1270 | __dasd_process_erp(device, cqr); | ||
1271 | continue; | ||
1272 | } | ||
1273 | /* Rechain request on device request queue */ | ||
1274 | cqr->endclk = get_clock(); | ||
1275 | list_move_tail(&cqr->list, &flush_queue); | ||
1276 | } | ||
1277 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1278 | /* Now call the callback function of flushed requests */ | ||
1279 | list_for_each_safe(l, n, &flush_queue) { | ||
1280 | cqr = list_entry(l, struct dasd_ccw_req, list); | ||
1281 | if (cqr->callback != NULL) | ||
1282 | (cqr->callback)(cqr, cqr->callback_data); | ||
1283 | } | ||
1284 | } | ||
1285 | |||
1286 | /* | ||
1287 | * Acquire the device lock and process queues for the device. | ||
1288 | */ | ||
1289 | static void | ||
1290 | dasd_tasklet(struct dasd_device * device) | ||
1291 | { | ||
1292 | struct list_head final_queue; | ||
1293 | struct list_head *l, *n; | ||
1294 | struct dasd_ccw_req *cqr; | ||
1295 | |||
1296 | atomic_set (&device->tasklet_scheduled, 0); | ||
1297 | INIT_LIST_HEAD(&final_queue); | ||
1298 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
1299 | /* Check expire time of first request on the ccw queue. */ | ||
1300 | __dasd_check_expire(device); | ||
1301 | /* Finish off requests on ccw queue */ | ||
1302 | __dasd_process_ccw_queue(device, &final_queue); | ||
1303 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1304 | /* Now call the callback function of requests with final status */ | ||
1305 | list_for_each_safe(l, n, &final_queue) { | ||
1306 | cqr = list_entry(l, struct dasd_ccw_req, list); | ||
1307 | list_del(&cqr->list); | ||
1308 | if (cqr->callback != NULL) | ||
1309 | (cqr->callback)(cqr, cqr->callback_data); | ||
1310 | } | ||
1311 | spin_lock_irq(&device->request_queue_lock); | ||
1312 | spin_lock(get_ccwdev_lock(device->cdev)); | ||
1313 | /* Get new request from the block device request queue */ | ||
1314 | __dasd_process_blk_queue(device); | ||
1315 | /* Now check if the head of the ccw queue needs to be started. */ | ||
1316 | __dasd_start_head(device); | ||
1317 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
1318 | spin_unlock_irq(&device->request_queue_lock); | ||
1319 | dasd_put_device(device); | ||
1320 | } | ||
1321 | |||
1322 | /* | ||
1323 | * Schedules a call to dasd_tasklet over the device tasklet. | ||
1324 | */ | ||
1325 | void | ||
1326 | dasd_schedule_bh(struct dasd_device * device) | ||
1327 | { | ||
1328 | /* Protect against rescheduling. */ | ||
1329 | if (atomic_compare_and_swap (0, 1, &device->tasklet_scheduled)) | ||
1330 | return; | ||
1331 | dasd_get_device(device); | ||
1332 | tasklet_hi_schedule(&device->tasklet); | ||
1333 | } | ||
1334 | |||
1335 | /* | ||
1336 | * Queue a request to the head of the ccw_queue. Start the I/O if | ||
1337 | * possible. | ||
1338 | */ | ||
1339 | void | ||
1340 | dasd_add_request_head(struct dasd_ccw_req *req) | ||
1341 | { | ||
1342 | struct dasd_device *device; | ||
1343 | unsigned long flags; | ||
1344 | |||
1345 | device = req->device; | ||
1346 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
1347 | req->status = DASD_CQR_QUEUED; | ||
1348 | req->device = device; | ||
1349 | list_add(&req->list, &device->ccw_queue); | ||
1350 | /* let the bh start the request to keep them in order */ | ||
1351 | dasd_schedule_bh(device); | ||
1352 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
1353 | } | ||
1354 | |||
1355 | /* | ||
1356 | * Queue a request to the tail of the ccw_queue. Start the I/O if | ||
1357 | * possible. | ||
1358 | */ | ||
1359 | void | ||
1360 | dasd_add_request_tail(struct dasd_ccw_req *req) | ||
1361 | { | ||
1362 | struct dasd_device *device; | ||
1363 | unsigned long flags; | ||
1364 | |||
1365 | device = req->device; | ||
1366 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
1367 | req->status = DASD_CQR_QUEUED; | ||
1368 | req->device = device; | ||
1369 | list_add_tail(&req->list, &device->ccw_queue); | ||
1370 | /* let the bh start the request to keep them in order */ | ||
1371 | dasd_schedule_bh(device); | ||
1372 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
1373 | } | ||
1374 | |||
1375 | /* | ||
1376 | * Wakeup callback. | ||
1377 | */ | ||
1378 | static void | ||
1379 | dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data) | ||
1380 | { | ||
1381 | wake_up((wait_queue_head_t *) data); | ||
1382 | } | ||
1383 | |||
1384 | static inline int | ||
1385 | _wait_for_wakeup(struct dasd_ccw_req *cqr) | ||
1386 | { | ||
1387 | struct dasd_device *device; | ||
1388 | int rc; | ||
1389 | |||
1390 | device = cqr->device; | ||
1391 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
1392 | rc = cqr->status == DASD_CQR_DONE || cqr->status == DASD_CQR_FAILED; | ||
1393 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1394 | return rc; | ||
1395 | } | ||
1396 | |||
1397 | /* | ||
1398 | * Attempts to start a special ccw queue and waits for its completion. | ||
1399 | */ | ||
1400 | int | ||
1401 | dasd_sleep_on(struct dasd_ccw_req * cqr) | ||
1402 | { | ||
1403 | wait_queue_head_t wait_q; | ||
1404 | struct dasd_device *device; | ||
1405 | int rc; | ||
1406 | |||
1407 | device = cqr->device; | ||
1408 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
1409 | |||
1410 | init_waitqueue_head (&wait_q); | ||
1411 | cqr->callback = dasd_wakeup_cb; | ||
1412 | cqr->callback_data = (void *) &wait_q; | ||
1413 | cqr->status = DASD_CQR_QUEUED; | ||
1414 | list_add_tail(&cqr->list, &device->ccw_queue); | ||
1415 | |||
1416 | /* let the bh start the request to keep them in order */ | ||
1417 | dasd_schedule_bh(device); | ||
1418 | |||
1419 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1420 | |||
1421 | wait_event(wait_q, _wait_for_wakeup(cqr)); | ||
1422 | |||
1423 | /* Request status is either done or failed. */ | ||
1424 | rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; | ||
1425 | return rc; | ||
1426 | } | ||
1427 | |||
1428 | /* | ||
1429 | * Attempts to start a special ccw queue and wait interruptible | ||
1430 | * for its completion. | ||
1431 | */ | ||
1432 | int | ||
1433 | dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr) | ||
1434 | { | ||
1435 | wait_queue_head_t wait_q; | ||
1436 | struct dasd_device *device; | ||
1437 | int rc, finished; | ||
1438 | |||
1439 | device = cqr->device; | ||
1440 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
1441 | |||
1442 | init_waitqueue_head (&wait_q); | ||
1443 | cqr->callback = dasd_wakeup_cb; | ||
1444 | cqr->callback_data = (void *) &wait_q; | ||
1445 | cqr->status = DASD_CQR_QUEUED; | ||
1446 | list_add_tail(&cqr->list, &device->ccw_queue); | ||
1447 | |||
1448 | /* let the bh start the request to keep them in order */ | ||
1449 | dasd_schedule_bh(device); | ||
1450 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1451 | |||
1452 | finished = 0; | ||
1453 | while (!finished) { | ||
1454 | rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr)); | ||
1455 | if (rc != -ERESTARTSYS) { | ||
1456 | /* Request status is either done or failed. */ | ||
1457 | rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; | ||
1458 | break; | ||
1459 | } | ||
1460 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
1461 | if (cqr->status == DASD_CQR_IN_IO && | ||
1462 | device->discipline->term_IO(cqr) == 0) { | ||
1463 | list_del(&cqr->list); | ||
1464 | finished = 1; | ||
1465 | } | ||
1466 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1467 | } | ||
1468 | return rc; | ||
1469 | } | ||
1470 | |||
1471 | /* | ||
1472 | * Whoa nelly now it gets really hairy. For some functions (e.g. steal lock | ||
1473 | * for eckd devices) the currently running request has to be terminated | ||
1474 | * and be put back to status queued, before the special request is added | ||
1475 | * to the head of the queue. Then the special request is waited on normally. | ||
1476 | */ | ||
1477 | static inline int | ||
1478 | _dasd_term_running_cqr(struct dasd_device *device) | ||
1479 | { | ||
1480 | struct dasd_ccw_req *cqr; | ||
1481 | int rc; | ||
1482 | |||
1483 | if (list_empty(&device->ccw_queue)) | ||
1484 | return 0; | ||
1485 | cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); | ||
1486 | rc = device->discipline->term_IO(cqr); | ||
1487 | if (rc == 0) { | ||
1488 | /* termination successful */ | ||
1489 | cqr->status = DASD_CQR_QUEUED; | ||
1490 | cqr->startclk = cqr->stopclk = 0; | ||
1491 | cqr->starttime = 0; | ||
1492 | } | ||
1493 | return rc; | ||
1494 | } | ||
1495 | |||
1496 | int | ||
1497 | dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr) | ||
1498 | { | ||
1499 | wait_queue_head_t wait_q; | ||
1500 | struct dasd_device *device; | ||
1501 | int rc; | ||
1502 | |||
1503 | device = cqr->device; | ||
1504 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
1505 | rc = _dasd_term_running_cqr(device); | ||
1506 | if (rc) { | ||
1507 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1508 | return rc; | ||
1509 | } | ||
1510 | |||
1511 | init_waitqueue_head (&wait_q); | ||
1512 | cqr->callback = dasd_wakeup_cb; | ||
1513 | cqr->callback_data = (void *) &wait_q; | ||
1514 | cqr->status = DASD_CQR_QUEUED; | ||
1515 | list_add(&cqr->list, &device->ccw_queue); | ||
1516 | |||
1517 | /* let the bh start the request to keep them in order */ | ||
1518 | dasd_schedule_bh(device); | ||
1519 | |||
1520 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
1521 | |||
1522 | wait_event(wait_q, _wait_for_wakeup(cqr)); | ||
1523 | |||
1524 | /* Request status is either done or failed. */ | ||
1525 | rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; | ||
1526 | return rc; | ||
1527 | } | ||
1528 | |||
1529 | /* | ||
1530 | * Cancels a request that was started with dasd_sleep_on_req. | ||
1531 | * This is useful to timeout requests. The request will be | ||
1532 | * terminated if it is currently in i/o. | ||
1533 | * Returns 1 if the request has been terminated. | ||
1534 | */ | ||
1535 | int | ||
1536 | dasd_cancel_req(struct dasd_ccw_req *cqr) | ||
1537 | { | ||
1538 | struct dasd_device *device = cqr->device; | ||
1539 | unsigned long flags; | ||
1540 | int rc; | ||
1541 | |||
1542 | rc = 0; | ||
1543 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
1544 | switch (cqr->status) { | ||
1545 | case DASD_CQR_QUEUED: | ||
1546 | /* request was not started - just set to failed */ | ||
1547 | cqr->status = DASD_CQR_FAILED; | ||
1548 | break; | ||
1549 | case DASD_CQR_IN_IO: | ||
1550 | /* request in IO - terminate IO and release again */ | ||
1551 | if (device->discipline->term_IO(cqr) != 0) | ||
1552 | /* what to do if unable to terminate ?????? | ||
1553 | e.g. not _IN_IO */ | ||
1554 | cqr->status = DASD_CQR_FAILED; | ||
1555 | cqr->stopclk = get_clock(); | ||
1556 | rc = 1; | ||
1557 | break; | ||
1558 | case DASD_CQR_DONE: | ||
1559 | case DASD_CQR_FAILED: | ||
1560 | /* already finished - do nothing */ | ||
1561 | break; | ||
1562 | default: | ||
1563 | DEV_MESSAGE(KERN_ALERT, device, | ||
1564 | "invalid status %02x in request", | ||
1565 | cqr->status); | ||
1566 | BUG(); | ||
1567 | |||
1568 | } | ||
1569 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
1570 | dasd_schedule_bh(device); | ||
1571 | return rc; | ||
1572 | } | ||
1573 | |||
1574 | /* | ||
1575 | * SECTION: Block device operations (request queue, partitions, open, release). | ||
1576 | */ | ||
1577 | |||
1578 | /* | ||
1579 | * Dasd request queue function. Called from ll_rw_blk.c | ||
1580 | */ | ||
1581 | static void | ||
1582 | do_dasd_request(request_queue_t * queue) | ||
1583 | { | ||
1584 | struct dasd_device *device; | ||
1585 | |||
1586 | device = (struct dasd_device *) queue->queuedata; | ||
1587 | spin_lock(get_ccwdev_lock(device->cdev)); | ||
1588 | /* Get new request from the block device request queue */ | ||
1589 | __dasd_process_blk_queue(device); | ||
1590 | /* Now check if the head of the ccw queue needs to be started. */ | ||
1591 | __dasd_start_head(device); | ||
1592 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
1593 | } | ||
1594 | |||
1595 | /* | ||
1596 | * Allocate and initialize request queue and default I/O scheduler. | ||
1597 | */ | ||
1598 | static int | ||
1599 | dasd_alloc_queue(struct dasd_device * device) | ||
1600 | { | ||
1601 | int rc; | ||
1602 | |||
1603 | device->request_queue = blk_init_queue(do_dasd_request, | ||
1604 | &device->request_queue_lock); | ||
1605 | if (device->request_queue == NULL) | ||
1606 | return -ENOMEM; | ||
1607 | |||
1608 | device->request_queue->queuedata = device; | ||
1609 | |||
1610 | elevator_exit(device->request_queue->elevator); | ||
1611 | rc = elevator_init(device->request_queue, "deadline"); | ||
1612 | if (rc) { | ||
1613 | blk_cleanup_queue(device->request_queue); | ||
1614 | return rc; | ||
1615 | } | ||
1616 | return 0; | ||
1617 | } | ||
1618 | |||
1619 | /* | ||
1620 | * Allocate and initialize request queue. | ||
1621 | */ | ||
1622 | static void | ||
1623 | dasd_setup_queue(struct dasd_device * device) | ||
1624 | { | ||
1625 | int max; | ||
1626 | |||
1627 | blk_queue_hardsect_size(device->request_queue, device->bp_block); | ||
1628 | max = device->discipline->max_blocks << device->s2b_shift; | ||
1629 | blk_queue_max_sectors(device->request_queue, max); | ||
1630 | blk_queue_max_phys_segments(device->request_queue, -1L); | ||
1631 | blk_queue_max_hw_segments(device->request_queue, -1L); | ||
1632 | blk_queue_max_segment_size(device->request_queue, -1L); | ||
1633 | blk_queue_segment_boundary(device->request_queue, -1L); | ||
1634 | } | ||
1635 | |||
1636 | /* | ||
1637 | * Deactivate and free request queue. | ||
1638 | */ | ||
1639 | static void | ||
1640 | dasd_free_queue(struct dasd_device * device) | ||
1641 | { | ||
1642 | if (device->request_queue) { | ||
1643 | blk_cleanup_queue(device->request_queue); | ||
1644 | device->request_queue = NULL; | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | /* | ||
1649 | * Flush request on the request queue. | ||
1650 | */ | ||
1651 | static void | ||
1652 | dasd_flush_request_queue(struct dasd_device * device) | ||
1653 | { | ||
1654 | struct request *req; | ||
1655 | |||
1656 | if (!device->request_queue) | ||
1657 | return; | ||
1658 | |||
1659 | spin_lock_irq(&device->request_queue_lock); | ||
1660 | while (!list_empty(&device->request_queue->queue_head)) { | ||
1661 | req = elv_next_request(device->request_queue); | ||
1662 | if (req == NULL) | ||
1663 | break; | ||
1664 | dasd_end_request(req, 0); | ||
1665 | blkdev_dequeue_request(req); | ||
1666 | } | ||
1667 | spin_unlock_irq(&device->request_queue_lock); | ||
1668 | } | ||
1669 | |||
1670 | static int | ||
1671 | dasd_open(struct inode *inp, struct file *filp) | ||
1672 | { | ||
1673 | struct gendisk *disk = inp->i_bdev->bd_disk; | ||
1674 | struct dasd_device *device = disk->private_data; | ||
1675 | int rc; | ||
1676 | |||
1677 | atomic_inc(&device->open_count); | ||
1678 | if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) { | ||
1679 | rc = -ENODEV; | ||
1680 | goto unlock; | ||
1681 | } | ||
1682 | |||
1683 | if (!try_module_get(device->discipline->owner)) { | ||
1684 | rc = -EINVAL; | ||
1685 | goto unlock; | ||
1686 | } | ||
1687 | |||
1688 | if (dasd_probeonly) { | ||
1689 | DEV_MESSAGE(KERN_INFO, device, "%s", | ||
1690 | "No access to device due to probeonly mode"); | ||
1691 | rc = -EPERM; | ||
1692 | goto out; | ||
1693 | } | ||
1694 | |||
1695 | if (device->state < DASD_STATE_BASIC) { | ||
1696 | DBF_DEV_EVENT(DBF_ERR, device, " %s", | ||
1697 | " Cannot open unrecognized device"); | ||
1698 | rc = -ENODEV; | ||
1699 | goto out; | ||
1700 | } | ||
1701 | |||
1702 | return 0; | ||
1703 | |||
1704 | out: | ||
1705 | module_put(device->discipline->owner); | ||
1706 | unlock: | ||
1707 | atomic_dec(&device->open_count); | ||
1708 | return rc; | ||
1709 | } | ||
1710 | |||
1711 | static int | ||
1712 | dasd_release(struct inode *inp, struct file *filp) | ||
1713 | { | ||
1714 | struct gendisk *disk = inp->i_bdev->bd_disk; | ||
1715 | struct dasd_device *device = disk->private_data; | ||
1716 | |||
1717 | atomic_dec(&device->open_count); | ||
1718 | module_put(device->discipline->owner); | ||
1719 | return 0; | ||
1720 | } | ||
1721 | |||
1722 | struct block_device_operations | ||
1723 | dasd_device_operations = { | ||
1724 | .owner = THIS_MODULE, | ||
1725 | .open = dasd_open, | ||
1726 | .release = dasd_release, | ||
1727 | .ioctl = dasd_ioctl, | ||
1728 | }; | ||
1729 | |||
1730 | |||
1731 | static void | ||
1732 | dasd_exit(void) | ||
1733 | { | ||
1734 | #ifdef CONFIG_PROC_FS | ||
1735 | dasd_proc_exit(); | ||
1736 | #endif | ||
1737 | dasd_ioctl_exit(); | ||
1738 | dasd_gendisk_exit(); | ||
1739 | dasd_devmap_exit(); | ||
1740 | devfs_remove("dasd"); | ||
1741 | if (dasd_debug_area != NULL) { | ||
1742 | debug_unregister(dasd_debug_area); | ||
1743 | dasd_debug_area = NULL; | ||
1744 | } | ||
1745 | } | ||
1746 | |||
1747 | /* | ||
1748 | * SECTION: common functions for ccw_driver use | ||
1749 | */ | ||
1750 | |||
1751 | /* initial attempt at a probe function. this can be simplified once | ||
1752 | * the other detection code is gone */ | ||
1753 | int | ||
1754 | dasd_generic_probe (struct ccw_device *cdev, | ||
1755 | struct dasd_discipline *discipline) | ||
1756 | { | ||
1757 | int ret; | ||
1758 | |||
1759 | ret = dasd_add_sysfs_files(cdev); | ||
1760 | if (ret) { | ||
1761 | printk(KERN_WARNING | ||
1762 | "dasd_generic_probe: could not add sysfs entries " | ||
1763 | "for %s\n", cdev->dev.bus_id); | ||
1764 | } | ||
1765 | |||
1766 | cdev->handler = &dasd_int_handler; | ||
1767 | |||
1768 | return ret; | ||
1769 | } | ||
1770 | |||
1771 | /* this will one day be called from a global not_oper handler. | ||
1772 | * It is also used by driver_unregister during module unload */ | ||
1773 | void | ||
1774 | dasd_generic_remove (struct ccw_device *cdev) | ||
1775 | { | ||
1776 | struct dasd_device *device; | ||
1777 | |||
1778 | dasd_remove_sysfs_files(cdev); | ||
1779 | device = dasd_device_from_cdev(cdev); | ||
1780 | if (IS_ERR(device)) | ||
1781 | return; | ||
1782 | if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { | ||
1783 | /* Already doing offline processing */ | ||
1784 | dasd_put_device(device); | ||
1785 | return; | ||
1786 | } | ||
1787 | /* | ||
1788 | * This device is removed unconditionally. Set offline | ||
1789 | * flag to prevent dasd_open from opening it while it is | ||
1790 | * no quite down yet. | ||
1791 | */ | ||
1792 | dasd_set_target_state(device, DASD_STATE_NEW); | ||
1793 | /* dasd_delete_device destroys the device reference. */ | ||
1794 | dasd_delete_device(device); | ||
1795 | } | ||
1796 | |||
1797 | /* activate a device. This is called from dasd_{eckd,fba}_probe() when either | ||
1798 | * the device is detected for the first time and is supposed to be used | ||
1799 | * or the user has started activation through sysfs */ | ||
1800 | int | ||
1801 | dasd_generic_set_online (struct ccw_device *cdev, | ||
1802 | struct dasd_discipline *discipline) | ||
1803 | |||
1804 | { | ||
1805 | struct dasd_device *device; | ||
1806 | int rc; | ||
1807 | |||
1808 | device = dasd_create_device(cdev); | ||
1809 | if (IS_ERR(device)) | ||
1810 | return PTR_ERR(device); | ||
1811 | |||
1812 | if (test_bit(DASD_FLAG_USE_DIAG, &device->flags)) { | ||
1813 | if (!dasd_diag_discipline_pointer) { | ||
1814 | printk (KERN_WARNING | ||
1815 | "dasd_generic couldn't online device %s " | ||
1816 | "- discipline DIAG not available\n", | ||
1817 | cdev->dev.bus_id); | ||
1818 | dasd_delete_device(device); | ||
1819 | return -ENODEV; | ||
1820 | } | ||
1821 | discipline = dasd_diag_discipline_pointer; | ||
1822 | } | ||
1823 | device->discipline = discipline; | ||
1824 | |||
1825 | rc = discipline->check_device(device); | ||
1826 | if (rc) { | ||
1827 | printk (KERN_WARNING | ||
1828 | "dasd_generic couldn't online device %s " | ||
1829 | "with discipline %s rc=%i\n", | ||
1830 | cdev->dev.bus_id, discipline->name, rc); | ||
1831 | dasd_delete_device(device); | ||
1832 | return rc; | ||
1833 | } | ||
1834 | |||
1835 | dasd_set_target_state(device, DASD_STATE_ONLINE); | ||
1836 | if (device->state <= DASD_STATE_KNOWN) { | ||
1837 | printk (KERN_WARNING | ||
1838 | "dasd_generic discipline not found for %s\n", | ||
1839 | cdev->dev.bus_id); | ||
1840 | rc = -ENODEV; | ||
1841 | dasd_set_target_state(device, DASD_STATE_NEW); | ||
1842 | dasd_delete_device(device); | ||
1843 | } else | ||
1844 | pr_debug("dasd_generic device %s found\n", | ||
1845 | cdev->dev.bus_id); | ||
1846 | |||
1847 | /* FIXME: we have to wait for the root device but we don't want | ||
1848 | * to wait for each single device but for all at once. */ | ||
1849 | wait_event(dasd_init_waitq, _wait_for_device(device)); | ||
1850 | |||
1851 | dasd_put_device(device); | ||
1852 | |||
1853 | return rc; | ||
1854 | } | ||
1855 | |||
1856 | int | ||
1857 | dasd_generic_set_offline (struct ccw_device *cdev) | ||
1858 | { | ||
1859 | struct dasd_device *device; | ||
1860 | int max_count; | ||
1861 | |||
1862 | device = dasd_device_from_cdev(cdev); | ||
1863 | if (IS_ERR(device)) | ||
1864 | return PTR_ERR(device); | ||
1865 | if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { | ||
1866 | /* Already doing offline processing */ | ||
1867 | dasd_put_device(device); | ||
1868 | return 0; | ||
1869 | } | ||
1870 | /* | ||
1871 | * We must make sure that this device is currently not in use. | ||
1872 | * The open_count is increased for every opener, that includes | ||
1873 | * the blkdev_get in dasd_scan_partitions. We are only interested | ||
1874 | * in the other openers. | ||
1875 | */ | ||
1876 | max_count = device->bdev ? 0 : -1; | ||
1877 | if (atomic_read(&device->open_count) > max_count) { | ||
1878 | printk (KERN_WARNING "Can't offline dasd device with open" | ||
1879 | " count = %i.\n", | ||
1880 | atomic_read(&device->open_count)); | ||
1881 | clear_bit(DASD_FLAG_OFFLINE, &device->flags); | ||
1882 | dasd_put_device(device); | ||
1883 | return -EBUSY; | ||
1884 | } | ||
1885 | dasd_set_target_state(device, DASD_STATE_NEW); | ||
1886 | /* dasd_delete_device destroys the device reference. */ | ||
1887 | dasd_delete_device(device); | ||
1888 | |||
1889 | return 0; | ||
1890 | } | ||
1891 | |||
1892 | int | ||
1893 | dasd_generic_notify(struct ccw_device *cdev, int event) | ||
1894 | { | ||
1895 | struct dasd_device *device; | ||
1896 | struct dasd_ccw_req *cqr; | ||
1897 | unsigned long flags; | ||
1898 | int ret; | ||
1899 | |||
1900 | device = dasd_device_from_cdev(cdev); | ||
1901 | if (IS_ERR(device)) | ||
1902 | return 0; | ||
1903 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); | ||
1904 | ret = 0; | ||
1905 | switch (event) { | ||
1906 | case CIO_GONE: | ||
1907 | case CIO_NO_PATH: | ||
1908 | if (device->state < DASD_STATE_BASIC) | ||
1909 | break; | ||
1910 | /* Device is active. We want to keep it. */ | ||
1911 | if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) { | ||
1912 | list_for_each_entry(cqr, &device->ccw_queue, list) | ||
1913 | if (cqr->status == DASD_CQR_IN_IO) | ||
1914 | cqr->status = DASD_CQR_FAILED; | ||
1915 | device->stopped |= DASD_STOPPED_DC_EIO; | ||
1916 | dasd_schedule_bh(device); | ||
1917 | } else { | ||
1918 | list_for_each_entry(cqr, &device->ccw_queue, list) | ||
1919 | if (cqr->status == DASD_CQR_IN_IO) { | ||
1920 | cqr->status = DASD_CQR_QUEUED; | ||
1921 | cqr->retries++; | ||
1922 | } | ||
1923 | device->stopped |= DASD_STOPPED_DC_WAIT; | ||
1924 | dasd_set_timer(device, 0); | ||
1925 | } | ||
1926 | ret = 1; | ||
1927 | break; | ||
1928 | case CIO_OPER: | ||
1929 | /* FIXME: add a sanity check. */ | ||
1930 | device->stopped &= ~(DASD_STOPPED_DC_WAIT|DASD_STOPPED_DC_EIO); | ||
1931 | dasd_schedule_bh(device); | ||
1932 | ret = 1; | ||
1933 | break; | ||
1934 | } | ||
1935 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); | ||
1936 | dasd_put_device(device); | ||
1937 | return ret; | ||
1938 | } | ||
1939 | |||
1940 | /* | ||
1941 | * Automatically online either all dasd devices (dasd_autodetect) or | ||
1942 | * all devices specified with dasd= parameters. | ||
1943 | */ | ||
1944 | void | ||
1945 | dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver) | ||
1946 | { | ||
1947 | struct device_driver *drv; | ||
1948 | struct device *d, *dev; | ||
1949 | struct ccw_device *cdev; | ||
1950 | |||
1951 | drv = get_driver(&dasd_discipline_driver->driver); | ||
1952 | down_read(&drv->bus->subsys.rwsem); | ||
1953 | dev = NULL; | ||
1954 | list_for_each_entry(d, &drv->devices, driver_list) { | ||
1955 | dev = get_device(d); | ||
1956 | if (!dev) | ||
1957 | continue; | ||
1958 | cdev = to_ccwdev(dev); | ||
1959 | if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0) | ||
1960 | ccw_device_set_online(cdev); | ||
1961 | put_device(dev); | ||
1962 | } | ||
1963 | up_read(&drv->bus->subsys.rwsem); | ||
1964 | put_driver(drv); | ||
1965 | } | ||
1966 | |||
1967 | static int __init | ||
1968 | dasd_init(void) | ||
1969 | { | ||
1970 | int rc; | ||
1971 | |||
1972 | init_waitqueue_head(&dasd_init_waitq); | ||
1973 | |||
1974 | /* register 'common' DASD debug area, used for all DBF_XXX calls */ | ||
1975 | dasd_debug_area = debug_register("dasd", 0, 2, 8 * sizeof (long)); | ||
1976 | if (dasd_debug_area == NULL) { | ||
1977 | rc = -ENOMEM; | ||
1978 | goto failed; | ||
1979 | } | ||
1980 | debug_register_view(dasd_debug_area, &debug_sprintf_view); | ||
1981 | debug_set_level(dasd_debug_area, DBF_EMERG); | ||
1982 | |||
1983 | DBF_EVENT(DBF_EMERG, "%s", "debug area created"); | ||
1984 | |||
1985 | dasd_diag_discipline_pointer = NULL; | ||
1986 | |||
1987 | rc = devfs_mk_dir("dasd"); | ||
1988 | if (rc) | ||
1989 | goto failed; | ||
1990 | rc = dasd_devmap_init(); | ||
1991 | if (rc) | ||
1992 | goto failed; | ||
1993 | rc = dasd_gendisk_init(); | ||
1994 | if (rc) | ||
1995 | goto failed; | ||
1996 | rc = dasd_parse(); | ||
1997 | if (rc) | ||
1998 | goto failed; | ||
1999 | rc = dasd_ioctl_init(); | ||
2000 | if (rc) | ||
2001 | goto failed; | ||
2002 | #ifdef CONFIG_PROC_FS | ||
2003 | rc = dasd_proc_init(); | ||
2004 | if (rc) | ||
2005 | goto failed; | ||
2006 | #endif | ||
2007 | |||
2008 | return 0; | ||
2009 | failed: | ||
2010 | MESSAGE(KERN_INFO, "%s", "initialization not performed due to errors"); | ||
2011 | dasd_exit(); | ||
2012 | return rc; | ||
2013 | } | ||
2014 | |||
2015 | module_init(dasd_init); | ||
2016 | module_exit(dasd_exit); | ||
2017 | |||
2018 | EXPORT_SYMBOL(dasd_debug_area); | ||
2019 | EXPORT_SYMBOL(dasd_diag_discipline_pointer); | ||
2020 | |||
2021 | EXPORT_SYMBOL(dasd_add_request_head); | ||
2022 | EXPORT_SYMBOL(dasd_add_request_tail); | ||
2023 | EXPORT_SYMBOL(dasd_cancel_req); | ||
2024 | EXPORT_SYMBOL(dasd_clear_timer); | ||
2025 | EXPORT_SYMBOL(dasd_enable_device); | ||
2026 | EXPORT_SYMBOL(dasd_int_handler); | ||
2027 | EXPORT_SYMBOL(dasd_kfree_request); | ||
2028 | EXPORT_SYMBOL(dasd_kick_device); | ||
2029 | EXPORT_SYMBOL(dasd_kmalloc_request); | ||
2030 | EXPORT_SYMBOL(dasd_schedule_bh); | ||
2031 | EXPORT_SYMBOL(dasd_set_target_state); | ||
2032 | EXPORT_SYMBOL(dasd_set_timer); | ||
2033 | EXPORT_SYMBOL(dasd_sfree_request); | ||
2034 | EXPORT_SYMBOL(dasd_sleep_on); | ||
2035 | EXPORT_SYMBOL(dasd_sleep_on_immediatly); | ||
2036 | EXPORT_SYMBOL(dasd_sleep_on_interruptible); | ||
2037 | EXPORT_SYMBOL(dasd_smalloc_request); | ||
2038 | EXPORT_SYMBOL(dasd_start_IO); | ||
2039 | EXPORT_SYMBOL(dasd_term_IO); | ||
2040 | |||
2041 | EXPORT_SYMBOL_GPL(dasd_generic_probe); | ||
2042 | EXPORT_SYMBOL_GPL(dasd_generic_remove); | ||
2043 | EXPORT_SYMBOL_GPL(dasd_generic_notify); | ||
2044 | EXPORT_SYMBOL_GPL(dasd_generic_set_online); | ||
2045 | EXPORT_SYMBOL_GPL(dasd_generic_set_offline); | ||
2046 | EXPORT_SYMBOL_GPL(dasd_generic_auto_online); | ||
2047 | |||
2048 | /* | ||
2049 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
2050 | * Emacs will notice this stuff at the end of the file and automatically | ||
2051 | * adjust the settings for this buffer only. This must remain at the end | ||
2052 | * of the file. | ||
2053 | * --------------------------------------------------------------------------- | ||
2054 | * Local variables: | ||
2055 | * c-indent-level: 4 | ||
2056 | * c-brace-imaginary-offset: 0 | ||
2057 | * c-brace-offset: -4 | ||
2058 | * c-argdecl-indent: 4 | ||
2059 | * c-label-offset: -4 | ||
2060 | * c-continued-statement-offset: 4 | ||
2061 | * c-continued-brace-offset: 0 | ||
2062 | * indent-tabs-mode: 1 | ||
2063 | * tab-width: 8 | ||
2064 | * End: | ||
2065 | */ | ||