tape_3590.c
来自「linux 内核源代码」· C语言 代码 · 共 1,767 行 · 第 1/4 页
C
1,767 行
case TAPE390_CRYPT_SET: return tape_3592_ioctl_crypt_set(device, arg); case TAPE390_CRYPT_QUERY: return tape_3592_ioctl_crypt_query(device, arg); default: return -EINVAL; /* no additional ioctls */ }}/* * SENSE Medium: Get Sense data about medium state */static inttape_3590_sense_medium(struct tape_device *device){ struct tape_request *request; request = tape_alloc_request(1, 128); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_MSEN; tape_ccw_end(request->cpaddr, MEDIUM_SENSE, 128, request->cpdata); return tape_do_io_free(device, request);}/* * MTTELL: Tell block. Return the number of block relative to current file. */static inttape_3590_mttell(struct tape_device *device, int mt_count){ __u64 block_id; int rc; rc = tape_std_read_block_id(device, &block_id); if (rc) return rc; return block_id >> 32;}/* * MTSEEK: seek to the specified block. */static inttape_3590_mtseek(struct tape_device *device, int count){ struct tape_request *request; DBF_EVENT(6, "xsee id: %x\n", count); request = tape_alloc_request(3, 4); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_LBL; tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); *(__u32 *) request->cpdata = count; tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata); tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL); return tape_do_io_free(device, request);}/* * Read Opposite Error Recovery Function: * Used, when Read Forward does not work */static voidtape_3590_read_opposite(struct tape_device *device, struct tape_request *request){ struct tape_3590_disc_data *data; /* * We have allocated 4 ccws in tape_std_read, so we can now * transform the request to a read backward, followed by a * forward space block. */ request->op = TO_RBA; tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); data = device->discdata; tape_ccw_cc_idal(request->cpaddr + 1, data->read_back_op, device->char_data.idal_buf); tape_ccw_cc(request->cpaddr + 2, FORSPACEBLOCK, 0, NULL); tape_ccw_end(request->cpaddr + 3, NOP, 0, NULL); DBF_EVENT(6, "xrop ccwg\n");}/* * Read Attention Msg * This should be done after an interrupt with attention bit (0x80) * in device state. * * After a "read attention message" request there are two possible * results: * * 1. A unit check is presented, when attention sense is present (e.g. when * a medium has been unloaded). The attention sense comes then * together with the unit check. The recovery action is either "retry" * (in case there is an attention message pending) or "permanent error". * * 2. The attention msg is written to the "read subsystem data" buffer. * In this case we probably should print it to the console. */static inttape_3590_read_attmsg(struct tape_device *device){ struct tape_request *request; char *buf; request = tape_alloc_request(3, 4096); if (IS_ERR(request)) return PTR_ERR(request); request->op = TO_READ_ATTMSG; buf = request->cpdata; buf[0] = PREP_RD_SS_DATA; buf[6] = RD_ATTMSG; /* read att msg */ tape_ccw_cc(request->cpaddr, PERFORM_SS_FUNC, 12, buf); tape_ccw_cc(request->cpaddr + 1, READ_SS_DATA, 4096 - 12, buf + 12); tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL); return tape_do_io_free(device, request);}/* * These functions are used to schedule follow-up actions from within an * interrupt context (like unsolicited interrupts). */struct work_handler_data { struct tape_device *device; enum tape_op op; struct work_struct work;};static voidtape_3590_work_handler(struct work_struct *work){ struct work_handler_data *p = container_of(work, struct work_handler_data, work); switch (p->op) { case TO_MSEN: tape_3590_sense_medium(p->device); break; case TO_READ_ATTMSG: tape_3590_read_attmsg(p->device); break; case TO_CRYPT_ON: tape_3592_enable_crypt(p->device); break; case TO_CRYPT_OFF: tape_3592_disable_crypt(p->device); break; default: DBF_EVENT(3, "T3590: work handler undefined for " "operation 0x%02x\n", p->op); } tape_put_device(p->device); kfree(p);}static inttape_3590_schedule_work(struct tape_device *device, enum tape_op op){ struct work_handler_data *p; if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL) return -ENOMEM; INIT_WORK(&p->work, tape_3590_work_handler); p->device = tape_get_device_reference(device); p->op = op; schedule_work(&p->work); return 0;}#ifdef CONFIG_S390_TAPE_BLOCK/* * Tape Block READ */static struct tape_request *tape_3590_bread(struct tape_device *device, struct request *req){ struct tape_request *request; struct ccw1 *ccw; int count = 0, start_block; unsigned off; char *dst; struct bio_vec *bv; struct req_iterator iter; DBF_EVENT(6, "xBREDid:"); start_block = req->sector >> TAPEBLOCK_HSEC_S2B; DBF_EVENT(6, "start_block = %i\n", start_block); rq_for_each_segment(bv, req, iter) count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9); request = tape_alloc_request(2 + count + 1, 4); if (IS_ERR(request)) return request; request->op = TO_BLOCK; *(__u32 *) request->cpdata = start_block; ccw = request->cpaddr; ccw = tape_ccw_cc(ccw, MODE_SET_DB, 1, device->modeset_byte); /* * We always setup a nop after the mode set ccw. This slot is * used in tape_std_check_locate to insert a locate ccw if the * current tape position doesn't match the start block to be read. */ ccw = tape_ccw_cc(ccw, NOP, 0, NULL); rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) { ccw->flags = CCW_FLAG_CC; ccw->cmd_code = READ_FORWARD; ccw->count = TAPEBLOCK_HSEC_SIZE; set_normalized_cda(ccw, (void *) __pa(dst)); ccw++; dst += TAPEBLOCK_HSEC_SIZE; } if (off > bv->bv_len) BUG(); } ccw = tape_ccw_end(ccw, NOP, 0, NULL); DBF_EVENT(6, "xBREDccwg\n"); return request;}static voidtape_3590_free_bread(struct tape_request *request){ struct ccw1 *ccw; /* Last ccw is a nop and doesn't need clear_normalized_cda */ for (ccw = request->cpaddr; ccw->flags & CCW_FLAG_CC; ccw++) if (ccw->cmd_code == READ_FORWARD) clear_normalized_cda(ccw); tape_free_request(request);}/* * check_locate is called just before the tape request is passed to * the common io layer for execution. It has to check the current * tape position and insert a locate ccw if it doesn't match the * start block for the request. */static voidtape_3590_check_locate(struct tape_device *device, struct tape_request *request){ __u32 *start_block; start_block = (__u32 *) request->cpdata; if (*start_block != device->blk_data.block_position) { /* Add the start offset of the file to get the real block. */ *start_block += device->bof; tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata); }}#endifstatic void tape_3590_med_state_set(struct tape_device *device, struct tape_3590_med_sense *sense){ struct tape390_crypt_info *c_info; c_info = &TAPE_3590_CRYPT_INFO(device); DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst); switch (sense->macst) { case 0x04: case 0x05: case 0x06: tape_med_state_set(device, MS_UNLOADED); TAPE_3590_CRYPT_INFO(device).medium_status = 0; return; case 0x08: case 0x09: tape_med_state_set(device, MS_LOADED); break; default: tape_med_state_set(device, MS_UNKNOWN); return; } c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK; if (sense->flags & MSENSE_CRYPT_MASK) { PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK; } else { DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags); c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK; }}/* * The done handler is called at device/channel end and wakes up the sleeping * process */static inttape_3590_done(struct tape_device *device, struct tape_request *request){ struct tape_3590_disc_data *disc_data; DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); disc_data = device->discdata; switch (request->op) { case TO_BSB: case TO_BSF: case TO_DSE: case TO_FSB: case TO_FSF: case TO_LBL: case TO_RFO: case TO_RBA: case TO_REW: case TO_WRI: case TO_WTM: case TO_BLOCK: case TO_LOAD: tape_med_state_set(device, MS_LOADED); break; case TO_RUN: tape_med_state_set(device, MS_UNLOADED); tape_3590_schedule_work(device, TO_CRYPT_OFF); break; case TO_MSEN: tape_3590_med_state_set(device, request->cpdata); break; case TO_CRYPT_ON: TAPE_3590_CRYPT_INFO(device).status |= TAPE390_CRYPT_ON_MASK; *(device->modeset_byte) |= 0x03; break; case TO_CRYPT_OFF: TAPE_3590_CRYPT_INFO(device).status &= ~TAPE390_CRYPT_ON_MASK; *(device->modeset_byte) &= ~0x03; break; case TO_RBI: /* RBI seems to succeed even without medium loaded. */ case TO_NOP: /* Same to NOP. */ case TO_READ_CONFIG: case TO_READ_ATTMSG: case TO_DIS: case TO_ASSIGN: case TO_UNASSIGN: case TO_SIZE: case TO_KEKL_SET: case TO_KEKL_QUERY: case TO_RDC: break; } return TAPE_IO_SUCCESS;}/* * This fuction is called, when error recovery was successfull */static inline inttape_3590_erp_succeded(struct tape_device *device, struct tape_request *request){ DBF_EVENT(3, "Error Recovery successfull for %s\n", tape_op_verbose[request->op]); return tape_3590_done(device, request);}/* * This fuction is called, when error recovery was not successfull */static inline inttape_3590_erp_failed(struct tape_device *device, struct tape_request *request, struct irb *irb, int rc){ DBF_EVENT(3, "Error Recovery failed for %s\n", tape_op_verbose[request->op]); tape_dump_sense_dbf(device, request, irb); return rc;}/* * Error Recovery do retry */static inline inttape_3590_erp_retry(struct tape_device *device, struct tape_request *request, struct irb *irb){ DBF_EVENT(2, "Retry: %s\n", tape_op_verbose[request->op]); tape_dump_sense_dbf(device, request, irb); return TAPE_IO_RETRY;}/* * Handle unsolicited interrupts */static inttape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb){ if (irb->scsw.dstat == DEV_STAT_CHN_END) /* Probably result of halt ssch */ return TAPE_IO_PENDING; else if (irb->scsw.dstat == 0x85) /* Device Ready */ DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id); else if (irb->scsw.dstat & DEV_STAT_ATTENTION) { tape_3590_schedule_work(device, TO_READ_ATTMSG); } else { DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); PRINT_WARN("Unsolicited IRQ (Device End) caught.\n"); tape_dump_sense(device, NULL, irb); } /* check medium state */ tape_3590_schedule_work(device, TO_MSEN); return TAPE_IO_SUCCESS;}/* * Basic Recovery routine */static inttape_3590_erp_basic(struct tape_device *device, struct tape_request *request, struct irb *irb, int rc){ struct tape_3590_sense *sense; sense = (struct tape_3590_sense *) irb->ecw; switch (sense->bra) { case SENSE_BRA_PER: return tape_3590_erp_failed(device, request, irb, rc); case SENSE_BRA_CONT: return tape_3590_erp_succeded(device, request); case SENSE_BRA_RE: return tape_3590_erp_retry(device, request, irb); case SENSE_BRA_DRE: return tape_3590_erp_failed(device, request, irb, rc); default: PRINT_ERR("Unknown BRA %x - This should not happen!\n", sense->bra); BUG(); return TAPE_IO_STOP; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?