diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2011-05-23 04:24:24 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-05-23 04:24:28 -0400 |
commit | 66ceed5ad1318863c21710f316942bcefff8081c (patch) | |
tree | 6d9e29f7ea129b1b599720ae7957ca364f3750b8 /drivers/s390 | |
parent | 043d07084b5347a26eab0a07aa13a4a929ad9e71 (diff) |
[S390] Remove tape block device driver.
Remove the tape block device driver. It's not of real use but has
already created some confusion when users wanted to access tape devices
and used the block device nodes instead of the character device nodes.
Also remove the whole tape documentation since it's completely outdated
and we have the device drivers book which is the place where everything
is properly documented.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/char/Kconfig | 12 | ||||
-rw-r--r-- | drivers/s390/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/s390/char/tape_block.c | 444 |
3 files changed, 0 insertions, 457 deletions
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index dcee3c5c8954..a4f117d9fdc6 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig | |||
@@ -119,18 +119,6 @@ config S390_TAPE | |||
119 | comment "S/390 tape interface support" | 119 | comment "S/390 tape interface support" |
120 | depends on S390_TAPE | 120 | depends on S390_TAPE |
121 | 121 | ||
122 | config S390_TAPE_BLOCK | ||
123 | def_bool y | ||
124 | prompt "Support for tape block devices" | ||
125 | depends on S390_TAPE && BLOCK | ||
126 | help | ||
127 | Select this option if you want to access your channel-attached tape | ||
128 | devices using the block device interface. This interface is similar | ||
129 | to CD-ROM devices on other platforms. The tapes can only be | ||
130 | accessed read-only when using this interface. Have a look at | ||
131 | <file:Documentation/s390/TAPE> for further information about creating | ||
132 | volumes for and using this interface. It is safe to say "Y" here. | ||
133 | |||
134 | comment "S/390 tape hardware support" | 122 | comment "S/390 tape hardware support" |
135 | depends on S390_TAPE | 123 | depends on S390_TAPE |
136 | 124 | ||
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index efb500ab66c0..af01b5abd069 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile | |||
@@ -22,7 +22,6 @@ obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o | |||
22 | obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o | 22 | obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o |
23 | obj-$(CONFIG_VMCP) += vmcp.o | 23 | obj-$(CONFIG_VMCP) += vmcp.o |
24 | 24 | ||
25 | tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o | ||
26 | tape-$(CONFIG_PROC_FS) += tape_proc.o | 25 | tape-$(CONFIG_PROC_FS) += tape_proc.o |
27 | tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y) | 26 | tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y) |
28 | obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o | 27 | obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o |
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c deleted file mode 100644 index 1b3924c2fffd..000000000000 --- a/drivers/s390/char/tape_block.c +++ /dev/null | |||
@@ -1,444 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/s390/char/tape_block.c | ||
3 | * block device frontend for tape device driver | ||
4 | * | ||
5 | * S390 and zSeries version | ||
6 | * Copyright (C) 2001,2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | ||
7 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
8 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> | ||
9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
10 | * Stefan Bader <shbader@de.ibm.com> | ||
11 | */ | ||
12 | |||
13 | #define KMSG_COMPONENT "tape" | ||
14 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
15 | |||
16 | #include <linux/fs.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/blkdev.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/buffer_head.h> | ||
22 | #include <linux/kernel.h> | ||
23 | |||
24 | #include <asm/debug.h> | ||
25 | |||
26 | #define TAPE_DBF_AREA tape_core_dbf | ||
27 | |||
28 | #include "tape.h" | ||
29 | |||
30 | #define TAPEBLOCK_MAX_SEC 100 | ||
31 | #define TAPEBLOCK_MIN_REQUEUE 3 | ||
32 | |||
33 | /* | ||
34 | * 2003/11/25 Stefan Bader <shbader@de.ibm.com> | ||
35 | * | ||
36 | * In 2.5/2.6 the block device request function is very likely to be called | ||
37 | * with disabled interrupts (e.g. generic_unplug_device). So the driver can't | ||
38 | * just call any function that tries to allocate CCW requests from that con- | ||
39 | * text since it might sleep. There are two choices to work around this: | ||
40 | * a) do not allocate with kmalloc but use its own memory pool | ||
41 | * b) take requests from the queue outside that context, knowing that | ||
42 | * allocation might sleep | ||
43 | */ | ||
44 | |||
45 | /* | ||
46 | * file operation structure for tape block frontend | ||
47 | */ | ||
48 | static DEFINE_MUTEX(tape_block_mutex); | ||
49 | static int tapeblock_open(struct block_device *, fmode_t); | ||
50 | static int tapeblock_release(struct gendisk *, fmode_t); | ||
51 | static unsigned int tapeblock_check_events(struct gendisk *, unsigned int); | ||
52 | static int tapeblock_revalidate_disk(struct gendisk *); | ||
53 | |||
54 | static const struct block_device_operations tapeblock_fops = { | ||
55 | .owner = THIS_MODULE, | ||
56 | .open = tapeblock_open, | ||
57 | .release = tapeblock_release, | ||
58 | .check_events = tapeblock_check_events, | ||
59 | .revalidate_disk = tapeblock_revalidate_disk, | ||
60 | }; | ||
61 | |||
62 | static int tapeblock_major = 0; | ||
63 | |||
64 | static void | ||
65 | tapeblock_trigger_requeue(struct tape_device *device) | ||
66 | { | ||
67 | /* Protect against rescheduling. */ | ||
68 | if (atomic_cmpxchg(&device->blk_data.requeue_scheduled, 0, 1) != 0) | ||
69 | return; | ||
70 | schedule_work(&device->blk_data.requeue_task); | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * Post finished request. | ||
75 | */ | ||
76 | static void | ||
77 | __tapeblock_end_request(struct tape_request *ccw_req, void *data) | ||
78 | { | ||
79 | struct tape_device *device; | ||
80 | struct request *req; | ||
81 | |||
82 | DBF_LH(6, "__tapeblock_end_request()\n"); | ||
83 | |||
84 | device = ccw_req->device; | ||
85 | req = (struct request *) data; | ||
86 | blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO); | ||
87 | if (ccw_req->rc == 0) | ||
88 | /* Update position. */ | ||
89 | device->blk_data.block_position = | ||
90 | (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B; | ||
91 | else | ||
92 | /* We lost the position information due to an error. */ | ||
93 | device->blk_data.block_position = -1; | ||
94 | device->discipline->free_bread(ccw_req); | ||
95 | if (!list_empty(&device->req_queue) || | ||
96 | blk_peek_request(device->blk_data.request_queue)) | ||
97 | tapeblock_trigger_requeue(device); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Feed the tape device CCW queue with requests supplied in a list. | ||
102 | */ | ||
103 | static int | ||
104 | tapeblock_start_request(struct tape_device *device, struct request *req) | ||
105 | { | ||
106 | struct tape_request * ccw_req; | ||
107 | int rc; | ||
108 | |||
109 | DBF_LH(6, "tapeblock_start_request(%p, %p)\n", device, req); | ||
110 | |||
111 | ccw_req = device->discipline->bread(device, req); | ||
112 | if (IS_ERR(ccw_req)) { | ||
113 | DBF_EVENT(1, "TBLOCK: bread failed\n"); | ||
114 | blk_end_request_all(req, -EIO); | ||
115 | return PTR_ERR(ccw_req); | ||
116 | } | ||
117 | ccw_req->callback = __tapeblock_end_request; | ||
118 | ccw_req->callback_data = (void *) req; | ||
119 | ccw_req->retries = TAPEBLOCK_RETRIES; | ||
120 | |||
121 | rc = tape_do_io_async(device, ccw_req); | ||
122 | if (rc) { | ||
123 | /* | ||
124 | * Start/enqueueing failed. No retries in | ||
125 | * this case. | ||
126 | */ | ||
127 | blk_end_request_all(req, -EIO); | ||
128 | device->discipline->free_bread(ccw_req); | ||
129 | } | ||
130 | |||
131 | return rc; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * Move requests from the block device request queue to the tape device ccw | ||
136 | * queue. | ||
137 | */ | ||
138 | static void | ||
139 | tapeblock_requeue(struct work_struct *work) { | ||
140 | struct tape_blk_data * blkdat; | ||
141 | struct tape_device * device; | ||
142 | struct request_queue * queue; | ||
143 | int nr_queued; | ||
144 | struct request * req; | ||
145 | struct list_head * l; | ||
146 | int rc; | ||
147 | |||
148 | blkdat = container_of(work, struct tape_blk_data, requeue_task); | ||
149 | device = blkdat->device; | ||
150 | if (!device) | ||
151 | return; | ||
152 | |||
153 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
154 | queue = device->blk_data.request_queue; | ||
155 | |||
156 | /* Count number of requests on ccw queue. */ | ||
157 | nr_queued = 0; | ||
158 | list_for_each(l, &device->req_queue) | ||
159 | nr_queued++; | ||
160 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
161 | |||
162 | spin_lock_irq(&device->blk_data.request_queue_lock); | ||
163 | while ( | ||
164 | blk_peek_request(queue) && | ||
165 | nr_queued < TAPEBLOCK_MIN_REQUEUE | ||
166 | ) { | ||
167 | req = blk_fetch_request(queue); | ||
168 | if (rq_data_dir(req) == WRITE) { | ||
169 | DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); | ||
170 | spin_unlock_irq(&device->blk_data.request_queue_lock); | ||
171 | blk_end_request_all(req, -EIO); | ||
172 | spin_lock_irq(&device->blk_data.request_queue_lock); | ||
173 | continue; | ||
174 | } | ||
175 | nr_queued++; | ||
176 | spin_unlock_irq(&device->blk_data.request_queue_lock); | ||
177 | rc = tapeblock_start_request(device, req); | ||
178 | spin_lock_irq(&device->blk_data.request_queue_lock); | ||
179 | } | ||
180 | spin_unlock_irq(&device->blk_data.request_queue_lock); | ||
181 | atomic_set(&device->blk_data.requeue_scheduled, 0); | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Tape request queue function. Called from ll_rw_blk.c | ||
186 | */ | ||
187 | static void | ||
188 | tapeblock_request_fn(struct request_queue *queue) | ||
189 | { | ||
190 | struct tape_device *device; | ||
191 | |||
192 | device = (struct tape_device *) queue->queuedata; | ||
193 | DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device); | ||
194 | BUG_ON(device == NULL); | ||
195 | tapeblock_trigger_requeue(device); | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * This function is called for every new tapedevice | ||
200 | */ | ||
201 | int | ||
202 | tapeblock_setup_device(struct tape_device * device) | ||
203 | { | ||
204 | struct tape_blk_data * blkdat; | ||
205 | struct gendisk * disk; | ||
206 | int rc; | ||
207 | |||
208 | blkdat = &device->blk_data; | ||
209 | blkdat->device = device; | ||
210 | spin_lock_init(&blkdat->request_queue_lock); | ||
211 | atomic_set(&blkdat->requeue_scheduled, 0); | ||
212 | |||
213 | blkdat->request_queue = blk_init_queue( | ||
214 | tapeblock_request_fn, | ||
215 | &blkdat->request_queue_lock | ||
216 | ); | ||
217 | if (!blkdat->request_queue) | ||
218 | return -ENOMEM; | ||
219 | |||
220 | rc = elevator_change(blkdat->request_queue, "noop"); | ||
221 | if (rc) | ||
222 | goto cleanup_queue; | ||
223 | |||
224 | blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); | ||
225 | blk_queue_max_hw_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC); | ||
226 | blk_queue_max_segments(blkdat->request_queue, -1L); | ||
227 | blk_queue_max_segment_size(blkdat->request_queue, -1L); | ||
228 | blk_queue_segment_boundary(blkdat->request_queue, -1L); | ||
229 | |||
230 | disk = alloc_disk(1); | ||
231 | if (!disk) { | ||
232 | rc = -ENOMEM; | ||
233 | goto cleanup_queue; | ||
234 | } | ||
235 | |||
236 | disk->major = tapeblock_major; | ||
237 | disk->first_minor = device->first_minor; | ||
238 | disk->fops = &tapeblock_fops; | ||
239 | disk->private_data = tape_get_device(device); | ||
240 | disk->queue = blkdat->request_queue; | ||
241 | set_capacity(disk, 0); | ||
242 | sprintf(disk->disk_name, "btibm%d", | ||
243 | device->first_minor / TAPE_MINORS_PER_DEV); | ||
244 | |||
245 | blkdat->disk = disk; | ||
246 | blkdat->medium_changed = 1; | ||
247 | blkdat->request_queue->queuedata = tape_get_device(device); | ||
248 | |||
249 | add_disk(disk); | ||
250 | |||
251 | tape_get_device(device); | ||
252 | INIT_WORK(&blkdat->requeue_task, tapeblock_requeue); | ||
253 | |||
254 | return 0; | ||
255 | |||
256 | cleanup_queue: | ||
257 | blk_cleanup_queue(blkdat->request_queue); | ||
258 | blkdat->request_queue = NULL; | ||
259 | |||
260 | return rc; | ||
261 | } | ||
262 | |||
263 | void | ||
264 | tapeblock_cleanup_device(struct tape_device *device) | ||
265 | { | ||
266 | flush_work_sync(&device->blk_data.requeue_task); | ||
267 | tape_put_device(device); | ||
268 | |||
269 | if (!device->blk_data.disk) { | ||
270 | goto cleanup_queue; | ||
271 | } | ||
272 | |||
273 | del_gendisk(device->blk_data.disk); | ||
274 | device->blk_data.disk->private_data = NULL; | ||
275 | tape_put_device(device); | ||
276 | put_disk(device->blk_data.disk); | ||
277 | |||
278 | device->blk_data.disk = NULL; | ||
279 | cleanup_queue: | ||
280 | device->blk_data.request_queue->queuedata = NULL; | ||
281 | tape_put_device(device); | ||
282 | |||
283 | blk_cleanup_queue(device->blk_data.request_queue); | ||
284 | device->blk_data.request_queue = NULL; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Detect number of blocks of the tape. | ||
289 | * FIXME: can we extent this to detect the blocks size as well ? | ||
290 | */ | ||
291 | static int | ||
292 | tapeblock_revalidate_disk(struct gendisk *disk) | ||
293 | { | ||
294 | struct tape_device * device; | ||
295 | unsigned int nr_of_blks; | ||
296 | int rc; | ||
297 | |||
298 | device = (struct tape_device *) disk->private_data; | ||
299 | BUG_ON(!device); | ||
300 | |||
301 | if (!device->blk_data.medium_changed) | ||
302 | return 0; | ||
303 | |||
304 | rc = tape_mtop(device, MTFSFM, 1); | ||
305 | if (rc) | ||
306 | return rc; | ||
307 | |||
308 | rc = tape_mtop(device, MTTELL, 1); | ||
309 | if (rc < 0) | ||
310 | return rc; | ||
311 | |||
312 | pr_info("%s: Determining the size of the recorded area...\n", | ||
313 | dev_name(&device->cdev->dev)); | ||
314 | DBF_LH(3, "Image file ends at %d\n", rc); | ||
315 | nr_of_blks = rc; | ||
316 | |||
317 | /* This will fail for the first file. Catch the error by checking the | ||
318 | * position. */ | ||
319 | tape_mtop(device, MTBSF, 1); | ||
320 | |||
321 | rc = tape_mtop(device, MTTELL, 1); | ||
322 | if (rc < 0) | ||
323 | return rc; | ||
324 | |||
325 | if (rc > nr_of_blks) | ||
326 | return -EINVAL; | ||
327 | |||
328 | DBF_LH(3, "Image file starts at %d\n", rc); | ||
329 | device->bof = rc; | ||
330 | nr_of_blks -= rc; | ||
331 | |||
332 | pr_info("%s: The size of the recorded area is %i blocks\n", | ||
333 | dev_name(&device->cdev->dev), nr_of_blks); | ||
334 | set_capacity(device->blk_data.disk, | ||
335 | nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); | ||
336 | |||
337 | device->blk_data.block_position = 0; | ||
338 | device->blk_data.medium_changed = 0; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static unsigned int | ||
343 | tapeblock_check_events(struct gendisk *disk, unsigned int clearing) | ||
344 | { | ||
345 | struct tape_device *device; | ||
346 | |||
347 | device = (struct tape_device *) disk->private_data; | ||
348 | DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n", | ||
349 | device, device->blk_data.medium_changed); | ||
350 | |||
351 | return device->blk_data.medium_changed ? DISK_EVENT_MEDIA_CHANGE : 0; | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * Block frontend tape device open function. | ||
356 | */ | ||
357 | static int | ||
358 | tapeblock_open(struct block_device *bdev, fmode_t mode) | ||
359 | { | ||
360 | struct gendisk * disk = bdev->bd_disk; | ||
361 | struct tape_device * device; | ||
362 | int rc; | ||
363 | |||
364 | mutex_lock(&tape_block_mutex); | ||
365 | device = tape_get_device(disk->private_data); | ||
366 | |||
367 | if (device->required_tapemarks) { | ||
368 | DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); | ||
369 | pr_warning("%s: Opening the tape failed because of missing " | ||
370 | "end-of-file marks\n", dev_name(&device->cdev->dev)); | ||
371 | rc = -EPERM; | ||
372 | goto put_device; | ||
373 | } | ||
374 | |||
375 | rc = tape_open(device); | ||
376 | if (rc) | ||
377 | goto put_device; | ||
378 | |||
379 | rc = tapeblock_revalidate_disk(disk); | ||
380 | if (rc) | ||
381 | goto release; | ||
382 | |||
383 | /* | ||
384 | * Note: The reference to <device> is hold until the release function | ||
385 | * is called. | ||
386 | */ | ||
387 | tape_state_set(device, TS_BLKUSE); | ||
388 | mutex_unlock(&tape_block_mutex); | ||
389 | return 0; | ||
390 | |||
391 | release: | ||
392 | tape_release(device); | ||
393 | put_device: | ||
394 | tape_put_device(device); | ||
395 | mutex_unlock(&tape_block_mutex); | ||
396 | return rc; | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * Block frontend tape device release function. | ||
401 | * | ||
402 | * Note: One reference to the tape device was made by the open function. So | ||
403 | * we just get the pointer here and release the reference. | ||
404 | */ | ||
405 | static int | ||
406 | tapeblock_release(struct gendisk *disk, fmode_t mode) | ||
407 | { | ||
408 | struct tape_device *device = disk->private_data; | ||
409 | |||
410 | mutex_lock(&tape_block_mutex); | ||
411 | tape_state_set(device, TS_IN_USE); | ||
412 | tape_release(device); | ||
413 | tape_put_device(device); | ||
414 | mutex_unlock(&tape_block_mutex); | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * Initialize block device frontend. | ||
421 | */ | ||
422 | int | ||
423 | tapeblock_init(void) | ||
424 | { | ||
425 | int rc; | ||
426 | |||
427 | /* Register the tape major number to the kernel */ | ||
428 | rc = register_blkdev(tapeblock_major, "tBLK"); | ||
429 | if (rc < 0) | ||
430 | return rc; | ||
431 | |||
432 | if (tapeblock_major == 0) | ||
433 | tapeblock_major = rc; | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | /* | ||
438 | * Deregister major for block device frontend | ||
439 | */ | ||
440 | void | ||
441 | tapeblock_exit(void) | ||
442 | { | ||
443 | unregister_blkdev(tapeblock_major, "tBLK"); | ||
444 | } | ||