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

📄 tape_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
			break;		default:			DBF_EVENT(3, "(%08x): Set offline failed "				"- drive in use.\n",				device->cdev_id);			PRINT_WARN("(%s): Set offline failed "				"- drive in use.\n",				device->cdev->dev.bus_id);			spin_unlock_irq(get_ccwdev_lock(device->cdev));			return -EBUSY;	}	DBF_LH(3, "(%08x): Drive set offline.\n", device->cdev_id);	return 0;}/* * Allocate memory for a new device structure. */static struct tape_device *tape_alloc_device(void){	struct tape_device *device;	device = (struct tape_device *)		kmalloc(sizeof(struct tape_device), GFP_KERNEL);	if (device == NULL) {		DBF_EXCEPTION(2, "ti:no mem\n");		PRINT_INFO ("can't allocate memory for "			    "tape info structure\n");		return ERR_PTR(-ENOMEM);	}	memset(device, 0, sizeof(struct tape_device));	device->modeset_byte = (char *) kmalloc(1, GFP_KERNEL | GFP_DMA);	if (device->modeset_byte == NULL) {		DBF_EXCEPTION(2, "ti:no mem\n");		PRINT_INFO("can't allocate memory for modeset byte\n");		kfree(device);		return ERR_PTR(-ENOMEM);	}	INIT_LIST_HEAD(&device->req_queue);	INIT_LIST_HEAD(&device->node);	init_waitqueue_head(&device->state_change_wq);	device->tape_state = TS_INIT;	device->medium_state = MS_UNKNOWN;	*device->modeset_byte = 0;	device->first_minor = -1;	atomic_set(&device->ref_count, 1);	INIT_WORK(&device->tape_dnr, tape_delayed_next_request, device);	return device;}/* * Get a reference to an existing device structure. This will automatically * increment the reference count. */struct tape_device *tape_get_device_reference(struct tape_device *device){	DBF_EVENT(4, "tape_get_device_reference(%p) = %i\n", device,		atomic_inc_return(&device->ref_count));	return device;}/* * Decrease the reference counter of a devices structure. If the * reference counter reaches zero free the device structure. * The function returns a NULL pointer to be used by the caller * for clearing reference pointers. */struct tape_device *tape_put_device(struct tape_device *device){	int remain;	remain = atomic_dec_return(&device->ref_count);	if (remain > 0) {		DBF_EVENT(4, "tape_put_device(%p) -> %i\n", device, remain);	} else {		if (remain < 0) {			DBF_EVENT(4, "put device without reference\n");			PRINT_ERR("put device without reference\n");		} else {			DBF_EVENT(4, "tape_free_device(%p)\n", device);			kfree(device->modeset_byte);			kfree(device);		}	}	return NULL;			}/* * Find tape device by a device index. */struct tape_device *tape_get_device(int devindex){	struct tape_device *device, *tmp;	device = ERR_PTR(-ENODEV);	read_lock(&tape_device_lock);	list_for_each_entry(tmp, &tape_device_list, node) {		if (tmp->first_minor / TAPE_MINORS_PER_DEV == devindex) {			device = tape_get_device_reference(tmp);			break;		}	}	read_unlock(&tape_device_lock);	return device;}/* * Driverfs tape probe function. */inttape_generic_probe(struct ccw_device *cdev){	struct tape_device *device;	device = tape_alloc_device();	if (IS_ERR(device))		return -ENODEV;	PRINT_INFO("tape device %s found\n", cdev->dev.bus_id);	cdev->dev.driver_data = device;	device->cdev = cdev;	device->cdev_id = busid_to_int(cdev->dev.bus_id);	cdev->handler = __tape_do_irq;	ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);	sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);	return 0;}static inline void__tape_discard_requests(struct tape_device *device){	struct tape_request *	request;	struct list_head *	l, *n;	list_for_each_safe(l, n, &device->req_queue) {		request = list_entry(l, struct tape_request, list);		if (request->status == TAPE_REQUEST_IN_IO)			request->status = TAPE_REQUEST_DONE;		list_del(&request->list);		/* Decrease ref_count for removed request. */		request->device = tape_put_device(device);		request->rc = -EIO;		if (request->callback != NULL)			request->callback(request, request->callback_data);	}}/* * Driverfs tape remove function. * * This function is called whenever the common I/O layer detects the device * gone. This can happen at any time and we cannot refuse. */voidtape_generic_remove(struct ccw_device *cdev){	struct tape_device *	device;	device = cdev->dev.driver_data;	if (!device) {		PRINT_ERR("No device pointer in tape_generic_remove!\n");		return;	}	DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev);	spin_lock_irq(get_ccwdev_lock(device->cdev));	switch (device->tape_state) {		case TS_INIT:			tape_state_set(device, TS_NOT_OPER);		case TS_NOT_OPER:			/*			 * Nothing to do.			 */			spin_unlock_irq(get_ccwdev_lock(device->cdev));			break;		case TS_UNUSED:			/*			 * Need only to release the device.			 */			tape_state_set(device, TS_NOT_OPER);			spin_unlock_irq(get_ccwdev_lock(device->cdev));			tape_cleanup_device(device);			break;		default:			/*			 * There may be requests on the queue. We will not get			 * an interrupt for a request that was running. So we			 * just post them all as I/O errors.			 */			DBF_EVENT(3, "(%08x): Drive in use vanished!\n",				device->cdev_id);			PRINT_WARN("(%s): Drive in use vanished - "				"expect trouble!\n",				device->cdev->dev.bus_id);			PRINT_WARN("State was %i\n", device->tape_state);			tape_state_set(device, TS_NOT_OPER);			__tape_discard_requests(device);			spin_unlock_irq(get_ccwdev_lock(device->cdev));			tape_cleanup_device(device);	}	if (cdev->dev.driver_data != NULL) {		sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group);		cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data);	}}/* * Allocate a new tape ccw request */struct tape_request *tape_alloc_request(int cplength, int datasize){	struct tape_request *request;	if (datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE)		BUG();	DBF_LH(6, "tape_alloc_request(%d, %d)\n", cplength, datasize);	request = (struct tape_request *) kmalloc(sizeof(struct tape_request),						  GFP_KERNEL);	if (request == NULL) {		DBF_EXCEPTION(1, "cqra nomem\n");		return ERR_PTR(-ENOMEM);	}	memset(request, 0, sizeof(struct tape_request));	/* allocate channel program */	if (cplength > 0) {		request->cpaddr = kmalloc(cplength*sizeof(struct ccw1),					  GFP_ATOMIC | GFP_DMA);		if (request->cpaddr == NULL) {			DBF_EXCEPTION(1, "cqra nomem\n");			kfree(request);			return ERR_PTR(-ENOMEM);		}		memset(request->cpaddr, 0, cplength*sizeof(struct ccw1));	}	/* alloc small kernel buffer */	if (datasize > 0) {		request->cpdata = kmalloc(datasize, GFP_KERNEL | GFP_DMA);		if (request->cpdata == NULL) {			DBF_EXCEPTION(1, "cqra nomem\n");			kfree(request->cpaddr);			kfree(request);			return ERR_PTR(-ENOMEM);		}		memset(request->cpdata, 0, datasize);	}	DBF_LH(6, "New request %p(%p/%p)\n", request, request->cpaddr,		request->cpdata);	return request;}/* * Free tape ccw request */voidtape_free_request (struct tape_request * request){	DBF_LH(6, "Free request %p\n", request);	if (request->device != NULL) {		request->device = tape_put_device(request->device);	}	kfree(request->cpdata);	kfree(request->cpaddr);	kfree(request);}static inline int__tape_start_io(struct tape_device *device, struct tape_request *request){	int rc;#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 == 0) {		request->status = TAPE_REQUEST_IN_IO;	} else if (rc == -EBUSY) {		/* The common I/O subsystem is currently busy. Retry later. */		request->status = TAPE_REQUEST_QUEUED;		schedule_work(&device->tape_dnr);		rc = 0;	} else {		/* Start failed. Remove request and indicate failure. */		DBF_EVENT(1, "tape: start request failed with RC = %i\n", rc);	}	return rc;}static inline void__tape_start_next_request(struct tape_device *device){	struct list_head *l, *n;	struct tape_request *request;	int rc;	DBF_LH(6, "__tape_start_next_request(%p)\n", device);	/*	 * Try to start each request on request queue until one is	 * started successful.	 */	list_for_each_safe(l, n, &device->req_queue) {		request = list_entry(l, struct tape_request, list);		/*		 * Avoid race condition if bottom-half was triggered more than		 * once.		 */		if (request->status == TAPE_REQUEST_IN_IO)			return;		/*		 * We wanted to cancel the request but the common I/O layer		 * was busy at that time. This can only happen if this		 * function is called by delayed_next_request.		 * Otherwise we start the next request on the queue.		 */		if (request->status == TAPE_REQUEST_CANCEL) {			rc = __tape_cancel_io(device, request);		} else {			rc = __tape_start_io(device, request);		}		if (rc == 0)			return;		/* Set ending status. */		request->rc = rc;		request->status = TAPE_REQUEST_DONE;		/* Remove from request queue. */		list_del(&request->list);		/* Do callback. */		if (request->callback != NULL)			request->callback(request, request->callback_data);	}}static voidtape_delayed_next_request(void *data){	struct tape_device *	device;	device = (struct tape_device *) data;	DBF_LH(6, "tape_delayed_next_request(%p)\n", device);	spin_lock_irq(get_ccwdev_lock(device->cdev));	__tape_start_next_request(device);	spin_unlock_irq(get_ccwdev_lock(device->cdev));}static inline void__tape_end_request(	struct tape_device *	device,	struct tape_request *	request,	int			rc){	DBF_LH(6, "__tape_end_request(%p, %p, %i)\n", device, request, rc);	if (request) {		request->rc = rc;		request->status = TAPE_REQUEST_DONE;		/* Remove from request queue. */		list_del(&request->list);		/* Do callback. */		if (request->callback != NULL)			request->callback(request, request->callback_data);	}	/* Start next request. */	if (!list_empty(&device->req_queue))		__tape_start_next_request(device);}/* * Write sense data to console/dbf */voidtape_dump_sense(struct tape_device* device, struct tape_request *request,		struct irb *irb){	unsigned int *sptr;	PRINT_INFO("-------------------------------------------------\n");	PRINT_INFO("DSTAT : %02x  CSTAT: %02x	CPA: %04x\n",		   irb->scsw.dstat, irb->scsw.cstat, irb->scsw.cpa);	PRINT_INFO("DEVICE: %s\n", device->cdev->dev.bus_id);	if (request != NULL)		PRINT_INFO("OP	  : %s\n", tape_op_verbose[request->op]);	sptr = (unsigned int *) irb->ecw;	PRINT_INFO("Sense data: %08X %08X %08X %08X \n",		   sptr[0], sptr[1], sptr[2], sptr[3]);	PRINT_INFO("Sense data: %08X %08X %08X %08X \n",		   sptr[4], sptr[5], sptr[6], sptr[7]);	PRINT_INFO("--------------------------------------------------\n");}/* * Write sense data to dbf */voidtape_dump_sense_dbf(struct tape_device *device, struct tape_request *request,		    struct irb *irb){	unsigned int *sptr;	const char* op;	if (request != NULL)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -