patch-2.2.17 linux/drivers/s390/block/dasd_fba.c
Next file: linux/drivers/s390/block/dasd_fba.h
Previous file: linux/drivers/s390/block/dasd_erp.h
Back to the patch index
Back to the overall index
- Lines: 563
- Date:
Mon Sep 4 18:39:20 2000
- Orig file:
v2.2.16/drivers/s390/block/dasd_fba.c
- Orig date:
Mon Sep 4 18:37:42 2000
diff -u --recursive --new-file v2.2.16/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c
@@ -1,68 +1,51 @@
+/*
+ * File...........: linux/drivers/s390/block/dasd_fba.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 <asm/debug.h>
#include <linux/malloc.h>
-#include <linux/dasd.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */
+#include <linux/blk.h>
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
+#include <asm/ebcdic.h>
#include <asm/io.h>
-
#include <asm/irq.h>
-#include "dasd_types.h"
-#include "dasd_ccwstuff.h"
+#include "dasd.h"
+#include "dasd_fba.h"
-#define DASD_FBA_CCW_LOCATE 0x43
-#define DASD_FBA_CCW_READ 0x42
-#define DASD_FBA_CCW_WRITE 0x41
#ifdef PRINTK_HEADER
#undef PRINTK_HEADER
#endif /* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(fba):"
+#define PRINTK_HEADER DASD_NAME"(fba):"
-typedef
-struct {
- struct {
- unsigned char perm:2; /* Permissions on this extent */
- unsigned char zero:2; /* Must be zero */
- unsigned char da:1; /* usually zero */
- unsigned char diag:1; /* allow diagnose */
- unsigned char zero2:2; /* zero */
- } __attribute__ ((packed)) mask;
- unsigned char zero; /* Must be zero */
- unsigned short blk_size; /* Blocksize */
- unsigned long ext_loc; /* Extent locator */
- unsigned long ext_beg; /* logical number of block 0 in extent */
- unsigned long ext_end; /* logocal number of last block in extent */
-} __attribute__ ((packed, aligned (32)))
-
-DE_fba_data_t;
-
-typedef
-struct {
- struct {
- unsigned char zero:4;
- unsigned char cmd:4;
- } __attribute__ ((packed)) operation;
- unsigned char auxiliary;
- unsigned short blk_ct;
- unsigned long blk_nr;
-} __attribute__ ((packed, aligned (32)))
+#define DASD_FBA_CCW_WRITE 0x41
+#define DASD_FBA_CCW_READ 0x42
+#define DASD_FBA_CCW_LOCATE 0x43
+#define DASD_FBA_CCW_DEFINE_EXTENT 0x63
+
+dasd_discipline_t dasd_fba_discipline;
-LO_fba_data_t;
+typedef struct
+dasd_fba_private_t {
+ dasd_fba_characteristics_t rdc_data;
+} dasd_fba_private_t;
-static void
+static inline void
define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
int blksize, int beg, int nr)
{
memset (DE_data, 0, sizeof (DE_fba_data_t));
- ccw->cmd_code = CCW_DEFINE_EXTENT;
+ ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
ccw->count = 16;
ccw->cda = (void *) __pa (DE_data);
if (rw == WRITE)
@@ -76,7 +59,7 @@
DE_data->ext_end = nr - 1;
}
-static void
+static inline void
locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr,
int block_ct)
{
@@ -94,46 +77,174 @@
LO_data->blk_ct = block_ct;
}
-int
-dasd_fba_ck_devinfo (dev_info_t * info)
+
+static int
+dasd_fba_id_check ( dev_info_t *info )
{
+ if ( info->sid_data.cu_type == 0x3880 )
+ if ( info->sid_data.dev_type == 0x3370 )
+ return 0;
+ if ( info->sid_data.cu_type == 0x6310 )
+ if ( info->sid_data.dev_type == 0x9336 )
return 0;
+ return -ENODEV;
}
-cqr_t *
-dasd_fba_build_req (int devindex,
- struct request * req)
+static int
+dasd_fba_check_characteristics (struct dasd_device_t *device)
{
- cqr_t *rw_cp = NULL;
- ccw1_t *ccw;
+ int rc = -ENODEV;
+ void *rdc_data;
+ dasd_fba_private_t *private;
+
+ if ( device == NULL ) {
+ printk ( KERN_WARNING PRINTK_HEADER
+ "Null device pointer passed to characteristics checker\n");
+ return -ENODEV;
+ }
+ if ( device->private == NULL ) {
+ device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL);
+ if ( device->private == NULL ) {
+ printk ( KERN_WARNING PRINTK_HEADER
+ "memory allocation failed for private data\n");
+ return -ENOMEM;
+ }
+ }
+ private = (dasd_fba_private_t *)device->private;
+ rdc_data = (void *)&(private->rdc_data);
+ rc = read_dev_chars (device->devinfo.irq, &rdc_data , 32);
+ if ( rc ) {
+ printk ( KERN_WARNING PRINTK_HEADER
+ "Read device characteristics returned error %d\n",rc);
+ return rc;
+ }
+ printk ( KERN_INFO PRINTK_HEADER
+ "%04X on sch %d: %04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)\n",
+ device->devinfo.devno, device->devinfo.irq,
+ device->devinfo.sid_data.dev_type, device->devinfo.sid_data.dev_model,
+ device->devinfo.sid_data.cu_type, device->devinfo.sid_data.cu_model,
+ (private->rdc_data.blk_bdsa *
+ (private->rdc_data.blk_size >> 9)) >> 11,
+ private->rdc_data.blk_size);
+ return 0;
+}
- DE_fba_data_t *DE_data;
- LO_fba_data_t *LO_data;
- struct buffer_head *bh;
+static int
+dasd_fba_do_analysis (struct dasd_device_t *device)
+{
+ int rc = 0;
+ int sb;
+ dasd_fba_private_t *private = (dasd_fba_private_t *)device->private;
+ int bs = private->rdc_data.blk_size;
+
+ memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
+ switch ( bs ) {
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ device->sizes.bp_block = bs;
+ break;
+ default:
+ printk ( KERN_INFO PRINTK_HEADER
+ "/dev/%s (%04X): unknown blocksize %d\n",
+ device->name, device->devinfo.devno,bs);
+ return -EMEDIUMTYPE;
+ }
+ device->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */
+ for (sb = 512; sb < bs; sb = sb << 1)
+ device->sizes.s2b_shift++;
+
+ device->sizes.blocks = (private->rdc_data.blk_bdsa);
+
+ return rc;
+}
+
+static int
+dasd_fba_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo)
+{
+ int rc = 0;
+ unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift;
+ unsigned long tracks = sectors >> 6;
+ unsigned long trk_rem = sectors & ((1<<6)-1);
+ unsigned long cyls = tracks >> 4;
+ unsigned long cyls_rem = tracks & ((1<<4)-1);
+
+ switch(device->sizes.bp_block) {
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ break;
+ default:
+ return -EINVAL;
+ }
+ geo->cylinders = cyls;
+ geo->heads = 16;
+ geo->sectors = 128 >> device->sizes.s2b_shift;
+ geo->start = 1;
+ return rc;
+}
+
+static dasd_era_t
+dasd_fba_examine_error (ccw_req_t *cqr, devstat_t * stat)
+{
+ dasd_device_t *device = (dasd_device_t *)cqr->device;
+ if (stat->cstat == 0x00 &&
+ stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+ return dasd_era_none;
+
+ switch (device->devinfo.sid_data.dev_model) {
+ case 0x3370:
+ return dasd_3370_erp_examine (cqr, stat);
+ case 0x9336:
+ return dasd_9336_erp_examine (cqr, stat);
+ default:
+ return dasd_era_recover;
+ }
+}
+
+static dasd_erp_action_fn_t
+dasd_fba_erp_action ( ccw_req_t * cqr )
+{
+ return default_erp_action;
+}
+
+static dasd_erp_postaction_fn_t
+dasd_fba_erp_postaction (ccw_req_t * cqr)
+{
+ if ( cqr -> function == default_erp_action)
+ return default_erp_postaction;
+ printk ( KERN_WARNING PRINTK_HEADER
+ "unknown ERP action %p\n",
+ cqr -> function);
+ return NULL;
+}
+
+static ccw_req_t *
+dasd_fba_build_cp_from_req (dasd_device_t *device, struct request *req)
+{
+ ccw_req_t *rw_cp = NULL;
int rw_cmd;
- int byt_per_blk = dasd_info[devindex]->sizes.bp_block;
int bhct;
long size;
+ ccw1_t *ccw;
+ DE_fba_data_t *DE_data;
+ LO_fba_data_t *LO_data;
+ struct buffer_head *bh;
+ dasd_fba_private_t *private = (dasd_fba_private_t *)device->private;
+ int byt_per_blk = device->sizes.bp_block;
- if (!req->nr_sectors) {
- PRINT_ERR ("No blocks to write...returning\n");
- return NULL;
- }
if (req->cmd == READ) {
rw_cmd = DASD_FBA_CCW_READ;
- } else
-#if DASD_PARANOIA > 2
- if (req->cmd == WRITE)
-#endif /* DASD_PARANOIA */
- {
+ } else if (req->cmd == WRITE) {
rw_cmd = DASD_FBA_CCW_WRITE;
- }
-#if DASD_PARANOIA > 2
- else {
+ } else {
PRINT_ERR ("Unknown command %d\n", req->cmd);
return NULL;
}
-#endif /* DASD_PARANOIA */
+ /* Build the request */
+ /* count bhs to prevent errors, when bh smaller than block */
bhct = 0;
for (bh = req->bh; bh; bh = bh->b_reqnext) {
if (bh->b_size > byt_per_blk)
@@ -143,8 +254,8 @@
bhct++;
}
- /* Build the request */
- rw_cp = request_cqr (2 + bhct,
+ rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
+ 2 + bhct,
sizeof (DE_fba_data_t) +
sizeof (LO_fba_data_t));
if (!rw_cp) {
@@ -160,11 +271,12 @@
ccw++;
locate_record (ccw, LO_data, req->cmd, 0, req->nr_sectors);
ccw->flags = CCW_FLAG_CC;
+
for (bh = req->bh; bh;) {
if (bh->b_size > byt_per_blk) {
for (size = 0; size < bh->b_size; size += byt_per_blk) {
ccw++;
- if (dasd_info[devindex]->rdc_data->fba.mode.bits.data_chain) {
+ if (private->rdc_data.mode.bits.data_chain) {
ccw->flags = CCW_FLAG_DC;
} else {
ccw->flags = CCW_FLAG_CC;
@@ -177,11 +289,11 @@
} else { /* group N bhs to fit into byt_per_blk */
for (size = 0; bh != NULL && size < byt_per_blk;) {
ccw++;
- if (dasd_info[devindex]->rdc_data->fba.mode.bits.data_chain) {
+ if (private->rdc_data.mode.bits.data_chain) {
ccw->flags = CCW_FLAG_DC;
} else {
PRINT_WARN ("Cannot chain chunks smaller than one block\n");
- release_cqr (rw_cp);
+ ccw_free_request (rw_cp);
return NULL;
}
ccw->cmd_code = rw_cmd;
@@ -193,164 +305,80 @@
ccw->flags = CCW_FLAG_CC;
if (size != byt_per_blk) {
PRINT_WARN ("Cannot fulfill request smaller than block\n");
- release_cqr (rw_cp);
+ ccw_free_request (rw_cp);
return NULL;
}
}
}
ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
+
+ rw_cp->device = device;
+ rw_cp->expires = 5 * 0xf424000; /* 5 seconds */
+ rw_cp->req = req;
+ atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED);
return rw_cp;
}
-void
-dasd_fba_print_char (dasd_characteristics_t * ct)
-{
- dasd_fba_characteristics_t *c =
- (dasd_fba_characteristics_t *) ct;
- PRINT_INFO ("%d blocks of %d bytes %d MB\n",
- c->blk_bdsa, c->blk_size,
- (c->blk_bdsa * (c->blk_size >> 9)) >> 11);
- PRINT_INFO ("%soverrun, %s mode, data chains %sallowed\n"
- "%sremovable, %sshared\n",
- (c->mode.bits.overrunnable ? "" : "no "),
- (c->mode.bits.burst_byte ? "burst" : "byte"),
- (c->mode.bits.data_chain ? "" : "not "),
- (c->features.bits.removable ? "" : "not "),
- (c->features.bits.shared ? "" : "not "));
-};
-
-int
-dasd_fba_ck_char (dasd_characteristics_t * rdc)
+static char *
+dasd_fba_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
{
- int rc = 0;
- dasd_fba_print_char (rdc);
- return rc;
+ char *page = (char *)get_free_page(GFP_KERNEL);
+ int len;
+ if ( page == NULL ) {
+ return NULL;
}
-cqr_t *
-dasd_fba_fill_sizes_first (int di)
-{
- cqr_t *rw_cp = NULL;
- ccw1_t *ccw;
- DE_fba_data_t *DE_data;
- LO_fba_data_t *LO_data;
- dasd_information_t *info = dasd_info[di];
- static char buffer[8];
-
- dasd_info[di]->sizes.label_block = 1;
+ len = sprintf ( page, KERN_WARNING PRINTK_HEADER
+ "device %04X on irq %d: I/O status report:\n",
+ device->devinfo.devno,device->devinfo.irq);
+
- rw_cp = request_cqr (3,
- sizeof (DE_fba_data_t) +
- sizeof (LO_fba_data_t));
- DE_data = rw_cp->data;
- LO_data = rw_cp->data + sizeof (DE_fba_data_t);
- ccw = rw_cp->cpaddr;
- define_extent (ccw, DE_data, READ, info->sizes.bp_block, 1, 1);
- ccw->flags = CCW_FLAG_CC;
- ccw++;
- locate_record (ccw, LO_data, READ, 0, 1);
- ccw->flags = CCW_FLAG_CC;
- ccw++;
- ccw->cmd_code = DASD_FBA_CCW_READ;
- ccw->flags = CCW_FLAG_SLI;
- ccw->count = 8;
- ccw->cda = (void *) __pa (buffer);
- rw_cp->devindex = di;
- atomic_set (&rw_cp->status, CQR_STATUS_FILLED);
- return rw_cp;
+ return page;
}
-int
-dasd_fba_fill_sizes_last (int devindex)
-{
- int rc = 0;
- int sb;
- dasd_information_t *info = dasd_info[devindex];
-
- info->sizes.bp_sector = info->rdc_data->fba.blk_size;
- info->sizes.bp_block = info->sizes.bp_sector;
-
- info->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */
- for (sb = 512; sb < info->sizes.bp_sector; sb = sb << 1)
- info->sizes.s2b_shift++;
-
- info->sizes.blocks = (info->rdc_data->fba.blk_bdsa);
-
- if (info->sizes.s2b_shift >= 1)
- info->sizes.kbytes = info->sizes.blocks <<
- (info->sizes.s2b_shift - 1);
- else
- info->sizes.kbytes = info->sizes.blocks >>
- (-(info->sizes.s2b_shift - 1));
-
- return rc;
-}
+dasd_discipline_t dasd_fba_discipline = {
+ name : "FBA ",
+ ebcname : "FBA ",
+ id_check: dasd_fba_id_check,
+ check_characteristics: dasd_fba_check_characteristics,
+ do_analysis: dasd_fba_do_analysis,
+ fill_geometry: dasd_fba_fill_geometry,
+ start_IO: dasd_start_IO,
+ examine_error: dasd_fba_examine_error,
+ erp_action: dasd_fba_erp_action,
+ erp_postaction: dasd_fba_erp_postaction,
+ build_cp_from_req: dasd_fba_build_cp_from_req,
+ dump_sense: dasd_fba_dump_sense,
+ int_handler: dasd_int_handler
+};
int
-dasd_fba_format (int devindex, format_data_t * fdata)
-{
+dasd_fba_init( void ) {
int rc = 0;
+ printk ( KERN_INFO PRINTK_HEADER
+ "%s discipline initializing\n", dasd_fba_discipline.name);
+ ASCEBC(dasd_fba_discipline.ebcname,4);
+ dasd_discipline_enq(&dasd_fba_discipline);
+
return rc;
}
+/*
+ * 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:
+ */
-void
-dasd_fba_fill_geometry (int di, struct hd_geometry *geo)
-{
- int bfactor, nr_sectors, sec_size;
- int trk_cap, trk_low, trk_high, tfactor, nr_trks, trk_size;
- int cfactor, nr_cyls, cyl_size;
- int remainder;
-
- dasd_information_t *info = dasd_info[di];
- PRINT_INFO ("FBA has no geometry! Faking one...\n%s", "");
-
- /* determine the blocking factor of sectors */
- for (bfactor = 8; bfactor > 0; bfactor--) {
- remainder = info->rdc_data->fba.blk_bdsa % bfactor;
- PRINT_INFO ("bfactor %d remainder %d\n", bfactor, remainder);
- if (!remainder)
- break;
- }
- nr_sectors = info->rdc_data->fba.blk_bdsa / bfactor;
- sec_size = info->rdc_data->fba.blk_size * bfactor;
-
- geo -> sectors = bfactor;
- /* determine the nr of sectors per track */
- trk_cap = (64 * 1 << 10) / sec_size; /* 64k in sectors */
- trk_low = trk_cap * 2 / 3;
- trk_high = trk_cap * 4 / 3;
- for (tfactor = trk_high; tfactor > trk_low; tfactor--) {
- PRINT_INFO ("remainder %d\n", remainder);
- remainder = nr_sectors % bfactor;
- if (!remainder)
- break;
- }
- nr_trks = nr_sectors / tfactor;
- trk_size = sec_size * tfactor;
-
- /* determine the nr of trks per cylinder */
- for (cfactor = 31; cfactor > 0; cfactor--) {
- PRINT_INFO ("remainder %d\n", remainder);
- remainder = nr_trks % bfactor;
- if (!remainder)
- break;
- }
- nr_cyls = nr_trks / cfactor;
- sec_size = info->rdc_data->fba.blk_size * bfactor;
-
- geo -> heads = nr_trks;
- geo -> cylinders = nr_cyls;
- geo -> start = info->sizes.label_block + 1;
-}
-
-dasd_operations_t dasd_fba_operations =
-{
- ck_devinfo:dasd_fba_ck_devinfo,
- get_req_ccw:dasd_fba_build_req,
- ck_characteristics:dasd_fba_ck_char,
- fill_sizes_first:dasd_fba_fill_sizes_first,
- fill_sizes_last:dasd_fba_fill_sizes_last,
- dasd_format:dasd_fba_format,
- fill_geometry:dasd_fba_fill_geometry
-};
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)