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