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

📄 tape_34xx.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct list_head *	sbid_list;	struct tape_34xx_sbid *	sbid;	struct list_head *	l;	/*	 * immediately return if there is no list at all or the block to add	 * is located in segment 1 of wrap 0 because this position is used	 * if no hardware position data is supplied.	 */	sbid_list = (struct list_head *) device->discdata;	if (!sbid_list || (bid.segment < 2 && bid.wrap == 0))		return;	/*	 * Search the position where to insert the new entry. Hardware	 * acceleration uses only the segment and wrap number. So we	 * need only one entry for a specific wrap/segment combination.	 * If there is a block with a lower number but the same hard-	 * ware position data we just update the block number in the	 * existing entry.	 */	list_for_each(l, sbid_list) {		sbid = list_entry(l, struct tape_34xx_sbid, list);		if (			(sbid->bid.segment == bid.segment) &&			(sbid->bid.wrap    == bid.wrap)		) {			if (bid.block < sbid->bid.block)				sbid->bid = bid;			else return;			break;		}		/* Sort in according to logical block number. */		if (bid.block < sbid->bid.block) {			tape_34xx_append_new_sbid(bid, l->prev);			break;		}	}	/* List empty or new block bigger than last entry. */	if (l == sbid_list)		tape_34xx_append_new_sbid(bid, l->prev);	DBF_LH(4, "Current list is:\n");	list_for_each(l, sbid_list) {		sbid = list_entry(l, struct tape_34xx_sbid, list);		DBF_LH(4, "%d:%03d@%05d\n",			sbid->bid.wrap,			sbid->bid.segment,			sbid->bid.block		);	}}/* * Delete all entries from the search block ID list that belong to tape blocks * equal or higher than the given number. */static voidtape_34xx_delete_sbid_from(struct tape_device *device, int from){	struct list_head *	sbid_list;	struct tape_34xx_sbid *	sbid;	struct list_head *	l;	struct list_head *	n;	sbid_list = (struct list_head *) device->discdata;	if (!sbid_list)		return;	list_for_each_safe(l, n, sbid_list) {		sbid = list_entry(l, struct tape_34xx_sbid, list);		if (sbid->bid.block >= from) {			DBF_LH(4, "Delete sbid %d:%03d@%05d\n",				sbid->bid.wrap,				sbid->bid.segment,				sbid->bid.block			);			list_del(l);			kfree(sbid);		}	}}/* * Merge hardware position data into a block id. */static voidtape_34xx_merge_sbid(	struct tape_device *		device,	struct tape_34xx_block_id *	bid) {	struct tape_34xx_sbid *	sbid;	struct tape_34xx_sbid *	sbid_to_use;	struct list_head *	sbid_list;	struct list_head *	l;	sbid_list = (struct list_head *) device->discdata;	bid->wrap    = 0;	bid->segment = 1;	if (!sbid_list || list_empty(sbid_list))		return;	sbid_to_use = NULL;	list_for_each(l, sbid_list) {		sbid = list_entry(l, struct tape_34xx_sbid, list);		if (sbid->bid.block >= bid->block)			break;		sbid_to_use = sbid;	}	if (sbid_to_use) {		bid->wrap    = sbid_to_use->bid.wrap;		bid->segment = sbid_to_use->bid.segment;		DBF_LH(4, "Use %d:%03d@%05d for %05d\n",			sbid_to_use->bid.wrap,			sbid_to_use->bid.segment,			sbid_to_use->bid.block,			bid->block		);	}}static inttape_34xx_setup_device(struct tape_device * device){	int			rc;	struct list_head *	discdata;	DBF_EVENT(6, "34xx device setup\n");	if ((rc = tape_std_assign(device)) == 0) {		if ((rc = tape_34xx_medium_sense(device)) != 0) {			DBF_LH(3, "34xx medium sense returned %d\n", rc);		}	}	discdata = kmalloc(sizeof(struct list_head), GFP_KERNEL);	if (discdata) {			INIT_LIST_HEAD(discdata);			device->discdata = discdata;	}	return rc;}static voidtape_34xx_cleanup_device(struct tape_device *device){	tape_std_unassign(device);		if (device->discdata) {		tape_34xx_delete_sbid_from(device, 0);		kfree(device->discdata);		device->discdata = NULL;	}}/* * MTTELL: Tell block. Return the number of block relative to current file. */static inttape_34xx_mttell(struct tape_device *device, int mt_count){	struct {		struct tape_34xx_block_id	cbid;		struct tape_34xx_block_id	dbid;	} __attribute__ ((packed)) block_id;	int rc;	rc = tape_std_read_block_id(device, (__u64 *) &block_id);	if (rc)		return rc;	tape_34xx_add_sbid(device, block_id.cbid);	return block_id.cbid.block;}/* * MTSEEK: seek to the specified block. */static inttape_34xx_mtseek(struct tape_device *device, int mt_count){	struct tape_request *request;	struct tape_34xx_block_id *	bid;	if (mt_count > 0x3fffff) {		DBF_EXCEPTION(6, "xsee parm\n");		return -EINVAL;	}	request = tape_alloc_request(3, 4);	if (IS_ERR(request))		return PTR_ERR(request);	/* setup ccws */	request->op = TO_LBL;	bid         = (struct tape_34xx_block_id *) request->cpdata;	bid->format = (*device->modeset_byte & 0x08) ?			TAPE34XX_FMT_3480_XF : TAPE34XX_FMT_3480;	bid->block  = mt_count;	tape_34xx_merge_sbid(device, bid);	tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte);	tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata);	tape_ccw_end(request->cpaddr + 2, NOP, 0, NULL);	/* execute it */	return tape_do_io_free(device, request);}#ifdef CONFIG_S390_TAPE_BLOCK/* * Tape block read for 34xx. */static struct tape_request *tape_34xx_bread(struct tape_device *device, struct request *req){	struct tape_request *request;	struct ccw1 *ccw;	int count = 0, i;	unsigned off;	char *dst;	struct bio_vec *bv;	struct bio *bio;	struct tape_34xx_block_id *	start_block;	DBF_EVENT(6, "xBREDid:");	/* Count the number of blocks for the request. */	rq_for_each_bio(bio, req) {		bio_for_each_segment(bv, bio, i) {			count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);		}	}	/* Allocate the ccw request. */	request = tape_alloc_request(3+count+1, 8);	if (IS_ERR(request))		return request;	/* Setup ccws. */	request->op = TO_BLOCK;	start_block = (struct tape_34xx_block_id *) request->cpdata;	start_block->block = req->sector >> TAPEBLOCK_HSEC_S2B;	DBF_EVENT(6, "start_block = %i\n", start_block->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.	 * The second nop will be filled with a read block id which is in	 * turn used by tape_34xx_free_bread to populate the segment bid	 * table.	 */	ccw = tape_ccw_cc(ccw, NOP, 0, NULL);	ccw = tape_ccw_cc(ccw, NOP, 0, NULL);	rq_for_each_bio(bio, req) {		bio_for_each_segment(bv, bio, i) {			dst = kmap(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;			}		}	}	ccw = tape_ccw_end(ccw, NOP, 0, NULL);	DBF_EVENT(6, "xBREDccwg\n");	return request;}static voidtape_34xx_free_bread (struct tape_request *request){	struct ccw1* ccw;	ccw = request->cpaddr;	if ((ccw + 2)->cmd_code == READ_BLOCK_ID) {		struct {			struct tape_34xx_block_id	cbid;			struct tape_34xx_block_id	dbid;		} __attribute__ ((packed)) *rbi_data;		rbi_data = request->cpdata;		if (request->device)			tape_34xx_add_sbid(request->device, rbi_data->cbid);	}	/* Last ccw is a nop and doesn't need clear_normalized_cda */	for (; 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_34xx_check_locate(struct tape_device *device, struct tape_request *request){	struct tape_34xx_block_id *	start_block;	start_block = (struct tape_34xx_block_id *) request->cpdata;	if (start_block->block == device->blk_data.block_position)		return;	DBF_LH(4, "Block seek(%06d+%06d)\n", start_block->block, device->bof);	start_block->wrap    = 0;	start_block->segment = 1;	start_block->format  = (*device->modeset_byte & 0x08) ?				TAPE34XX_FMT_3480_XF :				TAPE34XX_FMT_3480;	start_block->block   = start_block->block + device->bof;	tape_34xx_merge_sbid(device, start_block);	tape_ccw_cc(request->cpaddr + 1, LOCATE, 4, request->cpdata);	tape_ccw_cc(request->cpaddr + 2, READ_BLOCK_ID, 8, request->cpdata);}#endif/* * List of 3480/3490 magnetic tape commands. */static tape_mtop_fn tape_34xx_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_34xx_mtseek,	[MTTELL]	 = tape_34xx_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 3480 and 3490. */static struct tape_discipline tape_discipline_34xx = {	.owner = THIS_MODULE,	.setup_device = tape_34xx_setup_device,	.cleanup_device = tape_34xx_cleanup_device,	.process_eov = tape_std_process_eov,	.irq = tape_34xx_irq,	.read_block = tape_std_read_block,	.write_block = tape_std_write_block,#ifdef CONFIG_S390_TAPE_BLOCK	.bread = tape_34xx_bread,	.free_bread = tape_34xx_free_bread,	.check_locate = tape_34xx_check_locate,#endif	.ioctl_fn = tape_34xx_ioctl,	.mtop_array = tape_34xx_mtop};static struct ccw_device_id tape_34xx_ids[] = {	{ CCW_DEVICE_DEVTYPE(0x3480, 0, 0x3480, 0), driver_info: tape_3480},	{ CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), driver_info: tape_3490},	{ /* end of list */ }};static inttape_34xx_online(struct ccw_device *cdev){	return tape_generic_online(		cdev->dev.driver_data,		&tape_discipline_34xx	);}static inttape_34xx_offline(struct ccw_device *cdev){	return tape_generic_offline(cdev->dev.driver_data);}static struct ccw_driver tape_34xx_driver = {	.name = "tape_34xx",	.owner = THIS_MODULE,	.ids = tape_34xx_ids,	.probe = tape_generic_probe,	.remove = tape_generic_remove,	.set_online = tape_34xx_online,	.set_offline = tape_34xx_offline,};static inttape_34xx_init (void){	int rc;	TAPE_DBF_AREA = debug_register ( "tape_34xx", 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, "34xx init: $Revision: 1.23 $\n");	/* Register driver for 3480/3490 tapes. */	rc = ccw_driver_register(&tape_34xx_driver);	if (rc)		DBF_EVENT(3, "34xx init failed\n");	else		DBF_EVENT(3, "34xx registered\n");	return rc;}static voidtape_34xx_exit(void){	ccw_driver_unregister(&tape_34xx_driver);	debug_unregister(TAPE_DBF_AREA);}MODULE_DEVICE_TABLE(ccw, tape_34xx_ids);MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape "		   "device driver ($Revision: 1.23 $)");MODULE_LICENSE("GPL");module_init(tape_34xx_init);module_exit(tape_34xx_exit);

⌨️ 快捷键说明

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