tape_3590.c
来自「linux 内核源代码」· C语言 代码 · 共 1,767 行 · 第 1/4 页
C
1,767 行
return; } PRINT_WARN("(%s): Device Message(%x)\n", device->cdev->dev.bus_id, sense->mc);}static int tape_3590_crypt_error(struct tape_device *device, struct tape_request *request, struct irb *irb){ u8 cu_rc, ekm_rc1; u16 ekm_rc2; u32 drv_rc; char *bus_id, *sense; sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; bus_id = device->cdev->dev.bus_id; cu_rc = sense[0]; drv_rc = *((u32*) &sense[5]) & 0xffffff; ekm_rc1 = sense[9]; ekm_rc2 = *((u16*) &sense[10]); if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) /* key not defined on EKM */ return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED); if ((cu_rc == 1) || (cu_rc == 2)) /* No connection to EKM */ return tape_3590_erp_basic(device, request, irb, -ENOTCONN); PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id); PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc, drv_rc, ekm_rc1, ekm_rc2); return tape_3590_erp_basic(device, request, irb, -ENOKEY);}/* * 3590 error Recovery routine: * If possible, it tries to recover from the error. If this is not possible, * inform the user about the problem. */static inttape_3590_unit_check(struct tape_device *device, struct tape_request *request, struct irb *irb){ struct tape_3590_sense *sense; int rc;#ifdef CONFIG_S390_TAPE_BLOCK if (request->op == TO_BLOCK) { /* * Recovery for block device requests. Set the block_position * to something invalid and retry. */ device->blk_data.block_position = -1; if (request->retries-- <= 0) return tape_3590_erp_failed(device, request, irb, -EIO); else return tape_3590_erp_retry(device, request, irb); }#endif sense = (struct tape_3590_sense *) irb->ecw; DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc); /* * First check all RC-QRCs where we want to do something special * - "break": basic error recovery is done * - "goto out:": just print error message if available */ rc = -EIO; switch (sense->rc_rqc) { case 0x1110: tape_3590_print_era_msg(device, irb); return tape_3590_erp_read_buf_log(device, request, irb); case 0x2011: tape_3590_print_era_msg(device, irb); return tape_3590_erp_read_alternate(device, request, irb); case 0x2230: case 0x2231: tape_3590_print_era_msg(device, irb); return tape_3590_erp_special_interrupt(device, request, irb); case 0x2240: return tape_3590_crypt_error(device, request, irb); case 0x3010: DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n", device->cdev_id); return tape_3590_erp_basic(device, request, irb, -ENOSPC); case 0x3012: DBF_EVENT(2, "(%08x): Forward at End of Partition\n", device->cdev_id); return tape_3590_erp_basic(device, request, irb, -ENOSPC); case 0x3020: DBF_EVENT(2, "(%08x): End of Data Mark\n", device->cdev_id); return tape_3590_erp_basic(device, request, irb, -ENOSPC); case 0x3122: DBF_EVENT(2, "(%08x): Rewind Unload initiated\n", device->cdev_id); return tape_3590_erp_basic(device, request, irb, -EIO); case 0x3123: DBF_EVENT(2, "(%08x): Rewind Unload complete\n", device->cdev_id); tape_med_state_set(device, MS_UNLOADED); tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, 0); case 0x4010: /* * print additional msg since default msg * "device intervention" is not very meaningfull */ PRINT_WARN("(%s): Tape operation when medium not loaded\n", device->cdev->dev.bus_id); tape_med_state_set(device, MS_UNLOADED); tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); case 0x4012: /* Device Long Busy */ /* XXX: Also use long busy handling here? */ DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id); tape_3590_print_era_msg(device, irb); return tape_3590_erp_basic(device, request, irb, -EBUSY); case 0x4014: DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id); return tape_3590_erp_long_busy(device, request, irb); case 0x5010: if (sense->rac == 0xd0) { /* Swap */ tape_3590_print_era_msg(device, irb); return tape_3590_erp_swap(device, request, irb); } if (sense->rac == 0x26) { /* Read Opposite */ tape_3590_print_era_msg(device, irb); return tape_3590_erp_read_opposite(device, request, irb); } return tape_3590_erp_basic(device, request, irb, -EIO); case 0x5020: case 0x5021: case 0x5022: case 0x5040: case 0x5041: case 0x5042: tape_3590_print_era_msg(device, irb); return tape_3590_erp_swap(device, request, irb); case 0x5110: case 0x5111: return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE); case 0x5120: case 0x1120: tape_med_state_set(device, MS_UNLOADED); tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); case 0x6020: PRINT_WARN("(%s): Cartridge of wrong type ?\n", device->cdev->dev.bus_id); return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE); case 0x8011: PRINT_WARN("(%s): Another host has reserved the tape device\n", device->cdev->dev.bus_id); return tape_3590_erp_basic(device, request, irb, -EPERM); case 0x8013: PRINT_WARN("(%s): Another host has priviliged access to the " "tape device\n", device->cdev->dev.bus_id); PRINT_WARN("(%s): To solve the problem unload the current " "cartridge!\n", device->cdev->dev.bus_id); return tape_3590_erp_basic(device, request, irb, -EPERM); default: return tape_3590_erp_basic(device, request, irb, -EIO); }}/* * 3590 interrupt handler: */static inttape_3590_irq(struct tape_device *device, struct tape_request *request, struct irb *irb){ if (request == NULL) return tape_3590_unsolicited_irq(device, irb); if ((irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) && (irb->scsw.dstat & DEV_STAT_DEV_END) && (request->op == TO_WRI)) { /* Write at end of volume */ DBF_EVENT(2, "End of volume\n"); return tape_3590_erp_failed(device, request, irb, -ENOSPC); } if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) return tape_3590_unit_check(device, request, irb); if (irb->scsw.dstat & DEV_STAT_DEV_END) { if (irb->scsw.dstat == DEV_STAT_UNIT_EXCEP) { if (request->op == TO_FSB || request->op == TO_BSB) request->rescnt++; else DBF_EVENT(5, "Unit Exception!\n"); } return tape_3590_done(device, request); } if (irb->scsw.dstat & DEV_STAT_CHN_END) { DBF_EVENT(2, "cannel end\n"); return TAPE_IO_PENDING; } if (irb->scsw.dstat & DEV_STAT_ATTENTION) { DBF_EVENT(2, "Unit Attention when busy..\n"); return TAPE_IO_PENDING; } DBF_EVENT(6, "xunknownirq\n"); PRINT_ERR("Unexpected interrupt.\n"); PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]); tape_dump_sense(device, request, irb); return TAPE_IO_STOP;}static int tape_3590_read_dev_chars(struct tape_device *device, struct tape_3590_rdc_data *rdc_data){ int rc; struct tape_request *request; request = tape_alloc_request(1, sizeof(*rdc_data)); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_RDC; tape_ccw_end(request->cpaddr, CCW_CMD_RDC, sizeof(*rdc_data), request->cpdata); rc = tape_do_io(device, request); if (rc == 0) memcpy(rdc_data, request->cpdata, sizeof(*rdc_data)); tape_free_request(request); return rc;}/* * Setup device function */static inttape_3590_setup_device(struct tape_device *device){ int rc; struct tape_3590_disc_data *data; struct tape_3590_rdc_data *rdc_data; DBF_EVENT(6, "3590 device setup\n"); data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA); if (data == NULL) return -ENOMEM; data->read_back_op = READ_PREVIOUS; device->discdata = data; rdc_data = kmalloc(sizeof(*rdc_data), GFP_KERNEL | GFP_DMA); if (!rdc_data) { rc = -ENOMEM; goto fail_kmalloc; } rc = tape_3590_read_dev_chars(device, rdc_data); if (rc) { DBF_LH(3, "Read device characteristics failed!\n"); goto fail_kmalloc; } rc = tape_std_assign(device); if (rc) goto fail_rdc_data; if (rdc_data->data[31] == 0x13) { PRINT_INFO("Device has crypto support\n"); data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK; tape_3592_disable_crypt(device); } else { DBF_EVENT(6, "Device has NO crypto support\n"); } /* Try to find out if medium is loaded */ rc = tape_3590_sense_medium(device); if (rc) { DBF_LH(3, "3590 medium sense returned %d\n", rc); goto fail_rdc_data; } return 0;fail_rdc_data: kfree(rdc_data);fail_kmalloc: kfree(data); return rc;}/* * Cleanup device function */static voidtape_3590_cleanup_device(struct tape_device *device){ flush_scheduled_work(); tape_std_unassign(device); kfree(device->discdata); device->discdata = NULL;}/* * List of 3590 magnetic tape commands. */static tape_mtop_fn tape_3590_mtop[TAPE_NR_MTOPS] = { [MTRESET] = tape_std_mtreset, [MTFSF] = tape_std_mtfsf, [MTBSF] = tape_std_mtbsf, [MTFSR] = tape_std_mtfsr, [MTBSR] = tape_std_mtbsr, [MTWEOF] = tape_std_mtweof, [MTREW] = tape_std_mtrew, [MTOFFL] = tape_std_mtoffl, [MTNOP] = tape_std_mtnop, [MTRETEN] = tape_std_mtreten, [MTBSFM] = tape_std_mtbsfm, [MTFSFM] = tape_std_mtfsfm, [MTEOM] = tape_std_mteom, [MTERASE] = tape_std_mterase, [MTRAS1] = NULL, [MTRAS2] = NULL, [MTRAS3] = NULL, [MTSETBLK] = tape_std_mtsetblk, [MTSETDENSITY] = NULL, [MTSEEK] = tape_3590_mtseek, [MTTELL] = tape_3590_mttell, [MTSETDRVBUFFER] = NULL, [MTFSS] = NULL, [MTBSS] = NULL, [MTWSM] = NULL, [MTLOCK] = NULL, [MTUNLOCK] = NULL, [MTLOAD] = tape_std_mtload, [MTUNLOAD] = tape_std_mtunload, [MTCOMPRESSION] = tape_std_mtcompression, [MTSETPART] = NULL, [MTMKPART] = NULL};/* * Tape discipline structure for 3590. */static struct tape_discipline tape_discipline_3590 = { .owner = THIS_MODULE, .setup_device = tape_3590_setup_device, .cleanup_device = tape_3590_cleanup_device, .process_eov = tape_std_process_eov, .irq = tape_3590_irq, .read_block = tape_std_read_block, .write_block = tape_std_write_block,#ifdef CONFIG_S390_TAPE_BLOCK .bread = tape_3590_bread, .free_bread = tape_3590_free_bread, .check_locate = tape_3590_check_locate,#endif .ioctl_fn = tape_3590_ioctl, .mtop_array = tape_3590_mtop};static struct ccw_device_id tape_3590_ids[] = { {CCW_DEVICE_DEVTYPE(0x3590, 0, 0x3590, 0), .driver_info = tape_3590}, {CCW_DEVICE_DEVTYPE(0x3592, 0, 0x3592, 0), .driver_info = tape_3592}, { /* end of list */ }};static inttape_3590_online(struct ccw_device *cdev){ return tape_generic_online(cdev->dev.driver_data, &tape_discipline_3590);}static inttape_3590_offline(struct ccw_device *cdev){ return tape_generic_offline(cdev->dev.driver_data);}static struct ccw_driver tape_3590_driver = { .name = "tape_3590", .owner = THIS_MODULE, .ids = tape_3590_ids, .probe = tape_generic_probe, .remove = tape_generic_remove, .set_offline = tape_3590_offline, .set_online = tape_3590_online,};/* * Setup discipline structure. */static inttape_3590_init(void){ int rc; TAPE_DBF_AREA = debug_register("tape_3590", 2, 2, 4 * sizeof(long)); debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view);#ifdef DBF_LIKE_HELL debug_set_level(TAPE_DBF_AREA, 6);#endif DBF_EVENT(3, "3590 init\n"); /* Register driver for 3590 tapes. */ rc = ccw_driver_register(&tape_3590_driver); if (rc) DBF_EVENT(3, "3590 init failed\n"); else DBF_EVENT(3, "3590 registered\n"); return rc;}static voidtape_3590_exit(void){ ccw_driver_unregister(&tape_3590_driver); debug_unregister(TAPE_DBF_AREA);}MODULE_DEVICE_TABLE(ccw, tape_3590_ids);MODULE_AUTHOR("(C) 2001,2006 IBM Corporation");MODULE_DESCRIPTION("Linux on zSeries channel attached 3590 tape device driver");MODULE_LICENSE("GPL");module_init(tape_3590_init);module_exit(tape_3590_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?