⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tape_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
		op = tape_op_verbose[request->op];	else		op = "---";	DBF_EVENT(3, "DSTAT : %02x   CSTAT: %02x\n",		  irb->scsw.dstat,irb->scsw.cstat);	DBF_EVENT(3, "DEVICE: %08x OP\t: %s\n", device->cdev_id, op);	sptr = (unsigned int *) irb->ecw;	DBF_EVENT(3, "%08x %08x\n", sptr[0], sptr[1]);	DBF_EVENT(3, "%08x %08x\n", sptr[2], sptr[3]);	DBF_EVENT(3, "%08x %08x\n", sptr[4], sptr[5]);	DBF_EVENT(3, "%08x %08x\n", sptr[6], sptr[7]);}/* * I/O helper function. Adds the request to the request queue * and starts it if the tape is idle. Has to be called with * the device lock held. */static inline int__tape_start_request(struct tape_device *device, struct tape_request *request){	int rc;	switch (request->op) {		case TO_MSEN:		case TO_ASSIGN:		case TO_UNASSIGN:		case TO_READ_ATTMSG:			if (device->tape_state == TS_INIT)				break;			if (device->tape_state == TS_UNUSED)				break;		default:			if (device->tape_state == TS_BLKUSE)				break;			if (device->tape_state != TS_IN_USE)				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. */		rc = __tape_start_io(device, request);		if (rc)			return rc;		DBF_LH(5, "Request %p added for execution.\n", request);		list_add(&request->list, &device->req_queue);	} else {		DBF_LH(5, "Request %p add to queue.\n", request);		request->status = TAPE_REQUEST_QUEUED;		list_add_tail(&request->list, &device->req_queue);	}	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_start_request(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_start_request(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_start_request(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_cancel_io(device, request);	spin_unlock_irq(get_ccwdev_lock(device->cdev));	if (rc == 0) {		/* Wait for the interrupt that acknowledges the halt. */		do {			rc = wait_event_interruptible(				wq,				(request->callback == NULL)			);		} while (rc != -ERESTARTSYS);		DBF_EVENT(3, "IO stopped on %08x\n", device->cdev_id);		rc = -ERESTARTSYS;	}	return rc;}/* * 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 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)) {		/* FIXME: What to do with the request? */		switch (PTR_ERR(irb)) {			case -ETIMEDOUT:				PRINT_WARN("(%s): Request timed out\n",					cdev->dev.bus_id);			case -EIO:				__tape_end_request(device, request, -EIO);				break;			default:				PRINT_ERR("(%s): Unexpected i/o error %li\n",					cdev->dev.bus_id,					PTR_ERR(irb));		}		return;	}	/*	 * If the condition code is not zero and the start function bit is	 * still set, this is an deferred error and the last start I/O did	 * not succeed. Restart the request now.	 */	if (irb->scsw.cc != 0 && (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {		PRINT_WARN("(%s): deferred cc=%i. restaring\n",			cdev->dev.bus_id,			irb->scsw.cc);		rc = __tape_start_io(device, request);		if (rc)			__tape_end_request(device, request, rc);		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_end_request(device, request, -EIO);		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.	 */	switch (rc) {		case TAPE_IO_SUCCESS:			/* Upon normal completion the device _is_ online */			device->tape_generic_status |= GMT_ONLINE(~0);			__tape_end_request(device, request, rc);			break;		case TAPE_IO_PENDING:			break;		case TAPE_IO_RETRY:			rc = __tape_start_io(device, request);			if (rc)				__tape_end_request(device, request, rc);			break;		case TAPE_IO_STOP:			rc = __tape_cancel_io(device, request);			if (rc)				__tape_end_request(device, request, rc);			break;		default:			if (rc > 0) {				DBF_EVENT(6, "xunknownrc\n");				PRINT_ERR("Invalid return code from discipline "				  	"interrupt function.\n");				__tape_end_request(device, request, -EIO);			} else {				__tape_end_request(device, request, rc);			}			break;	}}/* * 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", 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, "tape init: ($Revision: 1.54 $)\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.54 $)");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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -