tape_core.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,236 行 · 第 1/3 页
C
1,236 行
return -ENODEV; } /* Increase use count of device for the added request. */ request->device = tape_get_device_reference(device); if (list_empty(&device->req_queue)) { /* No other requests are on the queue. Start this one. */#ifdef CONFIG_S390_TAPE_BLOCK if (request->op == TO_BLOCK) device->discipline->check_locate(device, request);#endif rc = ccw_device_start(device->cdev, request->cpaddr, (unsigned long) request, 0x00, request->options); if (rc) { DBF_EVENT(1, "tape: DOIO failed with rc = %i\n", rc); return rc; } DBF_LH(5, "Request %p added for execution.\n", request); list_add(&request->list, &device->req_queue); request->status = TAPE_REQUEST_IN_IO; } else { DBF_LH(5, "Request %p add to queue.\n", request); list_add_tail(&request->list, &device->req_queue); request->status = TAPE_REQUEST_QUEUED; } return 0;}/* * Add the request to the request queue, try to start it if the * tape is idle. Return without waiting for end of i/o. */inttape_do_io_async(struct tape_device *device, struct tape_request *request){ int rc; DBF_LH(6, "tape_do_io_async(%p, %p)\n", device, request); spin_lock_irq(get_ccwdev_lock(device->cdev)); /* Add request to request queue and try to start it. */ rc = __tape_do_io(device, request); spin_unlock_irq(get_ccwdev_lock(device->cdev)); return rc;}/* * tape_do_io/__tape_wake_up * Add the request to the request queue, try to start it if the * tape is idle and wait uninterruptible for its completion. */static void__tape_wake_up(struct tape_request *request, void *data){ request->callback = NULL; wake_up((wait_queue_head_t *) data);}inttape_do_io(struct tape_device *device, struct tape_request *request){ wait_queue_head_t wq; int rc; init_waitqueue_head(&wq); spin_lock_irq(get_ccwdev_lock(device->cdev)); /* Setup callback */ request->callback = __tape_wake_up; request->callback_data = &wq; /* Add request to request queue and try to start it. */ rc = __tape_do_io(device, request); spin_unlock_irq(get_ccwdev_lock(device->cdev)); if (rc) return rc; /* Request added to the queue. Wait for its completion. */ wait_event(wq, (request->callback == NULL)); /* Get rc from request */ return request->rc;}/* * tape_do_io_interruptible/__tape_wake_up_interruptible * Add the request to the request queue, try to start it if the * tape is idle and wait uninterruptible for its completion. */static void__tape_wake_up_interruptible(struct tape_request *request, void *data){ request->callback = NULL; wake_up_interruptible((wait_queue_head_t *) data);}inttape_do_io_interruptible(struct tape_device *device, struct tape_request *request){ wait_queue_head_t wq; int rc; init_waitqueue_head(&wq); spin_lock_irq(get_ccwdev_lock(device->cdev)); /* Setup callback */ request->callback = __tape_wake_up_interruptible; request->callback_data = &wq; rc = __tape_do_io(device, request); spin_unlock_irq(get_ccwdev_lock(device->cdev)); if (rc) return rc; /* Request added to the queue. Wait for its completion. */ rc = wait_event_interruptible(wq, (request->callback == NULL)); if (rc != -ERESTARTSYS) /* Request finished normally. */ return request->rc; /* Interrupted by a signal. We have to stop the current request. */ spin_lock_irq(get_ccwdev_lock(device->cdev)); rc = __tape_halt_io(device, request); if (rc == 0) { DBF_EVENT(3, "IO stopped on %08x\n", device->cdev_id); rc = -ERESTARTSYS; } spin_unlock_irq(get_ccwdev_lock(device->cdev)); return rc;}/* * Handle requests that return an i/o error in the irb. */static inline voidtape_handle_killed_request( struct tape_device *device, struct tape_request *request){ if(request != NULL) { /* Set ending status. FIXME: Should the request be retried? */ request->rc = -EIO; request->status = TAPE_REQUEST_DONE; __tape_remove_request(device, request); } else { __tape_do_io_list(device); }}/* * Tape interrupt routine, called from the ccw_device layer */static void__tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb){ struct tape_device *device; struct tape_request *request; int final; int rc; device = (struct tape_device *) cdev->dev.driver_data; if (device == NULL) { PRINT_ERR("could not get device structure for %s " "in interrupt\n", cdev->dev.bus_id); return; } request = (struct tape_request *) intparm; DBF_LH(6, "__tape_do_irq(device=%p, request=%p)\n", device, request); /* On special conditions irb is an error pointer */ if (IS_ERR(irb)) { switch (PTR_ERR(irb)) { case -ETIMEDOUT: PRINT_WARN("(%s): Request timed out\n", cdev->dev.bus_id); case -EIO: tape_handle_killed_request(device, request); break; default: PRINT_ERR("(%s): Unexpected i/o error %li\n", cdev->dev.bus_id, PTR_ERR(irb)); } return; } /* May be an unsolicited irq */ if(request != NULL) request->rescnt = irb->scsw.count; if (irb->scsw.dstat != 0x0c) { /* Set the 'ONLINE' flag depending on sense byte 1 */ if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE) device->tape_generic_status |= GMT_ONLINE(~0); else device->tape_generic_status &= ~GMT_ONLINE(~0); /* * Any request that does not come back with channel end * and device end is unusual. Log the sense data. */ DBF_EVENT(3,"-- Tape Interrupthandler --\n"); tape_dump_sense_dbf(device, request, irb); } else { /* Upon normal completion the device _is_ online */ device->tape_generic_status |= GMT_ONLINE(~0); } if (device->tape_state == TS_NOT_OPER) { DBF_EVENT(6, "tape:device is not operational\n"); return; } /* * Request that were canceled still come back with an interrupt. * To detect these request the state will be set to TAPE_REQUEST_DONE. */ if(request != NULL && request->status == TAPE_REQUEST_DONE) { __tape_remove_request(device, request); return; } rc = device->discipline->irq(device, request, irb); /* * rc < 0 : request finished unsuccessfully. * rc == TAPE_IO_SUCCESS: request finished successfully. * rc == TAPE_IO_PENDING: request is still running. Ignore rc. * rc == TAPE_IO_RETRY: request finished but needs another go. * rc == TAPE_IO_STOP: request needs to get terminated. */ final = 0; switch (rc) { case TAPE_IO_SUCCESS: /* Upon normal completion the device _is_ online */ device->tape_generic_status |= GMT_ONLINE(~0); final = 1; break; case TAPE_IO_PENDING: break; case TAPE_IO_RETRY:#ifdef CONFIG_S390_TAPE_BLOCK if (request->op == TO_BLOCK) device->discipline->check_locate(device, request);#endif rc = ccw_device_start(cdev, request->cpaddr, (unsigned long) request, 0x00, request->options); if (rc) { DBF_EVENT(1, "tape: DOIO failed with er = %i\n", rc); final = 1; } break; case TAPE_IO_STOP: __tape_halt_io(device, request); break; default: if (rc > 0) { DBF_EVENT(6, "xunknownrc\n"); PRINT_ERR("Invalid return code from discipline " "interrupt function.\n"); rc = -EIO; } final = 1; break; } if (final) { /* May be an unsolicited irq */ if(request != NULL) { /* Set ending status. */ request->rc = rc; request->status = TAPE_REQUEST_DONE; __tape_remove_request(device, request); } else { __tape_do_io_list(device); } }}/* * Tape device open function used by tape_char & tape_block frontends. */inttape_open(struct tape_device *device){ int rc; spin_lock(get_ccwdev_lock(device->cdev)); if (device->tape_state == TS_NOT_OPER) { DBF_EVENT(6, "TAPE:nodev\n"); rc = -ENODEV; } else if (device->tape_state == TS_IN_USE) { DBF_EVENT(6, "TAPE:dbusy\n"); rc = -EBUSY; } else if (device->tape_state == TS_BLKUSE) { DBF_EVENT(6, "TAPE:dbusy\n"); rc = -EBUSY; } else if (device->discipline != NULL && !try_module_get(device->discipline->owner)) { DBF_EVENT(6, "TAPE:nodisc\n"); rc = -ENODEV; } else { tape_state_set(device, TS_IN_USE); rc = 0; } spin_unlock(get_ccwdev_lock(device->cdev)); return rc;}/* * Tape device release function used by tape_char & tape_block frontends. */inttape_release(struct tape_device *device){ spin_lock(get_ccwdev_lock(device->cdev)); if (device->tape_state == TS_IN_USE) tape_state_set(device, TS_UNUSED); module_put(device->discipline->owner); spin_unlock(get_ccwdev_lock(device->cdev)); return 0;}/* * Execute a magnetic tape command a number of times. */inttape_mtop(struct tape_device *device, int mt_op, int mt_count){ tape_mtop_fn fn; int rc; DBF_EVENT(6, "TAPE:mtio\n"); DBF_EVENT(6, "TAPE:ioop: %x\n", mt_op); DBF_EVENT(6, "TAPE:arg: %x\n", mt_count); if (mt_op < 0 || mt_op >= TAPE_NR_MTOPS) return -EINVAL; fn = device->discipline->mtop_array[mt_op]; if (fn == NULL) return -EINVAL; /* We assume that the backends can handle count up to 500. */ if (mt_op == MTBSR || mt_op == MTFSR || mt_op == MTFSF || mt_op == MTBSF || mt_op == MTFSFM || mt_op == MTBSFM) { rc = 0; for (; mt_count > 500; mt_count -= 500) if ((rc = fn(device, 500)) != 0) break; if (rc == 0) rc = fn(device, mt_count); } else rc = fn(device, mt_count); return rc;}/* * Tape init function. */static inttape_init (void){ TAPE_DBF_AREA = debug_register ( "tape", 1, 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, "tape init: ($Revision: 1.50 $)\n"); tape_proc_init(); tapechar_init (); tapeblock_init (); return 0;}/* * Tape exit function. */static voidtape_exit(void){ DBF_EVENT(6, "tape exit\n"); /* Get rid of the frontends */ tapechar_exit(); tapeblock_exit(); tape_proc_cleanup(); debug_unregister (TAPE_DBF_AREA);}MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and " "Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)");MODULE_DESCRIPTION("Linux on zSeries channel attached " "tape device driver ($Revision: 1.50 $)");MODULE_LICENSE("GPL");module_init(tape_init);module_exit(tape_exit);EXPORT_SYMBOL(tape_generic_remove);EXPORT_SYMBOL(tape_generic_probe);EXPORT_SYMBOL(tape_generic_online);EXPORT_SYMBOL(tape_generic_offline);EXPORT_SYMBOL(tape_put_device);EXPORT_SYMBOL(tape_get_device_reference);EXPORT_SYMBOL(tape_state_verbose);EXPORT_SYMBOL(tape_op_verbose);EXPORT_SYMBOL(tape_state_set);EXPORT_SYMBOL(tape_med_state_set);EXPORT_SYMBOL(tape_alloc_request);EXPORT_SYMBOL(tape_free_request);EXPORT_SYMBOL(tape_dump_sense);EXPORT_SYMBOL(tape_dump_sense_dbf);EXPORT_SYMBOL(tape_do_io);EXPORT_SYMBOL(tape_do_io_async);EXPORT_SYMBOL(tape_do_io_interruptible);EXPORT_SYMBOL(tape_mtop);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?