patch-2.2.16 linux/drivers/s390/block/dasd_mdsk.c
Next file: linux/drivers/s390/block/dasd_mdsk.h
Previous file: linux/drivers/s390/block/dasd_fba.c
Back to the patch index
Back to the overall index
- Lines: 367
- Date:
Wed Jun 7 14:26:43 2000
- Orig file:
v2.2.15/linux/drivers/s390/block/dasd_mdsk.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN v2.2.15/linux/drivers/s390/block/dasd_mdsk.c linux/drivers/s390/block/dasd_mdsk.c
@@ -0,0 +1,366 @@
+#include <linux/dasd.h>
+#include <linux/malloc.h>
+#include <linux/ctype.h>
+#include "dasd_types.h"
+#include "dasd_ccwstuff.h"
+#include "dasd_mdsk.h"
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif /* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd(mdsk):"
+
+int dasd_is_accessible (int devno);
+void dasd_insert_range (int start, int end);
+
+/*
+ * The device characteristics function
+ */
+static __inline__ int
+dia210 (void *devchar)
+{
+ int rc;
+
+ asm volatile (" lr 2,%1\n"
+ " .long 0x83200210\n"
+ " ipm %0\n"
+ " srl %0,28"
+ :"=d" (rc)
+ :"d" ((void *) __pa (devchar))
+ :"2");
+ return rc;
+}
+
+static __inline__ int
+dia250 (void *iob, int cmd)
+{
+ int rc;
+
+ asm volatile (" lr 2,%1\n"
+ " lr 3,%2\n"
+ " .long 0x83230250\n"
+ " lr %0,3"
+ :"=d" (rc)
+ :"d" ((void *) __pa (iob)), "d" (cmd)
+ :"2", "3");
+ return rc;
+}
+
+/*
+ * Init of minidisk device
+ */
+
+static __inline__ int
+mdsk_init_io (int di, int blocksize, int offset, int size)
+{
+ mdsk_init_io_t *iib = &(dasd_info[di]->private.mdsk.iib);
+ int rc;
+
+ memset (iib, 0, sizeof (mdsk_init_io_t));
+
+ iib->dev_nr = dasd_info[di]->info.devno;
+ iib->block_size = blocksize;
+ iib->offset = offset;
+ iib->start_block = 0;
+ iib->end_block = size;
+
+ rc = dia250 (iib, INIT_BIO);
+
+ return rc;
+}
+
+/*
+ * release of minidisk device
+ */
+
+static __inline__ int
+mdsk_term_io (int di)
+{
+ mdsk_init_io_t *iib = &(dasd_info[di]->private.mdsk.iib);
+ int rc;
+
+ memset (iib, 0, sizeof (mdsk_init_io_t));
+ iib->dev_nr = dasd_info[di]->info.devno;
+ rc = dia250 (iib, TERM_BIO);
+ return rc;
+}
+
+void dasd_do_chanq (void);
+void dasd_schedule_bh (void (*func) (void));
+int register_dasd_last (int di);
+
+int
+dasd_mdsk_start_IO (cqr_t * cqr)
+{
+ int rc;
+ mdsk_rw_io_t *iob = &(dasd_info[cqr->devindex]->private.mdsk.iob);
+
+ iob->dev_nr = dasd_info[cqr->devindex]->info.devno;
+ iob->key = 0;
+ iob->flags = 2;
+ iob->block_count = cqr->cplength >> 1;
+ iob->interrupt_params = (u32) cqr;
+ iob->bio_list = __pa (cqr->cpaddr);
+
+ asm volatile ("STCK %0":"=m" (cqr->startclk));
+ rc = dia250 (iob, RW_BIO);
+ if (rc > 8) {
+ PRINT_WARN ("dia250 returned CC %d\n", rc);
+ ACS (cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_ERROR);
+ } else {
+ ACS (cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
+ atomic_dec (&chanq_tasks);
+ }
+ return rc;
+}
+
+void
+do_dasd_mdsk_interrupt (struct pt_regs *regs, __u16 code)
+{
+ int intparm = S390_lowcore.ext_params;
+ char status = *((char *) S390_lowcore.ext_params + 5);
+ cqr_t *cqr = (cqr_t *) intparm;
+ if (!intparm)
+ return;
+ if (cqr->magic != MDSK_MAGIC) {
+ panic ("unknown magic number\n");
+ }
+ asm volatile ("STCK %0":"=m" (cqr->stopclk));
+ if (atomic_read (&dasd_info[cqr->devindex]->status) ==
+ DASD_INFO_STATUS_DETECTED) {
+ register_dasd_last (cqr->devindex);
+ }
+ switch (status) {
+ case 0x00:
+ ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
+ break;
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ default:
+ ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+ atomic_inc (&dasd_info[cqr->devindex]->
+ queue.dirty_requests);
+ break;
+ }
+ atomic_inc (&chanq_tasks);
+ dasd_schedule_bh (dasd_do_chanq);
+}
+
+cqr_t *
+dasd_mdsk_build_req (int devindex,
+ struct request *req)
+{
+ cqr_t *rw_cp = NULL;
+ struct buffer_head *bh;
+ int rw_cmd;
+ dasd_information_t *info = dasd_info[devindex];
+ int noblk = req->nr_sectors >> info->sizes.s2b_shift;
+ int byt_per_blk = info->sizes.bp_block;
+ int block;
+ mdsk_bio_t *bio;
+ int bhct;
+ long size;
+
+ if (!noblk) {
+ PRINT_ERR ("No blocks to write...returning\n");
+ return NULL;
+ }
+ if (req->cmd == READ) {
+ rw_cmd = MDSK_READ_REQ;
+ } else
+#if DASD_PARANOIA > 2
+ if (req->cmd == WRITE)
+#endif /* DASD_PARANOIA */
+ {
+ rw_cmd = MDSK_WRITE_REQ;
+ }
+#if DASD_PARANOIA > 2
+ else {
+ PRINT_ERR ("Unknown command %d\n", req->cmd);
+ return NULL;
+ }
+#endif /* DASD_PARANOIA */
+ bhct = 0;
+ for (bh = req->bh; bh; bh = bh->b_reqnext) {
+ if (bh->b_size > byt_per_blk)
+ for (size = 0; size < bh->b_size; size += byt_per_blk)
+ bhct++;
+ else
+ bhct++;
+ }
+ /* Build the request */
+ rw_cp = request_cqr (MDSK_BIOS (bhct), 0);
+ if (!rw_cp) {
+ return NULL;
+ }
+ rw_cp->magic = MDSK_MAGIC;
+ bio = (mdsk_bio_t *) (rw_cp->cpaddr);
+
+ block = req->sector >> info->sizes.s2b_shift;
+ for (bh = req->bh; bh; bh = bh->b_reqnext) {
+ if (bh->b_size >= byt_per_blk) {
+ memset (bio, 0, sizeof (mdsk_bio_t));
+ for (size = 0; size < bh->b_size; size += byt_per_blk) {
+ bio->type = rw_cmd;
+ bio->block_number = block + 1;
+ bio->buffer = __pa (bh->b_data + size);
+ bio++;
+ block++;
+ }
+ } else {
+ PRINT_WARN ("Cannot fulfill request smaller than block\n");
+ release_cqr (rw_cp);
+ return NULL;
+ }
+ }
+ return rw_cp;
+}
+
+int
+dasd_mdsk_ck_devinfo (dev_info_t * info)
+{
+ int rc = 0;
+
+ dasd_mdsk_characteristics_t devchar =
+ {0,};
+
+ devchar.dev_nr = info->devno;
+ devchar.rdc_len = sizeof (dasd_mdsk_characteristics_t);
+
+ if (dia210 (&devchar) != 0) {
+ return -ENODEV;
+ }
+ if (devchar.vdev_class == DEV_CLASS_FBA ||
+ devchar.vdev_class == DEV_CLASS_ECKD ||
+ devchar.vdev_class == DEV_CLASS_CKD) {
+ return 0;
+ } else {
+ return -ENODEV;
+ }
+ return rc;
+}
+
+int
+dasd_mdsk_ck_characteristics (dasd_characteristics_t * dchar)
+{
+ int rc = 0;
+ dasd_mdsk_characteristics_t *devchar =
+ (dasd_mdsk_characteristics_t *) dchar;
+
+ if (dia210 (devchar) != 0) {
+ return -ENODEV;
+ }
+ if (devchar->vdev_class != DEV_CLASS_FBA &&
+ devchar->vdev_class != DEV_CLASS_ECKD &&
+ devchar->vdev_class != DEV_CLASS_CKD) {
+ return -ENODEV;
+ }
+ return rc;
+}
+
+cqr_t *
+dasd_mdsk_fill_sizes_first (int di)
+{
+ cqr_t *cqr = NULL;
+ dasd_information_t *info = dasd_info[di];
+ mdsk_bio_t *bio;
+ int bsize;
+ int rc;
+ /* Figure out position of label block */
+ if (info->rdc_data->mdsk.vdev_class == DEV_CLASS_FBA) {
+ info->sizes.label_block = 1;
+ } else if (info->rdc_data->mdsk.vdev_class == DEV_CLASS_ECKD ||
+ info->rdc_data->mdsk.vdev_class == DEV_CLASS_CKD) {
+ dasd_info[di]->sizes.label_block = 2;
+ } else {
+ return NULL;
+ }
+
+ /* figure out blocksize of device */
+ mdsk_term_io (di);
+ for (bsize = 512; bsize <= PAGE_SIZE; bsize = bsize << 1) {
+ rc = mdsk_init_io (di, bsize, 0, 64);
+ if (rc <= 4) {
+ break;
+ }
+ }
+ if (bsize > PAGE_SIZE) {
+ PRINT_INFO ("Blocksize larger than 4096??\n");
+ rc = mdsk_term_io (di);
+ return NULL;
+ }
+ dasd_info[di]->sizes.bp_sector = bsize;
+
+ info->private.mdsk.label = (long *) get_free_page (GFP_KERNEL);
+ cqr = request_cqr (MDSK_BIOS (1), 0);
+ cqr->magic = MDSK_MAGIC;
+ bio = (mdsk_bio_t *) (cqr->cpaddr);
+ memset (bio, 0, sizeof (mdsk_bio_t));
+ bio->type = MDSK_READ_REQ;
+ bio->block_number = info->sizes.label_block + 1;
+ bio->buffer = __pa (info->private.mdsk.label);
+ cqr->devindex = di;
+ atomic_set (&cqr->status, CQR_STATUS_FILLED);
+
+ return cqr;
+}
+
+int
+dasd_mdsk_fill_sizes_last (int di)
+{
+ int sb;
+ dasd_information_t *info = dasd_info[di];
+ long *label = info->private.mdsk.label;
+ int bs = info->private.mdsk.iib.block_size;
+
+ info->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */
+ for (sb = 512; sb < bs; sb = sb << 1)
+ info->sizes.s2b_shift++;
+
+ if (label[3] != bs) {
+ PRINT_WARN ("%04X mismatching blocksizes\n", info->info.devno);
+ atomic_set (&dasd_info[di]->status,
+ DASD_INFO_STATUS_DETECTED);
+ return -EINVAL;
+ }
+ if (label[0] != 0xc3d4e2f1) { /* CMS1 */
+ PRINT_WARN ("%04X is not CMS formatted\n", info->info.devno);
+ }
+ if (label[13] == 0) {
+ PRINT_WARN ("%04X is not reserved\n", info->info.devno);
+ }
+ /* defaults for first partition */
+ info->private.mdsk.setup.size =
+ (label[7] - 1 - label[13]) * (label[3] >> 9) >> 1;
+ info->private.mdsk.setup.blksize = label[3];
+ info->private.mdsk.setup.offset = label[13] + 1;
+
+ /* real size of the volume */
+ info->sizes.bp_block = label[3];
+ info->sizes.kbytes = label[7] * (label[3] >> 9) >> 1;
+
+ if (info->sizes.s2b_shift >= 1)
+ info->sizes.blocks = info->sizes.kbytes >>
+ (info->sizes.s2b_shift - 1);
+ else
+ info->sizes.blocks = info->sizes.kbytes <<
+ (-(info->sizes.s2b_shift - 1));
+
+ PRINT_INFO ("%ld kBytes in %d blocks of %d Bytes\n",
+ info->sizes.kbytes,
+ info->sizes.blocks,
+ info->sizes.bp_sector);
+ return 0;
+
+}
+
+dasd_operations_t dasd_mdsk_operations =
+{
+ ck_devinfo:dasd_mdsk_ck_devinfo,
+ get_req_ccw:dasd_mdsk_build_req,
+ ck_characteristics:dasd_mdsk_ck_characteristics,
+ fill_sizes_first:dasd_mdsk_fill_sizes_first,
+ fill_sizes_last:dasd_mdsk_fill_sizes_last,
+ dasd_format:NULL
+};
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)