Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] s390: 3590 tape driver

Michael Holzheu <holzheu@de.ibm.com>,
Martin Schwidefsky <schwidefsky@de.ibm.com>

Signed-off-by: Stefan Bader <shbader@de.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Stefan Bader and committed by
Linus Torvalds
b6cba4ee 5f384338

+1443 -11
+7 -1
drivers/s390/Kconfig
··· 183 183 tape subsystems and 100% compatibles. 184 184 It is safe to say "Y" here. 185 185 186 - 186 + config S390_TAPE_3590 187 + tristate "Support for 3590 tape hardware" 188 + depends on S390_TAPE 189 + help 190 + Select this option if you want to access IBM 3590 magnetic 191 + tape subsystems and 100% compatibles. 192 + It is safe to say "Y" here. 187 193 188 194 config VMLOGRDR 189 195 tristate "Support for the z/VM recording system services (VM only)"
+1
drivers/s390/char/Makefile
··· 26 26 tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y) 27 27 obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o 28 28 obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o 29 + obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o 29 30 obj-$(CONFIG_MONREADER) += monreader.o
+1 -7
drivers/s390/char/tape_34xx.c
··· 2 2 * drivers/s390/char/tape_34xx.c 3 3 * tape device discipline for 3480/3490 tapes. 4 4 * 5 - * S390 and zSeries version 6 - * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation 5 + * Copyright (C) IBM Corp. 2001,2006 7 6 * Author(s): Carsten Otte <cotte@de.ibm.com> 8 7 * Tuan Ngo-Anh <ngoanh@de.ibm.com> 9 8 * Martin Schwidefsky <schwidefsky@de.ibm.com> ··· 26 27 */ 27 28 debug_info_t *TAPE_DBF_AREA = NULL; 28 29 EXPORT_SYMBOL(TAPE_DBF_AREA); 29 - 30 - enum tape_34xx_type { 31 - tape_3480, 32 - tape_3490, 33 - }; 34 30 35 31 #define TAPE34XX_FMT_3480 0 36 32 #define TAPE34XX_FMT_3480_2_XF 1
+1301
drivers/s390/char/tape_3590.c
··· 1 + /* 2 + * drivers/s390/char/tape_3590.c 3 + * tape device discipline for 3590 tapes. 4 + * 5 + * Copyright (C) IBM Corp. 2001,2006 6 + * Author(s): Stefan Bader <shbader@de.ibm.com> 7 + * Michael Holzheu <holzheu@de.ibm.com> 8 + * Martin Schwidefsky <schwidefsky@de.ibm.com> 9 + */ 10 + 11 + #include <linux/config.h> 12 + #include <linux/module.h> 13 + #include <linux/init.h> 14 + #include <linux/bio.h> 15 + 16 + #define TAPE_DBF_AREA tape_3590_dbf 17 + 18 + #include "tape.h" 19 + #include "tape_std.h" 20 + #include "tape_3590.h" 21 + 22 + /* 23 + * Pointer to debug area. 24 + */ 25 + debug_info_t *TAPE_DBF_AREA = NULL; 26 + EXPORT_SYMBOL(TAPE_DBF_AREA); 27 + 28 + /******************************************************************* 29 + * Error Recovery fuctions: 30 + * - Read Opposite: implemented 31 + * - Read Device (buffered) log: BRA 32 + * - Read Library log: BRA 33 + * - Swap Devices: BRA 34 + * - Long Busy: BRA 35 + * - Special Intercept: BRA 36 + * - Read Alternate: implemented 37 + *******************************************************************/ 38 + 39 + #define PRINTK_HEADER "TAPE_3590: " 40 + 41 + static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = { 42 + [0x00] = "", 43 + [0x10] = "Lost Sense", 44 + [0x11] = "Assigned Elsewhere", 45 + [0x12] = "Allegiance Reset", 46 + [0x13] = "Shared Access Violation", 47 + [0x20] = "Command Reject", 48 + [0x21] = "Configuration Error", 49 + [0x22] = "Protection Exception", 50 + [0x23] = "Write Protect", 51 + [0x24] = "Write Length", 52 + [0x25] = "Read-Only Format", 53 + [0x31] = "Beginning of Partition", 54 + [0x33] = "End of Partition", 55 + [0x34] = "End of Data", 56 + [0x35] = "Block not found", 57 + [0x40] = "Device Intervention", 58 + [0x41] = "Loader Intervention", 59 + [0x42] = "Library Intervention", 60 + [0x50] = "Write Error", 61 + [0x51] = "Erase Error", 62 + [0x52] = "Formatting Error", 63 + [0x53] = "Read Error", 64 + [0x54] = "Unsupported Format", 65 + [0x55] = "No Formatting", 66 + [0x56] = "Positioning lost", 67 + [0x57] = "Read Length", 68 + [0x60] = "Unsupported Medium", 69 + [0x61] = "Medium Length Error", 70 + [0x62] = "Medium removed", 71 + [0x64] = "Load Check", 72 + [0x65] = "Unload Check", 73 + [0x70] = "Equipment Check", 74 + [0x71] = "Bus out Check", 75 + [0x72] = "Protocol Error", 76 + [0x73] = "Interface Error", 77 + [0x74] = "Overrun", 78 + [0x75] = "Halt Signal", 79 + [0x90] = "Device fenced", 80 + [0x91] = "Device Path fenced", 81 + [0xa0] = "Volume misplaced", 82 + [0xa1] = "Volume inaccessible", 83 + [0xa2] = "Volume in input", 84 + [0xa3] = "Volume ejected", 85 + [0xa4] = "All categories reserved", 86 + [0xa5] = "Duplicate Volume", 87 + [0xa6] = "Library Manager Offline", 88 + [0xa7] = "Library Output Station full", 89 + [0xa8] = "Vision System non-operational", 90 + [0xa9] = "Library Manager Equipment Check", 91 + [0xaa] = "Library Equipment Check", 92 + [0xab] = "All Library Cells full", 93 + [0xac] = "No Cleaner Volumes in Library", 94 + [0xad] = "I/O Station door open", 95 + [0xae] = "Subsystem environmental alert", 96 + }; 97 + 98 + /* 99 + * 3590 IOCTL Overload 100 + */ 101 + static int 102 + tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg) 103 + { 104 + switch (cmd) { 105 + case TAPE390_DISPLAY: { 106 + struct display_struct disp; 107 + 108 + if (copy_from_user(&disp, (char __user *) arg, sizeof(disp))) 109 + return -EFAULT; 110 + 111 + return tape_std_display(device, &disp); 112 + } 113 + default: 114 + return -EINVAL; /* no additional ioctls */ 115 + } 116 + } 117 + 118 + /* 119 + * SENSE Medium: Get Sense data about medium state 120 + */ 121 + static int 122 + tape_3590_sense_medium(struct tape_device *device) 123 + { 124 + struct tape_request *request; 125 + 126 + request = tape_alloc_request(1, 128); 127 + if (IS_ERR(request)) 128 + return PTR_ERR(request); 129 + request->op = TO_MSEN; 130 + tape_ccw_end(request->cpaddr, MEDIUM_SENSE, 128, request->cpdata); 131 + return tape_do_io_free(device, request); 132 + } 133 + 134 + /* 135 + * MTTELL: Tell block. Return the number of block relative to current file. 136 + */ 137 + static int 138 + tape_3590_mttell(struct tape_device *device, int mt_count) 139 + { 140 + __u64 block_id; 141 + int rc; 142 + 143 + rc = tape_std_read_block_id(device, &block_id); 144 + if (rc) 145 + return rc; 146 + return block_id >> 32; 147 + } 148 + 149 + /* 150 + * MTSEEK: seek to the specified block. 151 + */ 152 + static int 153 + tape_3590_mtseek(struct tape_device *device, int count) 154 + { 155 + struct tape_request *request; 156 + 157 + DBF_EVENT(6, "xsee id: %x\n", count); 158 + request = tape_alloc_request(3, 4); 159 + if (IS_ERR(request)) 160 + return PTR_ERR(request); 161 + request->op = TO_LBL; 162 + tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); 163 + *(__u32 *) request->cpdata = count; 164 + tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata); 165 + tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL); 166 + return tape_do_io_free(device, request); 167 + } 168 + 169 + /* 170 + * Read Opposite Error Recovery Function: 171 + * Used, when Read Forward does not work 172 + */ 173 + static void 174 + tape_3590_read_opposite(struct tape_device *device, 175 + struct tape_request *request) 176 + { 177 + struct tape_3590_disc_data *data; 178 + 179 + /* 180 + * We have allocated 4 ccws in tape_std_read, so we can now 181 + * transform the request to a read backward, followed by a 182 + * forward space block. 183 + */ 184 + request->op = TO_RBA; 185 + tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); 186 + data = device->discdata; 187 + tape_ccw_cc_idal(request->cpaddr + 1, data->read_back_op, 188 + device->char_data.idal_buf); 189 + tape_ccw_cc(request->cpaddr + 2, FORSPACEBLOCK, 0, NULL); 190 + tape_ccw_end(request->cpaddr + 3, NOP, 0, NULL); 191 + DBF_EVENT(6, "xrop ccwg\n"); 192 + } 193 + 194 + /* 195 + * Read Attention Msg 196 + * This should be done after an interrupt with attention bit (0x80) 197 + * in device state. 198 + * 199 + * After a "read attention message" request there are two possible 200 + * results: 201 + * 202 + * 1. A unit check is presented, when attention sense is present (e.g. when 203 + * a medium has been unloaded). The attention sense comes then 204 + * together with the unit check. The recovery action is either "retry" 205 + * (in case there is an attention message pending) or "permanent error". 206 + * 207 + * 2. The attention msg is written to the "read subsystem data" buffer. 208 + * In this case we probably should print it to the console. 209 + */ 210 + static int 211 + tape_3590_read_attmsg(struct tape_device *device) 212 + { 213 + struct tape_request *request; 214 + char *buf; 215 + 216 + request = tape_alloc_request(3, 4096); 217 + if (IS_ERR(request)) 218 + return PTR_ERR(request); 219 + request->op = TO_READ_ATTMSG; 220 + buf = request->cpdata; 221 + buf[0] = PREP_RD_SS_DATA; 222 + buf[6] = RD_ATTMSG; /* read att msg */ 223 + tape_ccw_cc(request->cpaddr, PERFORM_SS_FUNC, 12, buf); 224 + tape_ccw_cc(request->cpaddr + 1, READ_SS_DATA, 4096 - 12, buf + 12); 225 + tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL); 226 + return tape_do_io_free(device, request); 227 + } 228 + 229 + /* 230 + * These functions are used to schedule follow-up actions from within an 231 + * interrupt context (like unsolicited interrupts). 232 + */ 233 + static void 234 + tape_3590_work_handler(void *data) 235 + { 236 + struct { 237 + struct tape_device *device; 238 + enum tape_op op; 239 + struct work_struct work; 240 + } *p = data; 241 + 242 + switch (p->op) { 243 + case TO_MSEN: 244 + tape_3590_sense_medium(p->device); 245 + break; 246 + case TO_READ_ATTMSG: 247 + tape_3590_read_attmsg(p->device); 248 + break; 249 + default: 250 + DBF_EVENT(3, "T3590: work handler undefined for " 251 + "operation 0x%02x\n", p->op); 252 + } 253 + tape_put_device(p->device); 254 + kfree(p); 255 + } 256 + 257 + static int 258 + tape_3590_schedule_work(struct tape_device *device, enum tape_op op) 259 + { 260 + struct { 261 + struct tape_device *device; 262 + enum tape_op op; 263 + struct work_struct work; 264 + } *p; 265 + 266 + if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL) 267 + return -ENOMEM; 268 + 269 + INIT_WORK(&p->work, tape_3590_work_handler, p); 270 + 271 + p->device = tape_get_device_reference(device); 272 + p->op = op; 273 + 274 + schedule_work(&p->work); 275 + return 0; 276 + } 277 + 278 + #ifdef CONFIG_S390_TAPE_BLOCK 279 + /* 280 + * Tape Block READ 281 + */ 282 + static struct tape_request * 283 + tape_3590_bread(struct tape_device *device, struct request *req) 284 + { 285 + struct tape_request *request; 286 + struct ccw1 *ccw; 287 + int count = 0, start_block, i; 288 + unsigned off; 289 + char *dst; 290 + struct bio_vec *bv; 291 + struct bio *bio; 292 + 293 + DBF_EVENT(6, "xBREDid:"); 294 + start_block = req->sector >> TAPEBLOCK_HSEC_S2B; 295 + DBF_EVENT(6, "start_block = %i\n", start_block); 296 + 297 + rq_for_each_bio(bio, req) { 298 + bio_for_each_segment(bv, bio, i) { 299 + count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); 300 + } 301 + } 302 + request = tape_alloc_request(2 + count + 1, 4); 303 + if (IS_ERR(request)) 304 + return request; 305 + request->op = TO_BLOCK; 306 + *(__u32 *) request->cpdata = start_block; 307 + ccw = request->cpaddr; 308 + ccw = tape_ccw_cc(ccw, MODE_SET_DB, 1, device->modeset_byte); 309 + 310 + /* 311 + * We always setup a nop after the mode set ccw. This slot is 312 + * used in tape_std_check_locate to insert a locate ccw if the 313 + * current tape position doesn't match the start block to be read. 314 + */ 315 + ccw = tape_ccw_cc(ccw, NOP, 0, NULL); 316 + 317 + rq_for_each_bio(bio, req) { 318 + bio_for_each_segment(bv, bio, i) { 319 + dst = kmap(bv->bv_page) + bv->bv_offset; 320 + for (off = 0; off < bv->bv_len; 321 + off += TAPEBLOCK_HSEC_SIZE) { 322 + ccw->flags = CCW_FLAG_CC; 323 + ccw->cmd_code = READ_FORWARD; 324 + ccw->count = TAPEBLOCK_HSEC_SIZE; 325 + set_normalized_cda(ccw, (void *) __pa(dst)); 326 + ccw++; 327 + dst += TAPEBLOCK_HSEC_SIZE; 328 + } 329 + if (off > bv->bv_len) 330 + BUG(); 331 + } 332 + } 333 + ccw = tape_ccw_end(ccw, NOP, 0, NULL); 334 + DBF_EVENT(6, "xBREDccwg\n"); 335 + return request; 336 + } 337 + 338 + static void 339 + tape_3590_free_bread(struct tape_request *request) 340 + { 341 + struct ccw1 *ccw; 342 + 343 + /* Last ccw is a nop and doesn't need clear_normalized_cda */ 344 + for (ccw = request->cpaddr; ccw->flags & CCW_FLAG_CC; ccw++) 345 + if (ccw->cmd_code == READ_FORWARD) 346 + clear_normalized_cda(ccw); 347 + tape_free_request(request); 348 + } 349 + 350 + /* 351 + * check_locate is called just before the tape request is passed to 352 + * the common io layer for execution. It has to check the current 353 + * tape position and insert a locate ccw if it doesn't match the 354 + * start block for the request. 355 + */ 356 + static void 357 + tape_3590_check_locate(struct tape_device *device, struct tape_request *request) 358 + { 359 + __u32 *start_block; 360 + 361 + start_block = (__u32 *) request->cpdata; 362 + if (*start_block != device->blk_data.block_position) { 363 + /* Add the start offset of the file to get the real block. */ 364 + *start_block += device->bof; 365 + tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata); 366 + } 367 + } 368 + #endif 369 + 370 + /* 371 + * The done handler is called at device/channel end and wakes up the sleeping 372 + * process 373 + */ 374 + static int 375 + tape_3590_done(struct tape_device *device, struct tape_request *request) 376 + { 377 + struct tape_3590_med_sense *sense; 378 + 379 + DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); 380 + 381 + switch (request->op) { 382 + case TO_BSB: 383 + case TO_BSF: 384 + case TO_DSE: 385 + case TO_FSB: 386 + case TO_FSF: 387 + case TO_LBL: 388 + case TO_RFO: 389 + case TO_RBA: 390 + case TO_REW: 391 + case TO_WRI: 392 + case TO_WTM: 393 + case TO_BLOCK: 394 + case TO_LOAD: 395 + tape_med_state_set(device, MS_LOADED); 396 + break; 397 + case TO_RUN: 398 + tape_med_state_set(device, MS_UNLOADED); 399 + break; 400 + case TO_MSEN: 401 + sense = (struct tape_3590_med_sense *) request->cpdata; 402 + if (sense->masst == MSENSE_UNASSOCIATED) 403 + tape_med_state_set(device, MS_UNLOADED); 404 + if (sense->masst == MSENSE_ASSOCIATED_MOUNT) 405 + tape_med_state_set(device, MS_LOADED); 406 + break; 407 + case TO_RBI: /* RBI seems to succeed even without medium loaded. */ 408 + case TO_NOP: /* Same to NOP. */ 409 + case TO_READ_CONFIG: 410 + case TO_READ_ATTMSG: 411 + case TO_DIS: 412 + case TO_ASSIGN: 413 + case TO_UNASSIGN: 414 + break; 415 + case TO_SIZE: 416 + break; 417 + } 418 + return TAPE_IO_SUCCESS; 419 + } 420 + 421 + /* 422 + * This fuction is called, when error recovery was successfull 423 + */ 424 + static inline int 425 + tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request) 426 + { 427 + DBF_EVENT(3, "Error Recovery successfull for %s\n", 428 + tape_op_verbose[request->op]); 429 + return tape_3590_done(device, request); 430 + } 431 + 432 + /* 433 + * This fuction is called, when error recovery was not successfull 434 + */ 435 + static inline int 436 + tape_3590_erp_failed(struct tape_device *device, struct tape_request *request, 437 + struct irb *irb, int rc) 438 + { 439 + DBF_EVENT(3, "Error Recovery failed for %s\n", 440 + tape_op_verbose[request->op]); 441 + tape_dump_sense_dbf(device, request, irb); 442 + return rc; 443 + } 444 + 445 + /* 446 + * Error Recovery do retry 447 + */ 448 + static inline int 449 + tape_3590_erp_retry(struct tape_device *device, struct tape_request *request, 450 + struct irb *irb) 451 + { 452 + DBF_EVENT(2, "Retry: %s\n", tape_op_verbose[request->op]); 453 + tape_dump_sense_dbf(device, request, irb); 454 + return TAPE_IO_RETRY; 455 + } 456 + 457 + /* 458 + * Handle unsolicited interrupts 459 + */ 460 + static int 461 + tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb) 462 + { 463 + if (irb->scsw.dstat == DEV_STAT_CHN_END) 464 + /* Probably result of halt ssch */ 465 + return TAPE_IO_PENDING; 466 + else if (irb->scsw.dstat == 0x85) 467 + /* Device Ready -> check medium state */ 468 + tape_3590_schedule_work(device, TO_MSEN); 469 + else if (irb->scsw.dstat & DEV_STAT_ATTENTION) 470 + tape_3590_schedule_work(device, TO_READ_ATTMSG); 471 + else { 472 + DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); 473 + PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); 474 + tape_dump_sense(device, NULL, irb); 475 + } 476 + return TAPE_IO_SUCCESS; 477 + } 478 + 479 + /* 480 + * Basic Recovery routine 481 + */ 482 + static int 483 + tape_3590_erp_basic(struct tape_device *device, struct tape_request *request, 484 + struct irb *irb, int rc) 485 + { 486 + struct tape_3590_sense *sense; 487 + 488 + sense = (struct tape_3590_sense *) irb->ecw; 489 + 490 + switch (sense->bra) { 491 + case SENSE_BRA_PER: 492 + return tape_3590_erp_failed(device, request, irb, rc); 493 + case SENSE_BRA_CONT: 494 + return tape_3590_erp_succeded(device, request); 495 + case SENSE_BRA_RE: 496 + return tape_3590_erp_retry(device, request, irb); 497 + case SENSE_BRA_DRE: 498 + return tape_3590_erp_failed(device, request, irb, rc); 499 + default: 500 + PRINT_ERR("Unknown BRA %x - This should not happen!\n", 501 + sense->bra); 502 + BUG(); 503 + return TAPE_IO_STOP; 504 + } 505 + } 506 + 507 + /* 508 + * RDL: Read Device (buffered) log 509 + */ 510 + static int 511 + tape_3590_erp_read_buf_log(struct tape_device *device, 512 + struct tape_request *request, struct irb *irb) 513 + { 514 + /* 515 + * We just do the basic error recovery at the moment (retry). 516 + * Perhaps in the future, we read the log and dump it somewhere... 517 + */ 518 + return tape_3590_erp_basic(device, request, irb, -EIO); 519 + } 520 + 521 + /* 522 + * SWAP: Swap Devices 523 + */ 524 + static int 525 + tape_3590_erp_swap(struct tape_device *device, struct tape_request *request, 526 + struct irb *irb) 527 + { 528 + /* 529 + * This error recovery should swap the tapes 530 + * if the original has a problem. The operation 531 + * should proceed with the new tape... this 532 + * should probably be done in user space! 533 + */ 534 + PRINT_WARN("(%s): Swap Tape Device!\n", device->cdev->dev.bus_id); 535 + return tape_3590_erp_basic(device, request, irb, -EIO); 536 + } 537 + 538 + /* 539 + * LBY: Long Busy 540 + */ 541 + static int 542 + tape_3590_erp_long_busy(struct tape_device *device, 543 + struct tape_request *request, struct irb *irb) 544 + { 545 + /* FIXME: how about WAITING for a minute ? */ 546 + PRINT_WARN("(%s): Device is busy! Please wait a minute!\n", 547 + device->cdev->dev.bus_id); 548 + return tape_3590_erp_basic(device, request, irb, -EBUSY); 549 + } 550 + 551 + /* 552 + * SPI: Special Intercept 553 + */ 554 + static int 555 + tape_3590_erp_special_interrupt(struct tape_device *device, 556 + struct tape_request *request, struct irb *irb) 557 + { 558 + return tape_3590_erp_basic(device, request, irb, -EIO); 559 + } 560 + 561 + /* 562 + * RDA: Read Alternate 563 + */ 564 + static int 565 + tape_3590_erp_read_alternate(struct tape_device *device, 566 + struct tape_request *request, struct irb *irb) 567 + { 568 + struct tape_3590_disc_data *data; 569 + 570 + /* 571 + * The issued Read Backward or Read Previous command is not 572 + * supported by the device 573 + * The recovery action should be to issue another command: 574 + * Read Revious: if Read Backward is not supported 575 + * Read Backward: if Read Previous is not supported 576 + */ 577 + data = device->discdata; 578 + if (data->read_back_op == READ_PREVIOUS) { 579 + DBF_EVENT(2, "(%08x): No support for READ_PREVIOUS command\n", 580 + device->cdev_id); 581 + data->read_back_op = READ_BACKWARD; 582 + } else { 583 + DBF_EVENT(2, "(%08x): No support for READ_BACKWARD command\n", 584 + device->cdev_id); 585 + data->read_back_op = READ_PREVIOUS; 586 + } 587 + tape_3590_read_opposite(device, request); 588 + return tape_3590_erp_retry(device, request, irb); 589 + } 590 + 591 + /* 592 + * Error Recovery read opposite 593 + */ 594 + static int 595 + tape_3590_erp_read_opposite(struct tape_device *device, 596 + struct tape_request *request, struct irb *irb) 597 + { 598 + switch (request->op) { 599 + case TO_RFO: 600 + /* 601 + * We did read forward, but the data could not be read. 602 + * We will read backward and then skip forward again. 603 + */ 604 + tape_3590_read_opposite(device, request); 605 + return tape_3590_erp_retry(device, request, irb); 606 + case TO_RBA: 607 + /* We tried to read forward and backward, but hat no success */ 608 + return tape_3590_erp_failed(device, request, irb, -EIO); 609 + break; 610 + default: 611 + PRINT_WARN("read_opposite_recovery_called_with_op: %s\n", 612 + tape_op_verbose[request->op]); 613 + return tape_3590_erp_failed(device, request, irb, -EIO); 614 + } 615 + } 616 + 617 + /* 618 + * Print an MIM (Media Information Message) (message code f0) 619 + */ 620 + static void 621 + tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb) 622 + { 623 + struct tape_3590_sense *sense; 624 + 625 + sense = (struct tape_3590_sense *) irb->ecw; 626 + /* Exception Message */ 627 + switch (sense->fmt.f70.emc) { 628 + case 0x02: 629 + PRINT_WARN("(%s): Data degraded\n", device->cdev->dev.bus_id); 630 + break; 631 + case 0x03: 632 + PRINT_WARN("(%s): Data degraded in partion %i\n", 633 + device->cdev->dev.bus_id, sense->fmt.f70.mp); 634 + break; 635 + case 0x04: 636 + PRINT_WARN("(%s): Medium degraded\n", device->cdev->dev.bus_id); 637 + break; 638 + case 0x05: 639 + PRINT_WARN("(%s): Medium degraded in partition %i\n", 640 + device->cdev->dev.bus_id, sense->fmt.f70.mp); 641 + break; 642 + case 0x06: 643 + PRINT_WARN("(%s): Block 0 Error\n", device->cdev->dev.bus_id); 644 + break; 645 + case 0x07: 646 + PRINT_WARN("(%s): Medium Exception 0x%02x\n", 647 + device->cdev->dev.bus_id, sense->fmt.f70.md); 648 + break; 649 + default: 650 + PRINT_WARN("(%s): MIM ExMsg: 0x%02x\n", 651 + device->cdev->dev.bus_id, sense->fmt.f70.emc); 652 + break; 653 + } 654 + /* Service Message */ 655 + switch (sense->fmt.f70.smc) { 656 + case 0x02: 657 + PRINT_WARN("(%s): Reference Media maintenance procedure %i\n", 658 + device->cdev->dev.bus_id, sense->fmt.f70.md); 659 + break; 660 + default: 661 + PRINT_WARN("(%s): MIM ServiceMsg: 0x%02x\n", 662 + device->cdev->dev.bus_id, sense->fmt.f70.smc); 663 + break; 664 + } 665 + } 666 + 667 + /* 668 + * Print an I/O Subsystem Service Information Message (message code f1) 669 + */ 670 + static void 671 + tape_3590_print_io_sim_msg_f1(struct tape_device *device, struct irb *irb) 672 + { 673 + struct tape_3590_sense *sense; 674 + 675 + sense = (struct tape_3590_sense *) irb->ecw; 676 + /* Exception Message */ 677 + switch (sense->fmt.f71.emc) { 678 + case 0x01: 679 + PRINT_WARN("(%s): Effect of failure is unknown\n", 680 + device->cdev->dev.bus_id); 681 + break; 682 + case 0x02: 683 + PRINT_WARN("(%s): CU Exception - no performance impact\n", 684 + device->cdev->dev.bus_id); 685 + break; 686 + case 0x03: 687 + PRINT_WARN("(%s): CU Exception on channel interface 0x%02x\n", 688 + device->cdev->dev.bus_id, sense->fmt.f71.md[0]); 689 + break; 690 + case 0x04: 691 + PRINT_WARN("(%s): CU Exception on device path 0x%02x\n", 692 + device->cdev->dev.bus_id, sense->fmt.f71.md[0]); 693 + break; 694 + case 0x05: 695 + PRINT_WARN("(%s): CU Exception on library path 0x%02x\n", 696 + device->cdev->dev.bus_id, sense->fmt.f71.md[0]); 697 + break; 698 + case 0x06: 699 + PRINT_WARN("(%s): CU Exception on node 0x%02x\n", 700 + device->cdev->dev.bus_id, sense->fmt.f71.md[0]); 701 + break; 702 + case 0x07: 703 + PRINT_WARN("(%s): CU Exception on partition 0x%02x\n", 704 + device->cdev->dev.bus_id, sense->fmt.f71.md[0]); 705 + break; 706 + default: 707 + PRINT_WARN("(%s): SIM ExMsg: 0x%02x\n", 708 + device->cdev->dev.bus_id, sense->fmt.f71.emc); 709 + } 710 + /* Service Message */ 711 + switch (sense->fmt.f71.smc) { 712 + case 0x01: 713 + PRINT_WARN("(%s): Repair impact is unknown\n", 714 + device->cdev->dev.bus_id); 715 + break; 716 + case 0x02: 717 + PRINT_WARN("(%s): Repair will not impact cu performance\n", 718 + device->cdev->dev.bus_id); 719 + break; 720 + case 0x03: 721 + if (sense->fmt.f71.mdf == 0) 722 + PRINT_WARN("(%s): Repair will disable node " 723 + "0x%x on CU\n", 724 + device->cdev->dev.bus_id, 725 + sense->fmt.f71.md[1]); 726 + else 727 + PRINT_WARN("(%s): Repair will disable nodes " 728 + "(0x%x-0x%x) on CU\n", 729 + device->cdev->dev.bus_id, 730 + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); 731 + break; 732 + case 0x04: 733 + if (sense->fmt.f71.mdf == 0) 734 + PRINT_WARN("(%s): Repair will disable cannel path " 735 + "0x%x on CU\n", 736 + device->cdev->dev.bus_id, 737 + sense->fmt.f71.md[1]); 738 + else 739 + PRINT_WARN("(%s): Repair will disable cannel paths " 740 + "(0x%x-0x%x) on CU\n", 741 + device->cdev->dev.bus_id, 742 + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); 743 + break; 744 + case 0x05: 745 + if (sense->fmt.f71.mdf == 0) 746 + PRINT_WARN("(%s): Repair will disable device path " 747 + "0x%x on CU\n", 748 + device->cdev->dev.bus_id, 749 + sense->fmt.f71.md[1]); 750 + else 751 + PRINT_WARN("(%s): Repair will disable device paths " 752 + "(0x%x-0x%x) on CU\n", 753 + device->cdev->dev.bus_id, 754 + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); 755 + break; 756 + case 0x06: 757 + if (sense->fmt.f71.mdf == 0) 758 + PRINT_WARN("(%s): Repair will disable library path " 759 + "0x%x on CU\n", 760 + device->cdev->dev.bus_id, 761 + sense->fmt.f71.md[1]); 762 + else 763 + PRINT_WARN("(%s): Repair will disable library paths " 764 + "(0x%x-0x%x) on CU\n", 765 + device->cdev->dev.bus_id, 766 + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); 767 + break; 768 + case 0x07: 769 + PRINT_WARN("(%s): Repair will disable access to CU\n", 770 + device->cdev->dev.bus_id); 771 + break; 772 + default: 773 + PRINT_WARN("(%s): SIM ServiceMsg: 0x%02x\n", 774 + device->cdev->dev.bus_id, sense->fmt.f71.smc); 775 + } 776 + } 777 + 778 + /* 779 + * Print an Device Subsystem Service Information Message (message code f2) 780 + */ 781 + static void 782 + tape_3590_print_dev_sim_msg_f2(struct tape_device *device, struct irb *irb) 783 + { 784 + struct tape_3590_sense *sense; 785 + 786 + sense = (struct tape_3590_sense *) irb->ecw; 787 + /* Exception Message */ 788 + switch (sense->fmt.f71.emc) { 789 + case 0x01: 790 + PRINT_WARN("(%s): Effect of failure is unknown\n", 791 + device->cdev->dev.bus_id); 792 + break; 793 + case 0x02: 794 + PRINT_WARN("(%s): DV Exception - no performance impact\n", 795 + device->cdev->dev.bus_id); 796 + break; 797 + case 0x03: 798 + PRINT_WARN("(%s): DV Exception on channel interface 0x%02x\n", 799 + device->cdev->dev.bus_id, sense->fmt.f71.md[0]); 800 + break; 801 + case 0x04: 802 + PRINT_WARN("(%s): DV Exception on loader 0x%02x\n", 803 + device->cdev->dev.bus_id, sense->fmt.f71.md[0]); 804 + break; 805 + case 0x05: 806 + PRINT_WARN("(%s): DV Exception on message display 0x%02x\n", 807 + device->cdev->dev.bus_id, sense->fmt.f71.md[0]); 808 + break; 809 + case 0x06: 810 + PRINT_WARN("(%s): DV Exception in tape path\n", 811 + device->cdev->dev.bus_id); 812 + break; 813 + case 0x07: 814 + PRINT_WARN("(%s): DV Exception in drive\n", 815 + device->cdev->dev.bus_id); 816 + break; 817 + default: 818 + PRINT_WARN("(%s): DSIM ExMsg: 0x%02x\n", 819 + device->cdev->dev.bus_id, sense->fmt.f71.emc); 820 + } 821 + /* Service Message */ 822 + switch (sense->fmt.f71.smc) { 823 + case 0x01: 824 + PRINT_WARN("(%s): Repair impact is unknown\n", 825 + device->cdev->dev.bus_id); 826 + break; 827 + case 0x02: 828 + PRINT_WARN("(%s): Repair will not impact device performance\n", 829 + device->cdev->dev.bus_id); 830 + break; 831 + case 0x03: 832 + if (sense->fmt.f71.mdf == 0) 833 + PRINT_WARN("(%s): Repair will disable channel path " 834 + "0x%x on DV\n", 835 + device->cdev->dev.bus_id, 836 + sense->fmt.f71.md[1]); 837 + else 838 + PRINT_WARN("(%s): Repair will disable channel path " 839 + "(0x%x-0x%x) on DV\n", 840 + device->cdev->dev.bus_id, 841 + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); 842 + break; 843 + case 0x04: 844 + if (sense->fmt.f71.mdf == 0) 845 + PRINT_WARN("(%s): Repair will disable interface 0x%x " 846 + "on DV\n", 847 + device->cdev->dev.bus_id, 848 + sense->fmt.f71.md[1]); 849 + else 850 + PRINT_WARN("(%s): Repair will disable interfaces " 851 + "(0x%x-0x%x) on DV\n", 852 + device->cdev->dev.bus_id, 853 + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); 854 + break; 855 + case 0x05: 856 + if (sense->fmt.f71.mdf == 0) 857 + PRINT_WARN("(%s): Repair will disable loader 0x%x " 858 + "on DV\n", 859 + device->cdev->dev.bus_id, 860 + sense->fmt.f71.md[1]); 861 + else 862 + PRINT_WARN("(%s): Repair will disable loader " 863 + "(0x%x-0x%x) on DV\n", 864 + device->cdev->dev.bus_id, 865 + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); 866 + break; 867 + case 0x07: 868 + PRINT_WARN("(%s): Repair will disable access to DV\n", 869 + device->cdev->dev.bus_id); 870 + break; 871 + case 0x08: 872 + if (sense->fmt.f71.mdf == 0) 873 + PRINT_WARN("(%s): Repair will disable message " 874 + "display 0x%x on DV\n", 875 + device->cdev->dev.bus_id, 876 + sense->fmt.f71.md[1]); 877 + else 878 + PRINT_WARN("(%s): Repair will disable message " 879 + "displays (0x%x-0x%x) on DV\n", 880 + device->cdev->dev.bus_id, 881 + sense->fmt.f71.md[1], sense->fmt.f71.md[2]); 882 + break; 883 + case 0x09: 884 + PRINT_WARN("(%s): Clean DV\n", device->cdev->dev.bus_id); 885 + break; 886 + default: 887 + PRINT_WARN("(%s): DSIM ServiceMsg: 0x%02x\n", 888 + device->cdev->dev.bus_id, sense->fmt.f71.smc); 889 + } 890 + } 891 + 892 + /* 893 + * Print standard ERA Message 894 + */ 895 + static void 896 + tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) 897 + { 898 + struct tape_3590_sense *sense; 899 + 900 + sense = (struct tape_3590_sense *) irb->ecw; 901 + if (sense->mc == 0) 902 + return; 903 + if ((sense->mc > 0) && (sense->mc < TAPE_3590_MAX_MSG)) { 904 + if (tape_3590_msg[sense->mc] != NULL) 905 + PRINT_WARN("(%s): %s\n", device->cdev->dev.bus_id, 906 + tape_3590_msg[sense->mc]); 907 + else { 908 + PRINT_WARN("(%s): Message Code 0x%x\n", 909 + device->cdev->dev.bus_id, sense->mc); 910 + } 911 + return; 912 + } 913 + if (sense->mc == 0xf0) { 914 + /* Standard Media Information Message */ 915 + PRINT_WARN("(%s): MIM SEV=%i, MC=%02x, ES=%x/%x, " 916 + "RC=%02x-%04x-%02x\n", device->cdev->dev.bus_id, 917 + sense->fmt.f70.sev, sense->mc, 918 + sense->fmt.f70.emc, sense->fmt.f70.smc, 919 + sense->fmt.f70.refcode, sense->fmt.f70.mid, 920 + sense->fmt.f70.fid); 921 + tape_3590_print_mim_msg_f0(device, irb); 922 + return; 923 + } 924 + if (sense->mc == 0xf1) { 925 + /* Standard I/O Subsystem Service Information Message */ 926 + PRINT_WARN("(%s): IOSIM SEV=%i, DEVTYPE=3590/%02x, " 927 + "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", 928 + device->cdev->dev.bus_id, sense->fmt.f71.sev, 929 + device->cdev->id.dev_model, 930 + sense->mc, sense->fmt.f71.emc, 931 + sense->fmt.f71.smc, sense->fmt.f71.refcode1, 932 + sense->fmt.f71.refcode2, sense->fmt.f71.refcode3); 933 + tape_3590_print_io_sim_msg_f1(device, irb); 934 + return; 935 + } 936 + if (sense->mc == 0xf2) { 937 + /* Standard Device Service Information Message */ 938 + PRINT_WARN("(%s): DEVSIM SEV=%i, DEVTYPE=3590/%02x, " 939 + "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n", 940 + device->cdev->dev.bus_id, sense->fmt.f71.sev, 941 + device->cdev->id.dev_model, 942 + sense->mc, sense->fmt.f71.emc, 943 + sense->fmt.f71.smc, sense->fmt.f71.refcode1, 944 + sense->fmt.f71.refcode2, sense->fmt.f71.refcode3); 945 + tape_3590_print_dev_sim_msg_f2(device, irb); 946 + return; 947 + } 948 + if (sense->mc == 0xf3) { 949 + /* Standard Library Service Information Message */ 950 + return; 951 + } 952 + PRINT_WARN("(%s): Device Message(%x)\n", 953 + device->cdev->dev.bus_id, sense->mc); 954 + } 955 + 956 + /* 957 + * 3590 error Recovery routine: 958 + * If possible, it tries to recover from the error. If this is not possible, 959 + * inform the user about the problem. 960 + */ 961 + static int 962 + tape_3590_unit_check(struct tape_device *device, struct tape_request *request, 963 + struct irb *irb) 964 + { 965 + struct tape_3590_sense *sense; 966 + int rc; 967 + 968 + #ifdef CONFIG_S390_TAPE_BLOCK 969 + if (request->op == TO_BLOCK) { 970 + /* 971 + * Recovery for block device requests. Set the block_position 972 + * to something invalid and retry. 973 + */ 974 + device->blk_data.block_position = -1; 975 + if (request->retries-- <= 0) 976 + return tape_3590_erp_failed(device, request, irb, -EIO); 977 + else 978 + return tape_3590_erp_retry(device, request, irb); 979 + } 980 + #endif 981 + 982 + sense = (struct tape_3590_sense *) irb->ecw; 983 + 984 + /* 985 + * First check all RC-QRCs where we want to do something special 986 + * - "break": basic error recovery is done 987 + * - "goto out:": just print error message if available 988 + */ 989 + rc = -EIO; 990 + switch (sense->rc_rqc) { 991 + 992 + case 0x1110: 993 + tape_3590_print_era_msg(device, irb); 994 + return tape_3590_erp_read_buf_log(device, request, irb); 995 + 996 + case 0x2011: 997 + tape_3590_print_era_msg(device, irb); 998 + return tape_3590_erp_read_alternate(device, request, irb); 999 + 1000 + case 0x2230: 1001 + case 0x2231: 1002 + tape_3590_print_era_msg(device, irb); 1003 + return tape_3590_erp_special_interrupt(device, request, irb); 1004 + 1005 + case 0x3010: 1006 + DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n", 1007 + device->cdev_id); 1008 + return tape_3590_erp_basic(device, request, irb, -ENOSPC); 1009 + case 0x3012: 1010 + DBF_EVENT(2, "(%08x): Forward at End of Partition\n", 1011 + device->cdev_id); 1012 + return tape_3590_erp_basic(device, request, irb, -ENOSPC); 1013 + case 0x3020: 1014 + DBF_EVENT(2, "(%08x): End of Data Mark\n", device->cdev_id); 1015 + return tape_3590_erp_basic(device, request, irb, -ENOSPC); 1016 + 1017 + case 0x3122: 1018 + DBF_EVENT(2, "(%08x): Rewind Unload initiated\n", 1019 + device->cdev_id); 1020 + return tape_3590_erp_basic(device, request, irb, -EIO); 1021 + case 0x3123: 1022 + DBF_EVENT(2, "(%08x): Rewind Unload complete\n", 1023 + device->cdev_id); 1024 + tape_med_state_set(device, MS_UNLOADED); 1025 + return tape_3590_erp_basic(device, request, irb, 0); 1026 + 1027 + case 0x4010: 1028 + /* 1029 + * print additional msg since default msg 1030 + * "device intervention" is not very meaningfull 1031 + */ 1032 + PRINT_WARN("(%s): Tape operation when medium not loaded\n", 1033 + device->cdev->dev.bus_id); 1034 + tape_med_state_set(device, MS_UNLOADED); 1035 + return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); 1036 + case 0x4012: /* Device Long Busy */ 1037 + tape_3590_print_era_msg(device, irb); 1038 + return tape_3590_erp_long_busy(device, request, irb); 1039 + 1040 + case 0x5010: 1041 + if (sense->rac == 0xd0) { 1042 + /* Swap */ 1043 + tape_3590_print_era_msg(device, irb); 1044 + return tape_3590_erp_swap(device, request, irb); 1045 + } 1046 + if (sense->rac == 0x26) { 1047 + /* Read Opposite */ 1048 + tape_3590_print_era_msg(device, irb); 1049 + return tape_3590_erp_read_opposite(device, request, 1050 + irb); 1051 + } 1052 + return tape_3590_erp_basic(device, request, irb, -EIO); 1053 + case 0x5020: 1054 + case 0x5021: 1055 + case 0x5022: 1056 + case 0x5040: 1057 + case 0x5041: 1058 + case 0x5042: 1059 + tape_3590_print_era_msg(device, irb); 1060 + return tape_3590_erp_swap(device, request, irb); 1061 + 1062 + case 0x5110: 1063 + case 0x5111: 1064 + return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE); 1065 + 1066 + case 0x5120: 1067 + case 0x1120: 1068 + tape_med_state_set(device, MS_UNLOADED); 1069 + return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); 1070 + 1071 + case 0x6020: 1072 + PRINT_WARN("(%s): Cartridge of wrong type ?\n", 1073 + device->cdev->dev.bus_id); 1074 + return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE); 1075 + 1076 + case 0x8011: 1077 + PRINT_WARN("(%s): Another host has reserved the tape device\n", 1078 + device->cdev->dev.bus_id); 1079 + return tape_3590_erp_basic(device, request, irb, -EPERM); 1080 + case 0x8013: 1081 + PRINT_WARN("(%s): Another host has priviliged access to the " 1082 + "tape device\n", device->cdev->dev.bus_id); 1083 + PRINT_WARN("(%s): To solve the problem unload the current " 1084 + "cartridge!\n", device->cdev->dev.bus_id); 1085 + return tape_3590_erp_basic(device, request, irb, -EPERM); 1086 + default: 1087 + return tape_3590_erp_basic(device, request, irb, -EIO); 1088 + } 1089 + } 1090 + 1091 + /* 1092 + * 3590 interrupt handler: 1093 + */ 1094 + static int 1095 + tape_3590_irq(struct tape_device *device, struct tape_request *request, 1096 + struct irb *irb) 1097 + { 1098 + if (request == NULL) 1099 + return tape_3590_unsolicited_irq(device, irb); 1100 + 1101 + if ((irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) && 1102 + (irb->scsw.dstat & DEV_STAT_DEV_END) && (request->op == TO_WRI)) { 1103 + /* Write at end of volume */ 1104 + DBF_EVENT(2, "End of volume\n"); 1105 + return tape_3590_erp_failed(device, request, irb, -ENOSPC); 1106 + } 1107 + 1108 + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) 1109 + return tape_3590_unit_check(device, request, irb); 1110 + 1111 + if (irb->scsw.dstat & DEV_STAT_DEV_END) { 1112 + if (irb->scsw.dstat == DEV_STAT_UNIT_EXCEP) { 1113 + if (request->op == TO_FSB || request->op == TO_BSB) 1114 + request->rescnt++; 1115 + else 1116 + DBF_EVENT(5, "Unit Exception!\n"); 1117 + } 1118 + 1119 + return tape_3590_done(device, request); 1120 + } 1121 + 1122 + if (irb->scsw.dstat & DEV_STAT_CHN_END) { 1123 + DBF_EVENT(2, "cannel end\n"); 1124 + return TAPE_IO_PENDING; 1125 + } 1126 + 1127 + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { 1128 + DBF_EVENT(2, "Unit Attention when busy..\n"); 1129 + return TAPE_IO_PENDING; 1130 + } 1131 + 1132 + DBF_EVENT(6, "xunknownirq\n"); 1133 + PRINT_ERR("Unexpected interrupt.\n"); 1134 + PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]); 1135 + tape_dump_sense(device, request, irb); 1136 + return TAPE_IO_STOP; 1137 + } 1138 + 1139 + /* 1140 + * Setup device function 1141 + */ 1142 + static int 1143 + tape_3590_setup_device(struct tape_device *device) 1144 + { 1145 + int rc; 1146 + struct tape_3590_disc_data *data; 1147 + 1148 + DBF_EVENT(6, "3590 device setup\n"); 1149 + data = kmalloc(sizeof(struct tape_3590_disc_data), 1150 + GFP_KERNEL | GFP_DMA); 1151 + if (data == NULL) 1152 + return -ENOMEM; 1153 + data->read_back_op = READ_PREVIOUS; 1154 + device->discdata = data; 1155 + 1156 + if ((rc = tape_std_assign(device)) == 0) { 1157 + /* Try to find out if medium is loaded */ 1158 + if ((rc = tape_3590_sense_medium(device)) != 0) 1159 + DBF_LH(3, "3590 medium sense returned %d\n", rc); 1160 + } 1161 + 1162 + return rc; 1163 + } 1164 + 1165 + /* 1166 + * Cleanup device function 1167 + */ 1168 + static void 1169 + tape_3590_cleanup_device(struct tape_device *device) 1170 + { 1171 + tape_std_unassign(device); 1172 + 1173 + kfree(device->discdata); 1174 + device->discdata = NULL; 1175 + } 1176 + 1177 + /* 1178 + * List of 3590 magnetic tape commands. 1179 + */ 1180 + static tape_mtop_fn tape_3590_mtop[TAPE_NR_MTOPS] = { 1181 + [MTRESET] = tape_std_mtreset, 1182 + [MTFSF] = tape_std_mtfsf, 1183 + [MTBSF] = tape_std_mtbsf, 1184 + [MTFSR] = tape_std_mtfsr, 1185 + [MTBSR] = tape_std_mtbsr, 1186 + [MTWEOF] = tape_std_mtweof, 1187 + [MTREW] = tape_std_mtrew, 1188 + [MTOFFL] = tape_std_mtoffl, 1189 + [MTNOP] = tape_std_mtnop, 1190 + [MTRETEN] = tape_std_mtreten, 1191 + [MTBSFM] = tape_std_mtbsfm, 1192 + [MTFSFM] = tape_std_mtfsfm, 1193 + [MTEOM] = tape_std_mteom, 1194 + [MTERASE] = tape_std_mterase, 1195 + [MTRAS1] = NULL, 1196 + [MTRAS2] = NULL, 1197 + [MTRAS3] = NULL, 1198 + [MTSETBLK] = tape_std_mtsetblk, 1199 + [MTSETDENSITY] = NULL, 1200 + [MTSEEK] = tape_3590_mtseek, 1201 + [MTTELL] = tape_3590_mttell, 1202 + [MTSETDRVBUFFER] = NULL, 1203 + [MTFSS] = NULL, 1204 + [MTBSS] = NULL, 1205 + [MTWSM] = NULL, 1206 + [MTLOCK] = NULL, 1207 + [MTUNLOCK] = NULL, 1208 + [MTLOAD] = tape_std_mtload, 1209 + [MTUNLOAD] = tape_std_mtunload, 1210 + [MTCOMPRESSION] = tape_std_mtcompression, 1211 + [MTSETPART] = NULL, 1212 + [MTMKPART] = NULL 1213 + }; 1214 + 1215 + /* 1216 + * Tape discipline structure for 3590. 1217 + */ 1218 + static struct tape_discipline tape_discipline_3590 = { 1219 + .owner = THIS_MODULE, 1220 + .setup_device = tape_3590_setup_device, 1221 + .cleanup_device = tape_3590_cleanup_device, 1222 + .process_eov = tape_std_process_eov, 1223 + .irq = tape_3590_irq, 1224 + .read_block = tape_std_read_block, 1225 + .write_block = tape_std_write_block, 1226 + #ifdef CONFIG_S390_TAPE_BLOCK 1227 + .bread = tape_3590_bread, 1228 + .free_bread = tape_3590_free_bread, 1229 + .check_locate = tape_3590_check_locate, 1230 + #endif 1231 + .ioctl_fn = tape_3590_ioctl, 1232 + .mtop_array = tape_3590_mtop 1233 + }; 1234 + 1235 + static struct ccw_device_id tape_3590_ids[] = { 1236 + {CCW_DEVICE_DEVTYPE(0x3590, 0, 0x3590, 0), .driver_info = tape_3590}, 1237 + { /* end of list */ } 1238 + }; 1239 + 1240 + static int 1241 + tape_3590_online(struct ccw_device *cdev) 1242 + { 1243 + return tape_generic_online(cdev->dev.driver_data, 1244 + &tape_discipline_3590); 1245 + } 1246 + 1247 + static int 1248 + tape_3590_offline(struct ccw_device *cdev) 1249 + { 1250 + return tape_generic_offline(cdev->dev.driver_data); 1251 + } 1252 + 1253 + static struct ccw_driver tape_3590_driver = { 1254 + .name = "tape_3590", 1255 + .owner = THIS_MODULE, 1256 + .ids = tape_3590_ids, 1257 + .probe = tape_generic_probe, 1258 + .remove = tape_generic_remove, 1259 + .set_offline = tape_3590_offline, 1260 + .set_online = tape_3590_online, 1261 + }; 1262 + 1263 + /* 1264 + * Setup discipline structure. 1265 + */ 1266 + static int 1267 + tape_3590_init(void) 1268 + { 1269 + int rc; 1270 + 1271 + TAPE_DBF_AREA = debug_register("tape_3590", 2, 2, 4 * sizeof(long)); 1272 + debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view); 1273 + #ifdef DBF_LIKE_HELL 1274 + debug_set_level(TAPE_DBF_AREA, 6); 1275 + #endif 1276 + 1277 + DBF_EVENT(3, "3590 init\n"); 1278 + /* Register driver for 3590 tapes. */ 1279 + rc = ccw_driver_register(&tape_3590_driver); 1280 + if (rc) 1281 + DBF_EVENT(3, "3590 init failed\n"); 1282 + else 1283 + DBF_EVENT(3, "3590 registered\n"); 1284 + return rc; 1285 + } 1286 + 1287 + static void 1288 + tape_3590_exit(void) 1289 + { 1290 + ccw_driver_unregister(&tape_3590_driver); 1291 + 1292 + debug_unregister(TAPE_DBF_AREA); 1293 + } 1294 + 1295 + MODULE_DEVICE_TABLE(ccw, tape_3590_ids); 1296 + MODULE_AUTHOR("(C) 2001,2006 IBM Corporation"); 1297 + MODULE_DESCRIPTION("Linux on zSeries channel attached 3590 tape device driver"); 1298 + MODULE_LICENSE("GPL"); 1299 + 1300 + module_init(tape_3590_init); 1301 + module_exit(tape_3590_exit);
+124
drivers/s390/char/tape_3590.h
··· 1 + /* 2 + * drivers/s390/char/tape_3590.h 3 + * tape device discipline for 3590 tapes. 4 + * 5 + * Copyright (C) IBM Corp. 2001,2006 6 + * Author(s): Stefan Bader <shbader@de.ibm.com> 7 + * Michael Holzheu <holzheu@de.ibm.com> 8 + * Martin Schwidefsky <schwidefsky@de.ibm.com> 9 + */ 10 + 11 + #ifndef _TAPE_3590_H 12 + #define _TAPE_3590_H 13 + 14 + #define MEDIUM_SENSE 0xc2 15 + #define READ_PREVIOUS 0x0a 16 + #define MODE_SENSE 0xcf 17 + #define PERFORM_SS_FUNC 0x77 18 + #define READ_SS_DATA 0x3e 19 + 20 + #define PREP_RD_SS_DATA 0x18 21 + #define RD_ATTMSG 0x3 22 + 23 + #define SENSE_BRA_PER 0 24 + #define SENSE_BRA_CONT 1 25 + #define SENSE_BRA_RE 2 26 + #define SENSE_BRA_DRE 3 27 + 28 + #define SENSE_FMT_LIBRARY 0x23 29 + #define SENSE_FMT_UNSOLICITED 0x40 30 + #define SENSE_FMT_COMMAND_REJ 0x41 31 + #define SENSE_FMT_COMMAND_EXEC0 0x50 32 + #define SENSE_FMT_COMMAND_EXEC1 0x51 33 + #define SENSE_FMT_EVENT0 0x60 34 + #define SENSE_FMT_EVENT1 0x61 35 + #define SENSE_FMT_MIM 0x70 36 + #define SENSE_FMT_SIM 0x71 37 + 38 + #define MSENSE_UNASSOCIATED 0x00 39 + #define MSENSE_ASSOCIATED_MOUNT 0x01 40 + #define MSENSE_ASSOCIATED_UMOUNT 0x02 41 + 42 + #define TAPE_3590_MAX_MSG 0xb0 43 + 44 + /* Datatypes */ 45 + 46 + struct tape_3590_disc_data { 47 + unsigned char modeset_byte; 48 + int read_back_op; 49 + }; 50 + 51 + struct tape_3590_sense { 52 + 53 + unsigned int command_rej:1; 54 + unsigned int interv_req:1; 55 + unsigned int bus_out_check:1; 56 + unsigned int eq_check:1; 57 + unsigned int data_check:1; 58 + unsigned int overrun:1; 59 + unsigned int def_unit_check:1; 60 + unsigned int assgnd_elsew:1; 61 + 62 + unsigned int locate_fail:1; 63 + unsigned int inst_online:1; 64 + unsigned int reserved:1; 65 + unsigned int blk_seq_err:1; 66 + unsigned int begin_part:1; 67 + unsigned int wr_mode:1; 68 + unsigned int wr_prot:1; 69 + unsigned int not_cap:1; 70 + 71 + unsigned int bra:2; 72 + unsigned int lc:3; 73 + unsigned int vlf_active:1; 74 + unsigned int stm:1; 75 + unsigned int med_pos:1; 76 + 77 + unsigned int rac:8; 78 + 79 + unsigned int rc_rqc:16; 80 + 81 + unsigned int mc:8; 82 + 83 + unsigned int sense_fmt:8; 84 + 85 + union { 86 + struct { 87 + unsigned int emc:4; 88 + unsigned int smc:4; 89 + unsigned int sev:2; 90 + unsigned int reserved:6; 91 + unsigned int md:8; 92 + unsigned int refcode:8; 93 + unsigned int mid:16; 94 + unsigned int mp:16; 95 + unsigned char volid[6]; 96 + unsigned int fid:8; 97 + } f70; 98 + struct { 99 + unsigned int emc:4; 100 + unsigned int smc:4; 101 + unsigned int sev:2; 102 + unsigned int reserved1:5; 103 + unsigned int mdf:1; 104 + unsigned char md[3]; 105 + unsigned int simid:8; 106 + unsigned int uid:16; 107 + unsigned int refcode1:16; 108 + unsigned int refcode2:16; 109 + unsigned int refcode3:16; 110 + unsigned int reserved2:8; 111 + } f71; 112 + unsigned char data[14]; 113 + } fmt; 114 + unsigned char pad[10]; 115 + 116 + } __attribute__ ((packed)); 117 + 118 + struct tape_3590_med_sense { 119 + unsigned int macst:4; 120 + unsigned int masst:4; 121 + char pad[127]; 122 + } __attribute__ ((packed)); 123 + 124 + #endif /* _TAPE_3590_H */
+9 -3
drivers/s390/char/tape_std.h
··· 1 1 /* 2 - * drivers/s390/char/tape_34xx.h 2 + * drivers/s390/char/tape_std.h 3 3 * standard tape device functions for ibm tapes. 4 4 * 5 - * S390 and zSeries version 6 - * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation 5 + * Copyright (C) IBM Corp. 2001,2006 7 6 * Author(s): Carsten Otte <cotte@de.ibm.com> 8 7 * Tuan Ngo-Anh <ngoanh@de.ibm.com> 9 8 * Martin Schwidefsky <schwidefsky@de.ibm.com> ··· 147 148 void tape_std_error_recovery_do_retry(struct tape_device *); 148 149 void tape_std_error_recovery_read_opposite(struct tape_device *); 149 150 void tape_std_error_recovery_HWBUG(struct tape_device *, int condno); 151 + 152 + /* S390 tape types */ 153 + enum s390_tape_type { 154 + tape_3480, 155 + tape_3490, 156 + tape_3590, 157 + }; 150 158 151 159 #endif // _TAPE_STD_H