dasd_eckd.c

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

C
1,725
字号
	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);	cqr->retries = 0;	cqr->expires = 2 * HZ;	cqr->buildclk = get_clock();	cqr->status = DASD_CQR_FILLED;	rc = dasd_sleep_on_immediatly(cqr);	dasd_sfree_request(cqr, cqr->device);	return rc;}/* * Reserve device ioctl. * Options are set to 'synchronous wait for interrupt' and * 'timeout the request'. This leads to a terminate IO if  * the interrupt is outstanding for a certain time.  */static intdasd_eckd_reserve(struct dasd_device *device){	struct dasd_ccw_req *cqr;	int rc;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,				   1, 32, device);	if (IS_ERR(cqr)) {		DEV_MESSAGE(KERN_WARNING, device, "%s",			    "Could not allocate initialization request");		return PTR_ERR(cqr);	}	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;        cqr->cpaddr->flags |= CCW_FLAG_SLI;        cqr->cpaddr->count = 32;	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;	cqr->device = device;	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);	cqr->retries = 0;	cqr->expires = 2 * HZ;	cqr->buildclk = get_clock();	cqr->status = DASD_CQR_FILLED;	rc = dasd_sleep_on_immediatly(cqr);	dasd_sfree_request(cqr, cqr->device);	return rc;}/* * Steal lock ioctl - unconditional reserve device. * Buils a channel programm to break a device's reservation.  * (unconditional reserve) */static intdasd_eckd_steal_lock(struct dasd_device *device){	struct dasd_ccw_req *cqr;	int rc;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,				   1, 32, device);	if (IS_ERR(cqr)) {		DEV_MESSAGE(KERN_WARNING, device, "%s",			    "Could not allocate initialization request");		return PTR_ERR(cqr);	}	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK;        cqr->cpaddr->flags |= CCW_FLAG_SLI;        cqr->cpaddr->count = 32;	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;	cqr->device = device;	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);	cqr->retries = 0;	cqr->expires = 2 * HZ;	cqr->buildclk = get_clock();	cqr->status = DASD_CQR_FILLED;	rc = dasd_sleep_on_immediatly(cqr);	dasd_sfree_request(cqr, cqr->device);	return rc;}/* * Read performance statistics */static intdasd_eckd_performance(struct dasd_device *device, void __user *argp){	struct dasd_psf_prssd_data *prssdp;	struct dasd_rssd_perf_stats_t *stats;	struct dasd_ccw_req *cqr;	struct ccw1 *ccw;	int rc;	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,				   1 /* PSF */  + 1 /* RSSD */ ,				   (sizeof (struct dasd_psf_prssd_data) +				    sizeof (struct dasd_rssd_perf_stats_t)),				   device);	if (IS_ERR(cqr)) {		DEV_MESSAGE(KERN_WARNING, device, "%s",			    "Could not allocate initialization request");		return PTR_ERR(cqr);	}	cqr->device = device;	cqr->retries = 0;	cqr->expires = 10 * HZ;	/* Prepare for Read Subsystem Data */	prssdp = (struct dasd_psf_prssd_data *) cqr->data;	memset(prssdp, 0, sizeof (struct dasd_psf_prssd_data));	prssdp->order = PSF_ORDER_PRSSD;	prssdp->suborder = 0x01;	/* Perfomance Statistics */	prssdp->varies[1] = 0x01;	/* Perf Statistics for the Subsystem */	ccw = cqr->cpaddr;	ccw->cmd_code = DASD_ECKD_CCW_PSF;	ccw->count = sizeof (struct dasd_psf_prssd_data);	ccw->flags |= CCW_FLAG_CC;	ccw->cda = (__u32)(addr_t) prssdp;	/* Read Subsystem Data - Performance Statistics */	stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);	memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t));	ccw++;	ccw->cmd_code = DASD_ECKD_CCW_RSSD;	ccw->count = sizeof (struct dasd_rssd_perf_stats_t);	ccw->cda = (__u32)(addr_t) stats;	cqr->buildclk = get_clock();	cqr->status = DASD_CQR_FILLED;	rc = dasd_sleep_on(cqr);	if (rc == 0) {		/* Prepare for Read Subsystem Data */		prssdp = (struct dasd_psf_prssd_data *) cqr->data;		stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);		if (copy_to_user(argp, stats,				 sizeof(struct dasd_rssd_perf_stats_t)))			rc = -EFAULT;	}	dasd_sfree_request(cqr, cqr->device);	return rc;}/* * Get attributes (cache operations) * Returnes the cache attributes used in Define Extend (DE). */static intdasd_eckd_get_attrib(struct dasd_device *device, void __user *argp){	struct dasd_eckd_private *private =		(struct dasd_eckd_private *)device->private;	struct attrib_data_t attrib = private->attrib;	int rc;        if (!capable(CAP_SYS_ADMIN))                return -EACCES;	if (!argp)                return -EINVAL;	rc = 0;	if (copy_to_user(argp, (long *) &attrib,			 sizeof (struct attrib_data_t)))		rc = -EFAULT;	return rc;}/* * Set attributes (cache operations) * Stores the attributes for cache operation to be used in Define Extend (DE). */static intdasd_eckd_set_attrib(struct dasd_device *device, void __user *argp){	struct dasd_eckd_private *private =		(struct dasd_eckd_private *)device->private;	struct attrib_data_t attrib;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	if (!argp)		return -EINVAL;	if (copy_from_user(&attrib, argp, sizeof(struct attrib_data_t)))		return -EFAULT;	private->attrib = attrib;	DEV_MESSAGE(KERN_INFO, device,		    "cache operation mode set to %x (%i cylinder prestage)",		    private->attrib.operation, private->attrib.nr_cyl);	return 0;}static intdasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp){	switch (cmd) {	case BIODASDGATTR:		return dasd_eckd_get_attrib(device, argp);	case BIODASDSATTR:		return dasd_eckd_set_attrib(device, argp);	case BIODASDPSRD:		return dasd_eckd_performance(device, argp);	case BIODASDRLSE:		return dasd_eckd_release(device);	case BIODASDRSRV:		return dasd_eckd_reserve(device);	case BIODASDSLCK:		return dasd_eckd_steal_lock(device);	default:		return -ENOIOCTLCMD;	}}/* * Print sense data and related channel program. * Parts are printed because printk buffer is only 1024 bytes. */static voiddasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,		     struct irb *irb){	char *page;	struct ccw1 *act, *end, *last;	int len, sl, sct, count;	page = (char *) get_zeroed_page(GFP_ATOMIC);	if (page == NULL) {		DEV_MESSAGE(KERN_ERR, device, " %s",			    "No memory to dump sense data");		return;	}	len = sprintf(page, KERN_ERR PRINTK_HEADER		      " I/O status report for device %s:\n",		      device->cdev->dev.bus_id);	len += sprintf(page + len, KERN_ERR PRINTK_HEADER		       " in req: %p CS: 0x%02X DS: 0x%02X\n", req,		       irb->scsw.cstat, irb->scsw.dstat);	len += sprintf(page + len, KERN_ERR PRINTK_HEADER		       " device %s: Failing CCW: %p\n",		       device->cdev->dev.bus_id,		       (void *) (addr_t) irb->scsw.cpa);	if (irb->esw.esw0.erw.cons) {		for (sl = 0; sl < 4; sl++) {			len += sprintf(page + len, KERN_ERR PRINTK_HEADER				       " Sense(hex) %2d-%2d:",				       (8 * sl), ((8 * sl) + 7));			for (sct = 0; sct < 8; sct++) {				len += sprintf(page + len, " %02x",					       irb->ecw[8 * sl + sct]);			}			len += sprintf(page + len, "\n");		}		if (irb->ecw[27] & DASD_SENSE_BIT_0) {			/* 24 Byte Sense Data */			len += sprintf(page + len, KERN_ERR PRINTK_HEADER				       " 24 Byte: %x MSG %x, "				       "%s MSGb to SYSOP\n",				       irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,				       irb->ecw[1] & 0x10 ? "" : "no");		} else {			/* 32 Byte Sense Data */			len += sprintf(page + len, KERN_ERR PRINTK_HEADER				       " 32 Byte: Format: %x "				       "Exception class %x\n",				       irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);		}	} else {	        len += sprintf(page + len, KERN_ERR PRINTK_HEADER			       " SORRY - NO VALID SENSE AVAILABLE\n");	}	MESSAGE_LOG(KERN_ERR, "%s",		    page + sizeof(KERN_ERR PRINTK_HEADER));	/* dump the Channel Program */	/* print first CCWs (maximum 8) */	act = req->cpaddr;        for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);	end = min(act + 8, last);	len = sprintf(page, KERN_ERR PRINTK_HEADER		      " Related CP in req: %p\n", req);	while (act <= end) {		len += sprintf(page + len, KERN_ERR PRINTK_HEADER			       " CCW %p: %08X %08X DAT:",			       act, ((int *) act)[0], ((int *) act)[1]);		for (count = 0; count < 32 && count < act->count;		     count += sizeof(int))			len += sprintf(page + len, " %08X",				       ((int *) (addr_t) act->cda)				       [(count>>2)]);		len += sprintf(page + len, "\n");		act++;	}	MESSAGE_LOG(KERN_ERR, "%s",		    page + sizeof(KERN_ERR PRINTK_HEADER));	/* print failing CCW area */	len = 0;	if (act <  ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) {		act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2;		len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");	}	end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last);	while (act <= end) {		len += sprintf(page + len, KERN_ERR PRINTK_HEADER			       " CCW %p: %08X %08X DAT:",			       act, ((int *) act)[0], ((int *) act)[1]);		for (count = 0; count < 32 && count < act->count;		     count += sizeof(int))			len += sprintf(page + len, " %08X",				       ((int *) (addr_t) act->cda)				       [(count>>2)]);		len += sprintf(page + len, "\n");		act++;	}	/* print last CCWs */	if (act <  last - 2) {		act = last - 2;		len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");	}	while (act <= last) {		len += sprintf(page + len, KERN_ERR PRINTK_HEADER			       " CCW %p: %08X %08X DAT:",			       act, ((int *) act)[0], ((int *) act)[1]);		for (count = 0; count < 32 && count < act->count;		     count += sizeof(int))			len += sprintf(page + len, " %08X",				       ((int *) (addr_t) act->cda)				       [(count>>2)]);		len += sprintf(page + len, "\n");		act++;	}	if (len > 0)		MESSAGE_LOG(KERN_ERR, "%s",			    page + sizeof(KERN_ERR PRINTK_HEADER));	free_page((unsigned long) page);}/* * max_blocks is dependent on the amount of storage that is available * in the static io buffer for each device. Currently each device has * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In * addition we have one define extent ccw + 16 bytes of data and one * locate record ccw + 16 bytes of data. That makes: * (8192 - 24 - 136 - 8 - 16 - 8 - 16) / 16 = 499 blocks at maximum. * We want to fit two into the available memory so that we can immediately * start the next request if one finishes off. That makes 249.5 blocks * for one request. Give a little safety and the result is 240. */static struct dasd_discipline dasd_eckd_discipline = {	.owner = THIS_MODULE,	.name = "ECKD",	.ebcname = "ECKD",	.max_blocks = 240,	.check_device = dasd_eckd_check_characteristics,	.do_analysis = dasd_eckd_do_analysis,	.fill_geometry = dasd_eckd_fill_geometry,	.start_IO = dasd_start_IO,	.term_IO = dasd_term_IO,	.format_device = dasd_eckd_format_device,	.examine_error = dasd_eckd_examine_error,	.erp_action = dasd_eckd_erp_action,	.erp_postaction = dasd_eckd_erp_postaction,	.build_cp = dasd_eckd_build_cp,	.free_cp = dasd_eckd_free_cp,	.dump_sense = dasd_eckd_dump_sense,	.fill_info = dasd_eckd_fill_info,	.ioctl = dasd_eckd_ioctl,};static int __initdasd_eckd_init(void){	int ret;	ASCEBC(dasd_eckd_discipline.ebcname, 4);	ret = ccw_driver_register(&dasd_eckd_driver);	if (!ret)		dasd_generic_auto_online(&dasd_eckd_driver);	return ret;}static void __exitdasd_eckd_cleanup(void){	ccw_driver_unregister(&dasd_eckd_driver);}module_init(dasd_eckd_init);module_exit(dasd_eckd_cleanup);/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only.  This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4  * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * indent-tabs-mode: 1 * tab-width: 8 * End: */

⌨️ 快捷键说明

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