tape_3590.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,302 行 · 第 1/3 页

C
1,302
字号
	case 0x08:		if (sense->fmt.f71.mdf == 0)			PRINT_WARN("(%s): Repair will disable message "				   "display 0x%x on DV\n",				   device->cdev->dev.bus_id,				   sense->fmt.f71.md[1]);		else			PRINT_WARN("(%s): Repair will disable message "				   "displays (0x%x-0x%x) on DV\n",				   device->cdev->dev.bus_id,				   sense->fmt.f71.md[1], sense->fmt.f71.md[2]);		break;	case 0x09:		PRINT_WARN("(%s): Clean DV\n", device->cdev->dev.bus_id);		break;	default:		PRINT_WARN("(%s): DSIM ServiceMsg: 0x%02x\n",			   device->cdev->dev.bus_id, sense->fmt.f71.smc);	}}/* * Print standard ERA Message */static voidtape_3590_print_era_msg(struct tape_device *device, struct irb *irb){	struct tape_3590_sense *sense;	sense = (struct tape_3590_sense *) irb->ecw;	if (sense->mc == 0)		return;	if ((sense->mc > 0) && (sense->mc < TAPE_3590_MAX_MSG)) {		if (tape_3590_msg[sense->mc] != NULL)			PRINT_WARN("(%s): %s\n", device->cdev->dev.bus_id,				   tape_3590_msg[sense->mc]);		else {			PRINT_WARN("(%s): Message Code 0x%x\n",				   device->cdev->dev.bus_id, sense->mc);		}		return;	}	if (sense->mc == 0xf0) {		/* Standard Media Information Message */		PRINT_WARN("(%s): MIM SEV=%i, MC=%02x, ES=%x/%x, "			   "RC=%02x-%04x-%02x\n", device->cdev->dev.bus_id,			   sense->fmt.f70.sev, sense->mc,			   sense->fmt.f70.emc, sense->fmt.f70.smc,			   sense->fmt.f70.refcode, sense->fmt.f70.mid,			   sense->fmt.f70.fid);		tape_3590_print_mim_msg_f0(device, irb);		return;	}	if (sense->mc == 0xf1) {		/* Standard I/O Subsystem Service Information Message */		PRINT_WARN("(%s): IOSIM SEV=%i, DEVTYPE=3590/%02x, "			   "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",			   device->cdev->dev.bus_id, sense->fmt.f71.sev,			   device->cdev->id.dev_model,			   sense->mc, sense->fmt.f71.emc,			   sense->fmt.f71.smc, sense->fmt.f71.refcode1,			   sense->fmt.f71.refcode2, sense->fmt.f71.refcode3);		tape_3590_print_io_sim_msg_f1(device, irb);		return;	}	if (sense->mc == 0xf2) {		/* Standard Device Service Information Message */		PRINT_WARN("(%s): DEVSIM SEV=%i, DEVTYPE=3590/%02x, "			   "MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",			   device->cdev->dev.bus_id, sense->fmt.f71.sev,			   device->cdev->id.dev_model,			   sense->mc, sense->fmt.f71.emc,			   sense->fmt.f71.smc, sense->fmt.f71.refcode1,			   sense->fmt.f71.refcode2, sense->fmt.f71.refcode3);		tape_3590_print_dev_sim_msg_f2(device, irb);		return;	}	if (sense->mc == 0xf3) {		/* Standard Library Service Information Message */		return;	}	PRINT_WARN("(%s): Device Message(%x)\n",		   device->cdev->dev.bus_id, sense->mc);}/* *  3590 error Recovery routine: *  If possible, it tries to recover from the error. If this is not possible, *  inform the user about the problem. */static inttape_3590_unit_check(struct tape_device *device, struct tape_request *request,		     struct irb *irb){	struct tape_3590_sense *sense;	int rc;#ifdef CONFIG_S390_TAPE_BLOCK	if (request->op == TO_BLOCK) {		/*		 * Recovery for block device requests. Set the block_position		 * to something invalid and retry.		 */		device->blk_data.block_position = -1;		if (request->retries-- <= 0)			return tape_3590_erp_failed(device, request, irb, -EIO);		else			return tape_3590_erp_retry(device, request, irb);	}#endif	sense = (struct tape_3590_sense *) irb->ecw;	/*	 * First check all RC-QRCs where we want to do something special	 *   - "break":     basic error recovery is done	 *   - "goto out:": just print error message if available	 */	rc = -EIO;	switch (sense->rc_rqc) {	case 0x1110:		tape_3590_print_era_msg(device, irb);		return tape_3590_erp_read_buf_log(device, request, irb);	case 0x2011:		tape_3590_print_era_msg(device, irb);		return tape_3590_erp_read_alternate(device, request, irb);	case 0x2230:	case 0x2231:		tape_3590_print_era_msg(device, irb);		return tape_3590_erp_special_interrupt(device, request, irb);	case 0x3010:		DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n",			  device->cdev_id);		return tape_3590_erp_basic(device, request, irb, -ENOSPC);	case 0x3012:		DBF_EVENT(2, "(%08x): Forward at End of Partition\n",			  device->cdev_id);		return tape_3590_erp_basic(device, request, irb, -ENOSPC);	case 0x3020:		DBF_EVENT(2, "(%08x): End of Data Mark\n", device->cdev_id);		return tape_3590_erp_basic(device, request, irb, -ENOSPC);	case 0x3122:		DBF_EVENT(2, "(%08x): Rewind Unload initiated\n",			  device->cdev_id);		return tape_3590_erp_basic(device, request, irb, -EIO);	case 0x3123:		DBF_EVENT(2, "(%08x): Rewind Unload complete\n",			  device->cdev_id);		tape_med_state_set(device, MS_UNLOADED);		return tape_3590_erp_basic(device, request, irb, 0);	case 0x4010:		/*		 * print additional msg since default msg		 * "device intervention" is not very meaningfull		 */		PRINT_WARN("(%s): Tape operation when medium not loaded\n",			   device->cdev->dev.bus_id);		tape_med_state_set(device, MS_UNLOADED);		return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);	case 0x4012:		/* Device Long Busy */		tape_3590_print_era_msg(device, irb);		return tape_3590_erp_long_busy(device, request, irb);	case 0x5010:		if (sense->rac == 0xd0) {			/* Swap */			tape_3590_print_era_msg(device, irb);			return tape_3590_erp_swap(device, request, irb);		}		if (sense->rac == 0x26) {			/* Read Opposite */			tape_3590_print_era_msg(device, irb);			return tape_3590_erp_read_opposite(device, request,							   irb);		}		return tape_3590_erp_basic(device, request, irb, -EIO);	case 0x5020:	case 0x5021:	case 0x5022:	case 0x5040:	case 0x5041:	case 0x5042:		tape_3590_print_era_msg(device, irb);		return tape_3590_erp_swap(device, request, irb);	case 0x5110:	case 0x5111:		return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE);	case 0x5120:	case 0x1120:		tape_med_state_set(device, MS_UNLOADED);		return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);	case 0x6020:		PRINT_WARN("(%s): Cartridge of wrong type ?\n",			   device->cdev->dev.bus_id);		return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE);	case 0x8011:		PRINT_WARN("(%s): Another host has reserved the tape device\n",			   device->cdev->dev.bus_id);		return tape_3590_erp_basic(device, request, irb, -EPERM);	case 0x8013:		PRINT_WARN("(%s): Another host has priviliged access to the "			   "tape device\n", device->cdev->dev.bus_id);		PRINT_WARN("(%s): To solve the problem unload the current "			   "cartridge!\n", device->cdev->dev.bus_id);		return tape_3590_erp_basic(device, request, irb, -EPERM);	default:		return tape_3590_erp_basic(device, request, irb, -EIO);	}}/* * 3590 interrupt handler: */static inttape_3590_irq(struct tape_device *device, struct tape_request *request,	      struct irb *irb){	if (request == NULL)		return tape_3590_unsolicited_irq(device, irb);	if ((irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) &&	    (irb->scsw.dstat & DEV_STAT_DEV_END) && (request->op == TO_WRI)) {		/* Write at end of volume */		DBF_EVENT(2, "End of volume\n");		return tape_3590_erp_failed(device, request, irb, -ENOSPC);	}	if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)		return tape_3590_unit_check(device, request, irb);	if (irb->scsw.dstat & DEV_STAT_DEV_END) {		if (irb->scsw.dstat == DEV_STAT_UNIT_EXCEP) {			if (request->op == TO_FSB || request->op == TO_BSB)				request->rescnt++;			else				DBF_EVENT(5, "Unit Exception!\n");		}		return tape_3590_done(device, request);	}	if (irb->scsw.dstat & DEV_STAT_CHN_END) {		DBF_EVENT(2, "cannel end\n");		return TAPE_IO_PENDING;	}	if (irb->scsw.dstat & DEV_STAT_ATTENTION) {		DBF_EVENT(2, "Unit Attention when busy..\n");		return TAPE_IO_PENDING;	}	DBF_EVENT(6, "xunknownirq\n");	PRINT_ERR("Unexpected interrupt.\n");	PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]);	tape_dump_sense(device, request, irb);	return TAPE_IO_STOP;}/* * Setup device function */static inttape_3590_setup_device(struct tape_device *device){	int rc;	struct tape_3590_disc_data *data;	DBF_EVENT(6, "3590 device setup\n");	data = kmalloc(sizeof(struct tape_3590_disc_data),		       GFP_KERNEL | GFP_DMA);	if (data == NULL)		return -ENOMEM;	data->read_back_op = READ_PREVIOUS;	device->discdata = data;	if ((rc = tape_std_assign(device)) == 0) {		/* Try to find out if medium is loaded */		if ((rc = tape_3590_sense_medium(device)) != 0)			DBF_LH(3, "3590 medium sense returned %d\n", rc);	}	return rc;}/* * Cleanup device function */static voidtape_3590_cleanup_device(struct tape_device *device){	flush_scheduled_work();	tape_std_unassign(device);	kfree(device->discdata);	device->discdata = NULL;}/* * List of 3590 magnetic tape commands. */static tape_mtop_fn tape_3590_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_3590_mtseek,	[MTTELL]	 = tape_3590_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 3590. */static struct tape_discipline tape_discipline_3590 = {	.owner = THIS_MODULE,	.setup_device = tape_3590_setup_device,	.cleanup_device = tape_3590_cleanup_device,	.process_eov = tape_std_process_eov,	.irq = tape_3590_irq,	.read_block = tape_std_read_block,	.write_block = tape_std_write_block,#ifdef CONFIG_S390_TAPE_BLOCK	.bread = tape_3590_bread,	.free_bread = tape_3590_free_bread,	.check_locate = tape_3590_check_locate,#endif	.ioctl_fn = tape_3590_ioctl,	.mtop_array = tape_3590_mtop};static struct ccw_device_id tape_3590_ids[] = {	{CCW_DEVICE_DEVTYPE(0x3590, 0, 0x3590, 0), .driver_info = tape_3590},	{CCW_DEVICE_DEVTYPE(0x3592, 0, 0x3592, 0), .driver_info = tape_3592},	{ /* end of list */ }};static inttape_3590_online(struct ccw_device *cdev){	return tape_generic_online(cdev->dev.driver_data,				   &tape_discipline_3590);}static inttape_3590_offline(struct ccw_device *cdev){	return tape_generic_offline(cdev->dev.driver_data);}static struct ccw_driver tape_3590_driver = {	.name = "tape_3590",	.owner = THIS_MODULE,	.ids = tape_3590_ids,	.probe = tape_generic_probe,	.remove = tape_generic_remove,	.set_offline = tape_3590_offline,	.set_online = tape_3590_online,};/* * Setup discipline structure. */static inttape_3590_init(void){	int rc;	TAPE_DBF_AREA = debug_register("tape_3590", 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, "3590 init\n");	/* Register driver for 3590 tapes. */	rc = ccw_driver_register(&tape_3590_driver);	if (rc)		DBF_EVENT(3, "3590 init failed\n");	else		DBF_EVENT(3, "3590 registered\n");	return rc;}static voidtape_3590_exit(void){	ccw_driver_unregister(&tape_3590_driver);	debug_unregister(TAPE_DBF_AREA);}MODULE_DEVICE_TABLE(ccw, tape_3590_ids);MODULE_AUTHOR("(C) 2001,2006 IBM Corporation");MODULE_DESCRIPTION("Linux on zSeries channel attached 3590 tape device driver");MODULE_LICENSE("GPL");module_init(tape_3590_init);module_exit(tape_3590_exit);

⌨️ 快捷键说明

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