diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-05-12 23:48:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-05-12 23:48:34 +0000 |
commit | 7fd36ebeeec9244a7431bb010e6e3c5e4848a0d5 (patch) | |
tree | 5fb03a9aafdd1cec5f4f6ff7f1873174cb89b66c /drivers/s390/block/dasd_eckd.c | |
parent | ba2dacab305c598cd4c34a604f8e276bf5bab5ff (diff) |
Merge with Linux 2.3.99-pre8. Linus must hate me, too man patches ;-)
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 973 |
1 files changed, 973 insertions, 0 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c new file mode 100644 index 000000000..30e41f815 --- /dev/null +++ b/drivers/s390/block/dasd_eckd.c @@ -0,0 +1,973 @@ +/* + * File...........: linux/drivers/s390/block/dasd_eckd.c + * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + */ + +#include <linux/stddef.h> +#include <linux/kernel.h> + +#ifdef MODULE +#include <linux/module.h> +#endif /* MODULE */ + +#include <linux/malloc.h> +#include <linux/dasd.h> +#include <asm/io.h> + +#include <asm/irq.h> + +#include "dasd_types.h" +#include "dasd_ccwstuff.h" + + +#ifdef PRINTK_HEADER +#undef PRINTK_HEADER +#endif /* PRINTK_HEADER */ +#define PRINTK_HEADER "dasd(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) + +#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 + +#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a +#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09 + +#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16 +#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15 + +#define DASD_ECKD_CCW_READ_COUNT 0x12 +#define DASD_ECKD_CCW_READ 0x06 +#define DASD_ECKD_CCW_READ_MT 0x86 +#define DASD_ECKD_CCW_WRITE 0x05 +#define DASD_ECKD_CCW_WRITE_MT 0x85 +#define DASD_ECKD_CCW_READ_CKD 0x1e +#define DASD_ECKD_CCW_READ_CKD_MT 0x9e +#define DASD_ECKD_CCW_WRITE_CKD 0x1d +#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d + +typedef +struct { + __u16 cyl; + __u16 head; +} __attribute__ ((packed)) + +ch_t; + +typedef +struct { + __u16 cyl; + __u16 head; + __u32 sector; +} __attribute__ ((packed)) + +chs_t; + +typedef +struct { + __u16 cyl; + __u16 head; + __u8 record; +} __attribute__ ((packed)) + +chr_t; + +typedef +struct { + __u16 cyl; + __u16 head; + __u32 sector; +} geom_t; + +typedef struct { + struct { + struct { + unsigned char identifier:2; + unsigned char token_id:1; + unsigned char sno_valid:1; + unsigned char subst_sno:1; + unsigned char recNED:1; + unsigned char emuNED:1; + unsigned char reserved:1; + } __attribute__ ((packed)) flags; + __u8 descriptor; + __u8 dev_class; + __u8 reserved; + unsigned char dev_type[6]; + unsigned char dev_model[3]; + unsigned char HDA_manufacturer[3]; + unsigned char HDA_location[2]; + unsigned char HDA_seqno[12]; + __u16 ID; + } __attribute__ ((packed)) ned1; + struct { + struct { + unsigned char identifier:2; + unsigned char token_id:1; + unsigned char sno_valid:1; + unsigned char subst_sno:1; + unsigned char recNED:1; + unsigned char emuNED:1; + unsigned char reserved:1; + } __attribute__ ((packed)) flags; + __u8 descriptor; + __u8 reserved[2]; + unsigned char dev_type[6]; + unsigned char dev_model[3]; + unsigned char DASD_manufacturer[3]; + unsigned char DASD_location[2]; + unsigned char DASD_seqno[12]; + __u16 ID; + } __attribute__ ((packed)) ned2; + struct { + struct { + unsigned char identifier:2; + unsigned char token_id:1; + unsigned char sno_valid:1; + unsigned char subst_sno:1; + unsigned char recNED:1; + unsigned char emuNED:1; + unsigned char reserved:1; + } __attribute__ ((packed)) flags; + __u8 descriptor; + __u8 reserved[2]; + unsigned char cont_type[6]; + unsigned char cont_model[3]; + unsigned char cont_manufacturer[3]; + unsigned char cont_location[2]; + unsigned char cont_seqno[12]; + __u16 ID; + } __attribute__ ((packed)) ned3; + struct { + struct { + unsigned char identifier:2; + unsigned char token_id:1; + unsigned char sno_valid:1; + unsigned char subst_sno:1; + unsigned char recNED:1; + unsigned char emuNED:1; + unsigned char reserved:1; + } __attribute__ ((packed)) flags; + __u8 descriptor; + __u8 reserved[2]; + unsigned char cont_type[6]; + unsigned char empty[3]; + unsigned char cont_manufacturer[3]; + unsigned char cont_location[2]; + unsigned char cont_seqno[12]; + __u16 ID; + } __attribute__ ((packed)) ned4; + unsigned char ned5[32]; + unsigned char ned6[32]; + unsigned char ned7[32]; + struct { + struct { + unsigned char identifier:2; + unsigned char reserved:6; + } __attribute__ ((packed)) flags; + __u8 selector; + __u16 interfaceID; + __u32 reserved; + __u16 subsystemID; + struct { + unsigned char sp0:1; + unsigned char sp1:1; + unsigned char reserved:5; + unsigned char scluster:1; + } __attribute__ ((packed)) spathID; + __u8 unit_address; + __u8 dev_ID; + __u8 dev_address; + __u8 adapterID; + __u16 link_address; + struct { + unsigned char parallel:1; + unsigned char escon:1; + unsigned char reserved:1; + unsigned char ficon:1; + unsigned char reserved2:4; + } __attribute__ ((packed)) protocol_type; + struct { + unsigned char PID_in_236:1; + unsigned char reserved:7; + } __attribute__ ((packed)) format_flags; + __u8 log_dev_address; + unsigned char reserved2[12]; + } __attribute__ ((packed)) neq; + +} __attribute__ ((packed)) + +eckd_confdata_t; + +typedef +struct { + struct { + unsigned char perm:2; /* Permissions on this extent */ + unsigned char reserved:1; + unsigned char seek:2; /* Seek control */ + unsigned char auth:2; /* Access authorization */ + unsigned char pci:1; /* PCI Fetch mode */ + } __attribute__ ((packed)) mask; + struct { + unsigned char mode:2; /* Architecture mode */ + unsigned char ckd:1; /* CKD Conversion */ + unsigned char operation:3; /* Operation mode */ + unsigned char cfw:1; /* Cache fast write */ + unsigned char dfw:1; /* DASD fast write */ + } __attribute__ ((packed)) attributes; + __u16 short blk_size; /* Blocksize */ + __u16 fast_write_id; + __u8 unused; + __u8 reserved; + ch_t beg_ext; + ch_t end_ext; +} __attribute__ ((packed, aligned (32))) + +DE_eckd_data_t; + +typedef +struct { + struct { + unsigned char orientation:2; + unsigned char operation:6; + } __attribute__ ((packed)) operation; + struct { + unsigned char last_bytes_used:1; + unsigned char reserved:6; + unsigned char read_count_suffix:1; + } __attribute__ ((packed)) auxiliary; + __u8 unused; + __u8 count; + ch_t seek_addr; + chr_t search_arg; + __u8 sector; + __u16 length; +} __attribute__ ((packed, aligned (32))) + +LO_eckd_data_t; + +/* Stuff for handling home addresses */ +typedef struct { + __u8 skip_control[14]; + __u16 cell_number; + __u8 physical_addr[3]; + __u8 flag; + ch_t track_addr; + __u8 reserved; + __u8 key_length; + __u8 reserved2[2]; +} __attribute__ ((packed, aligned (32))) + +eckd_home_t; + + +static unsigned int +round_up_multiple (unsigned int no, unsigned int mult) +{ + int rem = no % mult; + return (rem ? no - rem + mult : no); +/* return (no % mult ? no - (no % mult) + mult : no); */ +} + +static unsigned int +ceil_quot (unsigned int d1, unsigned int d2) +{ + return (d1 + (d2 - 1)) / d2; +} + +static int +bytes_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 int +bytes_per_track (dasd_eckd_characteristics_t * rdc) +{ + return *(unsigned int *) (rdc->byte_per_track) >> 8; +} + +static unsigned int +recs_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 +void +define_extent (ccw1_t * de_ccw, + DE_eckd_data_t * data, + int trk, + int totrk, + int cmd, + dasd_information_t * info) +{ + ch_t geo, beg, end; + + geo.cyl = info->rdc_data->eckd.no_cyl; + geo.head = info->rdc_data->eckd.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 = CCW_DEFINE_EXTENT; + de_ccw->count = 16; + de_ccw->cda = (void *) virt_to_phys (data); + + 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_COUNT: + data->mask.perm = 0x1; + data->attributes.operation = 0x3; /* enable seq. caching */ + break; + case DASD_ECKD_CCW_WRITE: + case DASD_ECKD_CCW_WRITE_MT: + 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_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; + data->beg_ext.cyl = beg.cyl; + data->beg_ext.head = beg.head; + data->end_ext.cyl = end.cyl; + data->end_ext.head = end.head; +} + +static inline void +locate_record (ccw1_t * lo_ccw, + LO_eckd_data_t * data, + int trk, + int rec_on_trk, + int no_rec, + int cmd, + dasd_information_t * info) +{ + ch_t geo = + {info->rdc_data->eckd.no_cyl, + info->rdc_data->eckd.trk_per_cyl}; + ch_t seek = + {trk / (geo.head), trk % (geo.head)}; + int reclen = info->sizes.bp_block; + memset (lo_ccw, 0, sizeof (ccw1_t)); + lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; + lo_ccw->count = 16; + lo_ccw->cda = (void *) virt_to_phys (data); + + memset (data, 0, sizeof (LO_eckd_data_t)); + 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 = 0x3; + 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: + 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: + 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; + 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; + data->count += no_rec; +} + +void +dasd_eckd_print_error (devstat_t * stat) +{ + int sct, sl; + char *sense = stat->ii.sense.data; + PRINT_WARN ("IRQ on devno %x: with intparm:%x DS:0x%02x CS:0x%02x\n", + stat->devno, stat->intparm, stat->dstat, stat->cstat); + PRINT_WARN ("Failing CCW: %p\n", (ccw1_t *) stat->cpa); + for (sl = 0; sl < 4; sl++) { + PRINT_DEBUG ("Sense:"); + for (sct = 0; sct < 8; sct++) { + printk (" %2d:0x%02x", + 8 * sl + sct, sense[8 * sl + sct]); + } + printk ("\n"); + } + if (sense[27] & 0x80) { /* 32 Byte Sense Data */ + PRINT_INFO ("Sense Data is 32 Byte information\n"); + PRINT_INFO ("Format: %x Exception class %x\n", + sense[6] & 0x0f, sense[22] >> 4); + } else { /* 24 Byte Sense Data */ + PRINT_INFO ("Sense Data is 24 Byte information\n"); + PRINT_INFO ("FMT: %x MSG %x, %s MSGb to SYSOP\n", + sense[7] >> 4, sense[7] & 0x0f, + sense[1] & 0x10 ? "" : "no"); + } +} + +int +dasd_eckd_format_track (int di, int trk, int bs) +{ + int rc = 0; + int i; + int flags = 0x00; /* FORMAT_R0 = 0x01, FORMAT_HA = 0x03 */ + dasd_information_t * info=dasd_info[di]; + cqr_t *fcp; + DE_eckd_data_t *DE_data; + LO_eckd_data_t *LO_data; + eckd_count_t *ct_data; + eckd_count_t *r0_data; + ccw1_t *last_ccw; + int retries = 5; + + int rpt = recs_per_track (&(info->rdc_data->eckd), 0, bs); + int cyl = trk / info->rdc_data->eckd.trk_per_cyl; + int head = trk % info->rdc_data->eckd.trk_per_cyl; + + fcp = request_cqr (2 + 1 + rpt, + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t) + + (rpt + 1) * sizeof (eckd_count_t)); + fcp -> devindex=di; + DE_data = (DE_eckd_data_t *) fcp->data; + LO_data = (LO_eckd_data_t *) (((long) DE_data) + + sizeof (DE_eckd_data_t)); + r0_data = (eckd_count_t *) (((long) LO_data) + + sizeof (LO_eckd_data_t)); + ct_data = (eckd_count_t *) (((long) r0_data) + + sizeof (eckd_count_t)); + last_ccw = fcp->cpaddr; + switch (flags) { + case 0x03: + define_extent (last_ccw, DE_data, trk, trk, + DASD_ECKD_CCW_WRITE_HOME_ADDRESS, info); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, rpt, + DASD_ECKD_CCW_WRITE_HOME_ADDRESS, info); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + break; + case 0x01: + define_extent (last_ccw, DE_data, trk, trk, + DASD_ECKD_CCW_WRITE_RECORD_ZERO, info); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, rpt, + DASD_ECKD_CCW_WRITE_RECORD_ZERO, info); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + break; + case 0x00: + define_extent (last_ccw, DE_data, trk, trk, + DASD_ECKD_CCW_WRITE_CKD, info); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, rpt, + DASD_ECKD_CCW_WRITE_CKD, info); + LO_data->length = bs; + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + break; + default: + PRINT_WARN ("Unknown format flags...%d\n", flags); + return -EINVAL; + } + if (flags & 0x02) { + PRINT_WARN ("Unsupported format flag...%d\n", flags); + return -EINVAL; + } + if (flags & 0x01) { /* write record zero */ + memset (r0_data, 0, sizeof (eckd_count_t)); + r0_data->cyl = cyl; + r0_data->head = head; + r0_data->record = 0; + r0_data->kl = 0; + r0_data->dl = 8; + last_ccw->cmd_code = 0x03; + last_ccw->count = 8; + last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; + last_ccw->cda = (void *) virt_to_phys (r0_data); + last_ccw++; + } + /* write remaining records */ + for (i = 0; i < rpt; i++, last_ccw++) { + memset (ct_data + i, 0, sizeof (eckd_count_t)); + (ct_data + i)->cyl = cyl; + (ct_data + i)->head = head; + (ct_data + i)->record = i + 1; + (ct_data + i)->kl = 0; + (ct_data + i)->dl = bs; + last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; + last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; + last_ccw->count = 8; + last_ccw->cda = (void *) + virt_to_phys (ct_data + i); + } + (last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC); + fcp -> devindex = di; + fcp -> flags = DASD_DO_IO_SLEEP; + do { + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int irq; + int cs; + + irq = dasd_info[fcp->devindex]->info.irq; + s390irq_spin_lock_irqsave (irq, flags); + atomic_set(&fcp->status,CQR_STATUS_QUEUED); + rc = dasd_start_IO ( fcp ); + add_wait_queue (&dasd_waitq, &wait); + do { + current->state = TASK_UNINTERRUPTIBLE; + s390irq_spin_unlock_irqrestore (irq, flags); + schedule (); + s390irq_spin_lock_irqsave (irq, flags); + } while (((cs = atomic_read (&fcp->status)) != + CQR_STATUS_DONE) && + (cs != CQR_STATUS_ERROR)); + remove_wait_queue (&dasd_waitq, &wait); + s390irq_spin_unlock_irqrestore (irq, flags); + + retries --; + } while ( (rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)) && + retries); + if ((rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE))) + rc = -EIO; + release_cqr (fcp); + return rc; +} + +int +dasd_eckd_ck_devinfo (dev_info_t * info) +{ + return 0; +} + +cqr_t * +dasd_eckd_build_req (int devindex, + struct request * req) +{ + cqr_t *rw_cp = NULL; + ccw1_t *ccw; + + DE_eckd_data_t *DE_data; + LO_eckd_data_t *LO_data; + struct buffer_head *bh; + int rw_cmd; + dasd_information_t *info = dasd_info[devindex]; + int blk_per_trk = recs_per_track (&(info->rdc_data->eckd), + 0, info->sizes.bp_block); + int byt_per_blk = info->sizes.bp_block; + int noblk = req-> nr_sectors >> info->sizes.s2b_shift; + int btrk = (req->sector >> info->sizes.s2b_shift) / blk_per_trk; + int etrk = ((req->sector + req->nr_sectors - 1) >> + info->sizes.s2b_shift) / blk_per_trk; + + if ( ! noblk ) { + PRINT_ERR("No blocks to write...returning\n"); + return NULL; + } + + if (req->cmd == READ) { + rw_cmd = DASD_ECKD_CCW_READ_MT; + } else +#if DASD_PARANOIA > 2 + if (req->cmd == WRITE) +#endif /* DASD_PARANOIA */ + { + rw_cmd = DASD_ECKD_CCW_WRITE_MT; + } +#if DASD_PARANOIA > 2 + else { + PRINT_ERR ("Unknown command %d\n", req->cmd); + return NULL; + } +#endif /* DASD_PARANOIA */ + /* Build the request */ + rw_cp = request_cqr (2 + noblk, + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); + if ( ! rw_cp ) { + return NULL; + } + DE_data = rw_cp->data; + LO_data = rw_cp->data + sizeof (DE_eckd_data_t); + ccw = rw_cp->cpaddr; + + define_extent (ccw, DE_data, btrk, etrk, rw_cmd, info); + ccw->flags = CCW_FLAG_CC; + ccw++; + locate_record (ccw, LO_data, btrk, + (req->sector >> info->sizes.s2b_shift) % + blk_per_trk + 1, + req->nr_sectors >> info->sizes.s2b_shift, + rw_cmd, info); + ccw->flags = CCW_FLAG_CC; + for (bh = req->bh; bh; bh = bh->b_reqnext) { + long size; + for (size = 0; size < bh->b_size; size += byt_per_blk) { + ccw++; + ccw->flags = CCW_FLAG_CC; + ccw->cmd_code = rw_cmd; + ccw->count = byt_per_blk; + ccw->cda = (void *) virt_to_phys (bh->b_data + size); + } + } + ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC); + return rw_cp; +} + +cqr_t * +dasd_eckd_rw_label (int devindex, int rw, char *buffer) +{ + int cmd_code = 0x03; + dasd_information_t *info = dasd_info[devindex]; + cqr_t *cqr; + ccw1_t *ccw; + + switch (rw) { + case READ: + cmd_code = DASD_ECKD_CCW_READ; + break; + case WRITE: + cmd_code = DASD_ECKD_CCW_WRITE; + break; +#if DASD_PARANOIA > 2 + default: + INTERNAL_ERROR ("unknown cmd %d", rw); + return NULL; +#endif /* DASD_PARANOIA */ + } + cqr = request_cqr (3, sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); + ccw = cqr->cpaddr; + define_extent (ccw, cqr->data, 0, 0, cmd_code, info); + ccw->flags |= CCW_FLAG_CC; + ccw++; + locate_record (ccw, cqr->data + 1, 0, 2, 1, cmd_code, info); + ccw->flags |= CCW_FLAG_CC; + ccw++; + ccw->cmd_code = cmd_code; + ccw->flags |= CCW_FLAG_SLI; + ccw->count = sizeof (dasd_volume_label_t); + ccw->cda = (void *) virt_to_phys ((void *) buffer); + return cqr; + +} + +void +dasd_eckd_print_char (dasd_characteristics_t * i) +{ + dasd_eckd_characteristics_t * c = + (dasd_eckd_characteristics_t *)i; + PRINT_INFO ("%x/%x (%x/%x) Cyl: %d Head: %d Sec: %d \n", + c->dev_type, c->dev_model, + c->cu_type, c->cu_model.model, + c->no_cyl, c->trk_per_cyl, + c->sec_per_trk); + PRINT_INFO ("Estimate: %d Byte/trk %d byte/kByte %d kByte/trk \n", + bytes_per_track (c), + bytes_per_record (c, 0, 1024), + recs_per_track (c, 0, 1024)); +}; + +int +dasd_eckd_ck_char (dasd_characteristics_t * i) +{ + int rc = 0; + dasd_eckd_print_char (i); + return rc; +} + +int +dasd_eckd_format (int devindex, format_data_t * fdata) +{ + int rc = 0; + int i; + dasd_information_t *info = dasd_info[devindex]; + format_data_t fd; + + if (!fdata) { + fd.start_unit = 0; + fd.stop_unit = info->rdc_data->eckd.no_cyl * + info->rdc_data->eckd.trk_per_cyl - 1; + fd.blksize = 4096; + } else { + memcpy (&fd, fdata, sizeof (format_data_t)); + if ( fd.stop_unit == -1 ) { + fd.stop_unit = info->rdc_data->eckd.no_cyl * + info->rdc_data->eckd.trk_per_cyl - 1; + } + if ( fd.blksize == 0 ) { + fd.blksize = 4096; + } + } + PRINT_INFO("Formatting device %d from %d to %d with bs %d\n", + devindex,fd.start_unit,fd.stop_unit,fd.blksize); + if ( fd.start_unit > fd.stop_unit ) { + PRINT_WARN ("start unit .gt. stop unit\n"); + return -EINVAL; + } + if ( (fd.start_unit > info->rdc_data->eckd.no_cyl * + info->rdc_data->eckd.trk_per_cyl - 1) ) { + PRINT_WARN ("start unit beyond end of disk\n"); + return -EINVAL; + } + if ( (fd.stop_unit > info->rdc_data->eckd.no_cyl * + info->rdc_data->eckd.trk_per_cyl - 1) ) { + PRINT_WARN ("stop unit beyond end of disk\n"); + return -EINVAL; + } + switch (fd.blksize) { + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + PRINT_WARN ("invalid blocksize\n"); + return -EINVAL; + } + for (i = fd.start_unit; i <= fd.stop_unit; i++) { + /* print 20 messages per disk at all */ + if ( ! ( i % (info->rdc_data->eckd.trk_per_cyl * + (info->rdc_data->eckd.no_cyl / 20 ) ))) { + PRINT_INFO ("Format %d Cylinder: %d\n",devindex, + i/info->rdc_data->eckd.trk_per_cyl); + } + rc = dasd_eckd_format_track (devindex, i, fd.blksize); + if (rc) { + PRINT_WARN ("Formatting of Track %d failed...exiting\n", i); + break; + } + } + PRINT_INFO("Formated device %d from %d to %d with bs %d\n", + devindex,fd.start_unit,fd.stop_unit,fd.blksize); + return rc; +} + +cqr_t * +dasd_eckd_fill_sizes_first (int di) +{ + cqr_t *rw_cp = NULL; + ccw1_t *ccw; + DE_eckd_data_t *DE_data; + LO_eckd_data_t *LO_data; + dasd_information_t *info = dasd_info[di]; + eckd_count_t *count_data= &(info->private.eckd.count_data); + rw_cp = request_cqr (3, + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); + DE_data = rw_cp->data; + LO_data = rw_cp->data + sizeof (DE_eckd_data_t); + ccw = rw_cp->cpaddr; + define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, info); + ccw->flags = CCW_FLAG_CC; + ccw++; + locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, info); + ccw->flags = CCW_FLAG_CC; + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; + ccw->count = 8; + ccw->cda = (void *) __pa (count_data); + rw_cp->devindex = di; + atomic_set(&rw_cp->status,CQR_STATUS_FILLED); + return rw_cp; +} + +int dasd_eckd_fill_sizes_last (int devindex) +{ + int sb; + dasd_information_t *in = dasd_info[devindex]; + int bs = in->private.eckd.count_data.dl; + if (bs <= 0) { + PRINT_INFO("Cannot figure out blocksize. did you format the disk?\n"); + memset (&(in -> sizes), 0, sizeof(dasd_sizes_t )); + return -EMEDIUMTYPE; + } else { + in->sizes.bp_block = bs; + } + in->sizes.bp_sector = in->sizes.bp_block; + + in->sizes.b2k_shift = 0; /* bits to shift a block to get 1k */ + for (sb = 1024; sb < bs; sb = sb << 1) + in->sizes.b2k_shift++; + + in->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */ + for (sb = 512; sb < bs; sb = sb << 1) + in->sizes.s2b_shift++; + + in->sizes.blocks = in->rdc_data->eckd.no_cyl * + in->rdc_data->eckd.trk_per_cyl * + recs_per_track (&(in->rdc_data->eckd), 0, bs); + in->sizes.kbytes = in->sizes.blocks << in->sizes.b2k_shift; + + PRINT_INFO ("Verified: %d B/trk %d B/Blk(%d B) %d Blks/trk %d kB/trk \n", + bytes_per_track (&(in->rdc_data->eckd)), + bytes_per_record (&(in->rdc_data->eckd), 0, in->sizes.bp_block), + in->sizes.bp_block, + recs_per_track (&(in->rdc_data->eckd), 0, in->sizes.bp_block), + (recs_per_track (&(in->rdc_data->eckd), 0, in->sizes.bp_block) << + in->sizes.b2k_shift )); + return 0; +} + +dasd_operations_t dasd_eckd_operations = +{ + ck_devinfo: dasd_eckd_ck_devinfo, + get_req_ccw: dasd_eckd_build_req, + rw_label: dasd_eckd_rw_label, + ck_characteristics: dasd_eckd_ck_char, + fill_sizes_first: dasd_eckd_fill_sizes_first, + fill_sizes_last: dasd_eckd_fill_sizes_last, + dasd_format: dasd_eckd_format, +}; + +/* + * 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: nil + * tab-width: 8 + * End: + */ |