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

📄 dasd_eckd.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  * File...........: linux/drivers/s390/block/dasd_eckd.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>                    Carsten Otte <Cotte@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * History of changes (starts July 2000) * 07/11/00 Enabled rotational position sensing * 07/14/00 Reorganized the format process for better ERP * 07/20/00 added experimental support for 2105 control unit (ESS) * 07/24/00 increased expiration time and added the missing zero * 08/07/00 added some bits to define_extent for ESS support * 09/20/00 added reserve and release ioctls * 10/04/00 changed RW-CCWS to R/W Key and Data * 10/10/00 reverted last change according to ESS exploitation * 10/10/00 now dequeuing init_cqr before freeing *ouch* * 26/10/00 fixed ITPM20144ASC (problems when accesing a device formatted by VIF) * 01/23/01 fixed kmalloc statement in dump_sense to be GFP_ATOMIC *          fixed partition handling and HDIO_GETGEO */#include <linux/config.h>#include <linux/stddef.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/hdreg.h>	/* HDIO_GETGEO                      */#include <linux/blk.h>#include <asm/debug.h>#include <asm/ccwcache.h>#include <asm/idals.h>#include <asm/ebcdic.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/s390dyn.h>#include "dasd_int.h"#include "dasd_eckd.h"#ifdef PRINTK_HEADER#undef PRINTK_HEADER#endif				/* PRINTK_HEADER */#define PRINTK_HEADER DASD_NAME"(eckd):"#undef CDL_PRINTK#define ECKD_C0(i) (i->home_bytes)#define ECKD_F(i) (i->formula)#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1))#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2))#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3))#define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0)#define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0)#define ECKD_F6(i) (i->factor6)#define ECKD_F7(i) (i->factor7)#define ECKD_F8(i) (i->factor8)dasd_discipline_t dasd_eckd_discipline;typedef structdasd_eckd_private_t {	dasd_eckd_characteristics_t rdc_data;	dasd_eckd_confdata_t conf_data;	eckd_count_t count_area[5];	int uses_cdl;} dasd_eckd_private_t;#ifdef CONFIG_DASD_DYNAMICstaticdevreg_t dasd_eckd_known_devices[] = {        {                ci: { hc: {ctype:0x3880, dtype: 3390}},                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE |                       DEVREG_TYPE_DEVCHARS),                oper_func:dasd_oper_handler        },        {                ci: { hc: {ctype:0x3990}},                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),                oper_func:dasd_oper_handler        },	{                ci: { hc: {ctype:0x2105}},                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),                oper_func:dasd_oper_handler        },	{                ci: { hc: {ctype:0x9343}},                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),                oper_func:dasd_oper_handler        }};#endifint sizes_trk0[] = { 28, 148, 84 };#define LABEL_SIZE 140static inline unsigned intround_up_multiple (unsigned int no, unsigned int mult){	int rem = no % mult;	return (rem ? no - rem + mult : no);}static inline unsigned intceil_quot (unsigned int d1, unsigned int d2){	return (d1 + (d2 - 1)) / d2;}static inline intbytes_per_record (dasd_eckd_characteristics_t * rdc, int kl,	/* key length */		  int dl /* data length */ ){	int bpr = 0;	switch (rdc->formula) {	case 0x01:{			unsigned int fl1, fl2;			fl1 = round_up_multiple (ECKD_F2 (rdc) + dl,						 ECKD_F1 (rdc));			fl2 = round_up_multiple (kl ? ECKD_F2 (rdc) + kl : 0,						 ECKD_F1 (rdc));			bpr = fl1 + fl2;			break;		}	case 0x02:{			unsigned int fl1, fl2, int1, int2;			int1 = ceil_quot (dl + ECKD_F6 (rdc),					  ECKD_F5 (rdc) << 1);			int2 = ceil_quot (kl + ECKD_F6 (rdc),					  ECKD_F5 (rdc) << 1);			fl1 = round_up_multiple (ECKD_F1 (rdc) *						 ECKD_F2 (rdc) +						 (dl + ECKD_F6 (rdc) +						  ECKD_F4 (rdc) * int1),						 ECKD_F1 (rdc));			fl2 = round_up_multiple (ECKD_F1 (rdc) *						 ECKD_F3 (rdc) +						 (kl + ECKD_F6 (rdc) +						  ECKD_F4 (rdc) * int2),						 ECKD_F1 (rdc));			bpr = fl1 + fl2;			break;		}	default:		INTERNAL_ERROR ("unknown formula%d\n", rdc->formula);	}	return bpr;}static inline unsigned intbytes_per_track (dasd_eckd_characteristics_t * rdc){	return *(unsigned int *) (rdc->byte_per_track) >> 8;}static inline unsigned intrecs_per_track (dasd_eckd_characteristics_t * rdc,		unsigned int kl, unsigned int dl){	int rpt = 0;	int dn;	switch (rdc->dev_type) {	case 0x3380:		if (kl)			return 1499 / (15 +				       7 + ceil_quot (kl + 12, 32) +				       ceil_quot (dl + 12, 32));		else			return 1499 / (15 + ceil_quot (dl + 12, 32));	case 0x3390:		dn = ceil_quot (dl + 6, 232) + 1;		if (kl) {			int kn = ceil_quot (kl + 6, 232) + 1;			return 1729 / (10 +				       9 + ceil_quot (kl + 6 * kn, 34) +				       9 + ceil_quot (dl + 6 * dn, 34));		} else			return 1729 / (10 + 9 + ceil_quot (dl + 6 * dn, 34));	case 0x9345:		dn = ceil_quot (dl + 6, 232) + 1;		if (kl) {			int kn = ceil_quot (kl + 6, 232) + 1;			return 1420 / (18 +				       7 + ceil_quot (kl + 6 * kn, 34) +				       ceil_quot (dl + 6 * dn, 34));		} else			return 1420 / (18 + 7 + ceil_quot (dl + 6 * dn, 34));	}	return rpt;}static inline intdefine_extent (ccw1_t * de_ccw,	       DE_eckd_data_t * data,	       int trk, int totrk, int cmd, dasd_device_t * device, ccw_req_t* cqr){        int rc=0;	ch_t geo, beg, end;	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;	geo.cyl = private->rdc_data.no_cyl;	geo.head = private->rdc_data.trk_per_cyl;	beg.cyl = trk / geo.head;	beg.head = trk % geo.head;	end.cyl = totrk / geo.head;	end.head = totrk % geo.head;	memset (de_ccw, 0, sizeof (ccw1_t));	de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;	de_ccw->count = 16;	if ((rc=dasd_set_normalized_cda (de_ccw, __pa (data), cqr, device)))                 return rc;	memset (data, 0, sizeof (DE_eckd_data_t));	switch (cmd) {	case DASD_ECKD_CCW_READ_HOME_ADDRESS:	case DASD_ECKD_CCW_READ_RECORD_ZERO:	case DASD_ECKD_CCW_READ:	case DASD_ECKD_CCW_READ_MT:	case DASD_ECKD_CCW_READ_CKD:	/* Fallthrough */	case DASD_ECKD_CCW_READ_CKD_MT:	case DASD_ECKD_CCW_READ_KD:	case DASD_ECKD_CCW_READ_KD_MT:	case DASD_ECKD_CCW_READ_COUNT:		data->mask.perm = 0x1;		data->attributes.operation = 0x3;	/* enable seq. caching */		break;	case DASD_ECKD_CCW_WRITE:	case DASD_ECKD_CCW_WRITE_MT:	case DASD_ECKD_CCW_WRITE_KD:	case DASD_ECKD_CCW_WRITE_KD_MT:		data->mask.perm = 0x02;		data->attributes.operation = 0x3;	/* enable seq. caching */		break;	case DASD_ECKD_CCW_WRITE_CKD:	case DASD_ECKD_CCW_WRITE_CKD_MT:		data->attributes.operation = 0x1;	/* format through cache */		break;	case DASD_ECKD_CCW_ERASE:	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:		data->mask.perm = 0x3;		data->mask.auth = 0x1;		data->attributes.operation = 0x1;	/* format through cache */		break;	default:		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);		break;	}	data->attributes.mode = 0x3;	if (private->rdc_data.cu_type == 0x2105	    && !(private->uses_cdl && trk < 2)	    ) {		data->reserved |= 0x40;	}	data->beg_ext.cyl = beg.cyl;	data->beg_ext.head = beg.head;	data->end_ext.cyl = end.cyl;	data->end_ext.head = end.head;        return rc;}static inline intlocate_record (ccw1_t * lo_ccw,	       LO_eckd_data_t * data,	       int trk,	       int rec_on_trk,	       int no_rec, int cmd, dasd_device_t * device, int reclen, ccw_req_t* cqr){        int rc=0;	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;	ch_t geo = { private->rdc_data.no_cyl,		private->rdc_data.trk_per_cyl	};	ch_t seek = { trk / (geo.head), trk % (geo.head) };	int sector = 0;#ifdef CDL_PRINTK	printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n", trk,		rec_on_trk, no_rec, cmd, reclen);#endif	memset (lo_ccw, 0, sizeof (ccw1_t));	lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;	lo_ccw->count = 16;	if ((rc=dasd_set_normalized_cda (lo_ccw, __pa (data), cqr, device)))                return rc;	memset (data, 0, sizeof (LO_eckd_data_t));        if (rec_on_trk) {                switch (private->rdc_data.dev_type) {                case 0x3390:{                        int dn, d;                        dn = ceil_quot (reclen + 6, 232);                        d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34);                        sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8;                        break;                }                case 0x3380:{                        int d;                        d = 7 + ceil_quot (reclen + 12, 32);                        sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;                        break;                }                case 0x9345:                default:                        sector = 0;                }        }        data->sector = sector;	data->count = no_rec;	switch (cmd) {	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:		data->operation.orientation = 0x3;		data->operation.operation = 0x03;		break;	case DASD_ECKD_CCW_READ_HOME_ADDRESS:		data->operation.orientation = 0x3;		data->operation.operation = 0x16;		break;	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:		data->operation.orientation = 0x1;		data->operation.operation = 0x03;		data->count++;		break;	case DASD_ECKD_CCW_READ_RECORD_ZERO:		data->operation.orientation = 0x3;		data->operation.operation = 0x16;		data->count++;		break;	case DASD_ECKD_CCW_WRITE:	case DASD_ECKD_CCW_WRITE_MT:	case DASD_ECKD_CCW_WRITE_KD:	case DASD_ECKD_CCW_WRITE_KD_MT:		data->auxiliary.last_bytes_used = 0x1;		data->length = reclen;		data->operation.operation = 0x01;		break;	case DASD_ECKD_CCW_WRITE_CKD:	case DASD_ECKD_CCW_WRITE_CKD_MT:		data->auxiliary.last_bytes_used = 0x1;		data->length = reclen;		data->operation.operation = 0x03;		break;	case DASD_ECKD_CCW_READ:	case DASD_ECKD_CCW_READ_MT:	case DASD_ECKD_CCW_READ_KD:	case DASD_ECKD_CCW_READ_KD_MT:		data->auxiliary.last_bytes_used = 0x1;		data->length = reclen;		data->operation.operation = 0x06;		break;	case DASD_ECKD_CCW_READ_CKD:	case DASD_ECKD_CCW_READ_CKD_MT:		data->auxiliary.last_bytes_used = 0x1;		data->length = reclen;		data->operation.operation = 0x16;		break;	case DASD_ECKD_CCW_READ_COUNT:		data->operation.operation = 0x06;		break;	case DASD_ECKD_CCW_ERASE:                data->length = reclen;                data->auxiliary.last_bytes_used = 0x1;		data->operation.operation = 0x0b;		break;	default:		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);	}	memcpy (&(data->seek_addr), &seek, sizeof (ch_t));	memcpy (&(data->search_arg), &seek, sizeof (ch_t));	data->search_arg.record = rec_on_trk;        return rc;}static intdasd_eckd_id_check (s390_dev_info_t * info){	if (info->sid_data.cu_type == 0x3990 ||	    info->sid_data.cu_type == 0x2105)		    if (info->sid_data.dev_type == 0x3390) return 0;	if (info->sid_data.cu_type == 0x3990 ||	    info->sid_data.cu_type == 0x2105)		    if (info->sid_data.dev_type == 0x3380) return 0;	if (info->sid_data.cu_type == 0x9343)		if (info->sid_data.dev_type == 0x9345)			return 0;	return -ENODEV;}static intdasd_eckd_check_characteristics (struct dasd_device_t *device){	int rc = 0;	void *conf_data;	void *rdc_data;	int conf_len;	dasd_eckd_private_t *private;	if (device == NULL) {		printk (KERN_WARNING PRINTK_HEADER			"Null device pointer passed to characteristics checker\n");                return -ENODEV;	}	device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL);	if (device->private == NULL) {		printk (KERN_WARNING PRINTK_HEADER			"memory allocation failed for private data\n");		rc = -ENOMEM;                goto fail;	}	private = (dasd_eckd_private_t *) device->private;	rdc_data = (void *) &(private->rdc_data);	rc = read_dev_chars (device->devinfo.irq, &rdc_data, 64);	if (rc) {		printk (KERN_WARNING PRINTK_HEADER			"Read device characteristics returned error %d\n", rc);                goto fail;        }	printk (KERN_INFO PRINTK_HEADER		"%04X on sch %d: %04X/%02X(CU:%04X/%02X) "                "Cyl:%d Head:%d Sec:%d\n",		device->devinfo.devno, device->devinfo.irq,		private->rdc_data.dev_type, private->rdc_data.dev_model,		private->rdc_data.cu_type, private->rdc_data.cu_model.model,		private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl,		private->rdc_data.sec_per_trk);	rc = read_conf_data (device->devinfo.irq, &conf_data, &conf_len,                             LPM_ANYPATH);        if (rc == -EOPNOTSUPP) {                rc = 0; /* this one is ok */        }	if (rc) {		printk (KERN_WARNING PRINTK_HEADER			"Read configuration data returned error %d\n", rc);                goto fail;	}        if (conf_data == NULL) {		printk (KERN_WARNING PRINTK_HEADER			"No configuration data retrieved\n");                goto out; /* no errror */	}         if (conf_len != sizeof (dasd_eckd_confdata_t)) {		printk (KERN_WARNING PRINTK_HEADER			"sizes of configuration data mismatch"                        "%d (read) vs %ld (expected)\n",			conf_len, sizeof (dasd_eckd_confdata_t));                goto out; /* no errror */	}         memcpy (&private->conf_data, conf_data,                 sizeof (dasd_eckd_confdata_t));        printk (KERN_INFO PRINTK_HEADER                "%04X on sch %d: %04X/%02X(CU:%04X/%02X): "                "Configuration data read\n",                device->devinfo.devno, device->devinfo.irq,                private->rdc_data.dev_type,                 private->rdc_data.dev_model,                private->rdc_data.cu_type,                 private->rdc_data.cu_model.model);        goto out; fail:        if ( rc ) {                kfree (device->private);                device->private = NULL;        } out:	return rc;}static inline intdasd_eckd_cdl_reclen (dasd_device_t * device, int recid){	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;	int byt_per_blk = device->sizes.bp_block;	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);	if (recid < 3)		return sizes_trk0[recid];	if (recid < blk_per_trk)		return byt_per_blk;	if (recid < 2 * blk_per_trk)		return LABEL_SIZE;	return byt_per_blk;}static ccw_req_t *dasd_eckd_init_analysis (struct dasd_device_t *device){	ccw_req_t *cqr = NULL;	ccw1_t *ccw;	DE_eckd_data_t *DE_data;	LO_eckd_data_t *LO_data;	dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;

⌨️ 快捷键说明

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