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#include <linux/fs.h> 14#include <linux/module.h> 15#include <linux/blkdev.h> 16#include <linux/interrupt.h> 17#include <linux/buffer_head.h> 18#include <linux/kernel.h> 19 20#include <asm/debug.h> 21 22#define TAPE_DBF_AREA tape_core_dbf 23 24#include "tape.h" 25 26#define PRINTK_HEADER "TAPE_BLOCK: " 27 28#define TAPEBLOCK_MAX_SEC 100 29#define TAPEBLOCK_MIN_REQUEUE 3 30 31 32/* 33 * file operation structure for tape block frontend 34 */ 35static int tapeblock_open(struct inode *, struct file *); 36static int tapeblock_release(struct inode *, struct file *); 37static int tapeblock_ioctl(struct inode *, struct file *, unsigned int, 38 unsigned long); 39static int tapeblock_medium_changed(struct gendisk *); 40static int tapeblock_revalidate_disk(struct gendisk *); 41 42static struct block_device_operations tapeblock_fops = { 43 .owner = THIS_MODULE, 44 .open = tapeblock_open, 45 .release = tapeblock_release, 46 .ioctl = tapeblock_ioctl, 47 .media_changed = tapeblock_medium_changed, 48 .revalidate_disk = tapeblock_revalidate_disk, 49}; 50 51static int tapeblock_major = 0; 52 53static void 54tapeblock_trigger_requeue(struct tape_device *device) 55{ 56 /* Protect against rescheduling. */ 57 if (atomic_cmpxchg(&device->blk_data.requeue_scheduled, 0, 1) != 0) 58 return; 59 schedule_work(&device->blk_data.requeue_task); 60} 61 62/* 63 * Post finished request. 64 */ 65static void 66tapeblock_end_request(struct request *req, int uptodate) 67{ 68 if (end_that_request_first(req, uptodate, req->hard_nr_sectors)) 69 BUG(); 70 end_that_request_last(req, uptodate); 71} 72 73static void 74__tapeblock_end_request(struct tape_request *ccw_req, void *data) 75{ 76 struct tape_device *device; 77 struct request *req; 78 79 DBF_LH(6, "__tapeblock_end_request()\n"); 80 81 device = ccw_req->device; 82 req = (struct request *) data; 83 tapeblock_end_request(req, ccw_req->rc == 0); 84 if (ccw_req->rc == 0) 85 /* Update position. */ 86 device->blk_data.block_position = 87 (req->sector + req->nr_sectors) >> TAPEBLOCK_HSEC_S2B; 88 else 89 /* We lost the position information due to an error. */ 90 device->blk_data.block_position = -1; 91 device->discipline->free_bread(ccw_req); 92 if (!list_empty(&device->req_queue) || 93 elv_next_request(device->blk_data.request_queue)) 94 tapeblock_trigger_requeue(device); 95} 96 97/* 98 * Feed the tape device CCW queue with requests supplied in a list. 99 */ 100static int 101tapeblock_start_request(struct tape_device *device, struct request *req) 102{ 103 struct tape_request * ccw_req; 104 int rc; 105 106 DBF_LH(6, "tapeblock_start_request(%p, %p)\n", device, req); 107 108 ccw_req = device->discipline->bread(device, req); 109 if (IS_ERR(ccw_req)) { 110 DBF_EVENT(1, "TBLOCK: bread failed\n"); 111 tapeblock_end_request(req, 0); 112 return PTR_ERR(ccw_req); 113 } 114 ccw_req->callback = __tapeblock_end_request; 115 ccw_req->callback_data = (void *) req; 116 ccw_req->retries = TAPEBLOCK_RETRIES; 117 118 rc = tape_do_io_async(device, ccw_req); 119 if (rc) { 120 /* 121 * Start/enqueueing failed. No retries in 122 * this case. 123 */ 124 tapeblock_end_request(req, 0); 125 device->discipline->free_bread(ccw_req); 126 } 127 128 return rc; 129} 130 131/* 132 * Move requests from the block device request queue to the tape device ccw 133 * queue. 134 */ 135static void 136tapeblock_requeue(struct work_struct *work) { 137 struct tape_blk_data * blkdat; 138 struct tape_device * device; 139 request_queue_t * queue; 140 int nr_queued; 141 struct request * req; 142 struct list_head * l; 143 int rc; 144 145 blkdat = container_of(work, struct tape_blk_data, requeue_task); 146 device = blkdat->device; 147 if (!device) 148 return; 149 150 spin_lock_irq(get_ccwdev_lock(device->cdev)); 151 queue = device->blk_data.request_queue; 152 153 /* Count number of requests on ccw queue. */ 154 nr_queued = 0; 155 list_for_each(l, &device->req_queue) 156 nr_queued++; 157 spin_unlock(get_ccwdev_lock(device->cdev)); 158 159 spin_lock(&device->blk_data.request_queue_lock); 160 while ( 161 !blk_queue_plugged(queue) && 162 elv_next_request(queue) && 163 nr_queued < TAPEBLOCK_MIN_REQUEUE 164 ) { 165 req = elv_next_request(queue); 166 if (rq_data_dir(req) == WRITE) { 167 DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); 168 blkdev_dequeue_request(req); 169 tapeblock_end_request(req, 0); 170 continue; 171 } 172 spin_unlock_irq(&device->blk_data.request_queue_lock); 173 rc = tapeblock_start_request(device, req); 174 spin_lock_irq(&device->blk_data.request_queue_lock); 175 blkdev_dequeue_request(req); 176 nr_queued++; 177 } 178 spin_unlock_irq(&device->blk_data.request_queue_lock); 179 atomic_set(&device->blk_data.requeue_scheduled, 0); 180} 181 182/* 183 * Tape request queue function. Called from ll_rw_blk.c 184 */ 185static void 186tapeblock_request_fn(request_queue_t *queue) 187{ 188 struct tape_device *device; 189 190 device = (struct tape_device *) queue->queuedata; 191 DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device); 192 BUG_ON(device == NULL); 193 tapeblock_trigger_requeue(device); 194} 195 196/* 197 * This function is called for every new tapedevice 198 */ 199int 200tapeblock_setup_device(struct tape_device * device) 201{ 202 struct tape_blk_data * blkdat; 203 struct gendisk * disk; 204 int rc; 205 206 blkdat = &device->blk_data; 207 blkdat->device = device; 208 spin_lock_init(&blkdat->request_queue_lock); 209 atomic_set(&blkdat->requeue_scheduled, 0); 210 211 blkdat->request_queue = blk_init_queue( 212 tapeblock_request_fn, 213 &blkdat->request_queue_lock 214 ); 215 if (!blkdat->request_queue) 216 return -ENOMEM; 217 218 elevator_exit(blkdat->request_queue->elevator); 219 rc = elevator_init(blkdat->request_queue, "noop"); 220 if (rc) 221 goto cleanup_queue; 222 223 blk_queue_hardsect_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); 224 blk_queue_max_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC); 225 blk_queue_max_phys_segments(blkdat->request_queue, -1L); 226 blk_queue_max_hw_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_reference(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_reference(device); 248 249 add_disk(disk); 250 251 tape_get_device_reference(device); 252 INIT_WORK(&blkdat->requeue_task, tapeblock_requeue); 253 254 return 0; 255 256cleanup_queue: 257 blk_cleanup_queue(blkdat->request_queue); 258 blkdat->request_queue = NULL; 259 260 return rc; 261} 262 263void 264tapeblock_cleanup_device(struct tape_device *device) 265{ 266 flush_scheduled_work(); 267 tape_put_device(device); 268 269 if (!device->blk_data.disk) { 270 PRINT_ERR("(%s): No gendisk to clean up!\n", 271 device->cdev->dev.bus_id); 272 goto cleanup_queue; 273 } 274 275 del_gendisk(device->blk_data.disk); 276 device->blk_data.disk->private_data = 277 tape_put_device(device->blk_data.disk->private_data); 278 put_disk(device->blk_data.disk); 279 280 device->blk_data.disk = NULL; 281cleanup_queue: 282 device->blk_data.request_queue->queuedata = tape_put_device(device); 283 284 blk_cleanup_queue(device->blk_data.request_queue); 285 device->blk_data.request_queue = NULL; 286} 287 288static int 289tapeblock_revalidate_disk(struct gendisk *disk) 290{ 291 struct tape_device * device; 292 unsigned int nr_of_blks; 293 int rc; 294 295 device = (struct tape_device *) disk->private_data; 296 BUG_ON(!device); 297 298 if (!device->blk_data.medium_changed) 299 return 0; 300 301 PRINT_INFO("Detecting media size...\n"); 302 rc = tape_mtop(device, MTFSFM, 1); 303 if (rc) 304 return rc; 305 306 rc = tape_mtop(device, MTTELL, 1); 307 if (rc < 0) 308 return rc; 309 310 DBF_LH(3, "Image file ends at %d\n", rc); 311 nr_of_blks = rc; 312 313 /* This will fail for the first file. Catch the error by checking the 314 * position. */ 315 tape_mtop(device, MTBSF, 1); 316 317 rc = tape_mtop(device, MTTELL, 1); 318 if (rc < 0) 319 return rc; 320 321 if (rc > nr_of_blks) 322 return -EINVAL; 323 324 DBF_LH(3, "Image file starts at %d\n", rc); 325 device->bof = rc; 326 nr_of_blks -= rc; 327 328 PRINT_INFO("Found %i blocks on media\n", nr_of_blks); 329 set_capacity(device->blk_data.disk, 330 nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); 331 332 device->blk_data.block_position = 0; 333 device->blk_data.medium_changed = 0; 334 return 0; 335} 336 337static int 338tapeblock_medium_changed(struct gendisk *disk) 339{ 340 struct tape_device *device; 341 342 device = (struct tape_device *) disk->private_data; 343 DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n", 344 device, device->blk_data.medium_changed); 345 346 return device->blk_data.medium_changed; 347} 348 349/* 350 * Block frontend tape device open function. 351 */ 352static int 353tapeblock_open(struct inode *inode, struct file *filp) 354{ 355 struct gendisk * disk; 356 struct tape_device * device; 357 int rc; 358 359 disk = inode->i_bdev->bd_disk; 360 device = tape_get_device_reference(disk->private_data); 361 362 if (device->required_tapemarks) { 363 DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); 364 PRINT_ERR("TBLOCK: Refusing to open tape with missing" 365 " end of file marks.\n"); 366 rc = -EPERM; 367 goto put_device; 368 } 369 370 rc = tape_open(device); 371 if (rc) 372 goto put_device; 373 374 rc = tapeblock_revalidate_disk(disk); 375 if (rc) 376 goto release; 377 378 /* 379 * Note: The reference to <device> is hold until the release function 380 * is called. 381 */ 382 tape_state_set(device, TS_BLKUSE); 383 return 0; 384 385release: 386 tape_release(device); 387 put_device: 388 tape_put_device(device); 389 return rc; 390} 391 392/* 393 * Block frontend tape device release function. 394 * 395 * Note: One reference to the tape device was made by the open function. So 396 * we just get the pointer here and release the reference. 397 */ 398static int 399tapeblock_release(struct inode *inode, struct file *filp) 400{ 401 struct gendisk *disk = inode->i_bdev->bd_disk; 402 struct tape_device *device = disk->private_data; 403 404 tape_state_set(device, TS_IN_USE); 405 tape_release(device); 406 tape_put_device(device); 407 408 return 0; 409} 410 411/* 412 * Support of some generic block device IOCTLs. 413 */ 414static int 415tapeblock_ioctl( 416 struct inode * inode, 417 struct file * file, 418 unsigned int command, 419 unsigned long arg 420) { 421 int rc; 422 int minor; 423 struct gendisk *disk; 424 struct tape_device *device; 425 426 rc = 0; 427 disk = inode->i_bdev->bd_disk; 428 BUG_ON(!disk); 429 device = disk->private_data; 430 BUG_ON(!device); 431 minor = iminor(inode); 432 433 DBF_LH(6, "tapeblock_ioctl(0x%0x)\n", command); 434 DBF_LH(6, "device = %d:%d\n", tapeblock_major, minor); 435 436 switch (command) { 437 /* Refuse some IOCTL calls without complaining (mount). */ 438 case 0x5310: /* CDROMMULTISESSION */ 439 rc = -EINVAL; 440 break; 441 default: 442 PRINT_WARN("invalid ioctl 0x%x\n", command); 443 rc = -EINVAL; 444 } 445 446 return rc; 447} 448 449/* 450 * Initialize block device frontend. 451 */ 452int 453tapeblock_init(void) 454{ 455 int rc; 456 457 /* Register the tape major number to the kernel */ 458 rc = register_blkdev(tapeblock_major, "tBLK"); 459 if (rc < 0) 460 return rc; 461 462 if (tapeblock_major == 0) 463 tapeblock_major = rc; 464 PRINT_INFO("tape gets major %d for block device\n", tapeblock_major); 465 return 0; 466} 467 468/* 469 * Deregister major for block device frontend 470 */ 471void 472tapeblock_exit(void) 473{ 474 unregister_blkdev(tapeblock_major, "tBLK"); 475} 476