dasd_eckd.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 1,885 行 · 第 1/4 页
C
1,885 行
/* * File...........: linux/drivers/s390/block/dasd_eckd.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Horst Hummel <Horst.Hummel@de.ibm.com> * Carsten Otte <Cotte@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * * $Revision $ * * 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):"#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)#ifdef MODULE#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))MODULE_LICENSE("GPL");#endif#endifdasd_discipline_t dasd_eckd_discipline;typedef struct dasd_eckd_private_t { dasd_eckd_characteristics_t rdc_data; dasd_eckd_confdata_t conf_data; eckd_count_t count_area[5]; int uses_cdl; attrib_data_t attrib; /* e.g. cache operations */} dasd_eckd_private_t;#ifdef CONFIG_DASD_DYNAMICstaticdevreg_t dasd_eckd_known_devices[] = { { ci: { hc: {ctype:0x3880, dtype: 0x3390}}, 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: MESSAGE (KERN_ERR, "unknown formula%d", 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 voidcheck_XRC (ccw1_t *de_ccw, DE_eckd_data_t *data, dasd_device_t *device){ dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; /* switch on System Time Stamp - needed for XRC Support */ if (private->rdc_data.facilities.XRC_supported) { data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ data->ep_sys_time = get_clock (); de_ccw->count = sizeof (DE_eckd_data_t); de_ccw->flags |= CCW_FLAG_SLI; } return;} /* end check_XRC */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 = private->attrib.operation; 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 = private->attrib.operation; check_XRC (de_ccw, data, device); break; case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD_MT: data->attributes.operation = DASD_BYPASS_CACHE; check_XRC (de_ccw, data, device); 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 = DASD_BYPASS_CACHE; check_XRC (de_ccw, data, device); break; default: MESSAGE (KERN_ERR, "unknown opcode 0x%x", cmd); break; } data->attributes.mode = 0x3; /* ECKD */ if (private->rdc_data.cu_type == 0x2105 && !(private->uses_cdl && trk < 2) ) { data->ga_extended |= 0x40; } /* check for sequential prestage - enhance cylinder range */ if (data->attributes.operation == DASD_SEQ_PRESTAGE || data->attributes.operation == DASD_SEQ_ACCESS ) { if (end.cyl + private->attrib.nr_cyl < geo.cyl) { end.cyl += private->attrib.nr_cyl; DBF_DEV_EVENT (DBF_NOTICE, device, "Enhanced DE Cylinder from %x to %x", (totrk / geo.head), end.cyl); } else { end.cyl = (geo.cyl -1); DBF_DEV_EVENT (DBF_NOTICE, device, "Enhanced DE Cylinder from %x to " "End of device %x", (totrk / geo.head), end.cyl); } } 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; DBF_EVENT (DBF_INFO, "Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d", trk, rec_on_trk, no_rec, cmd, reclen); 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: MESSAGE (KERN_ERR, "unknown opcode 0x%x", 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)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?