patch-2.4.8 linux/drivers/s390/block/dasd_fba.c

Next file: linux/drivers/s390/block/dasd_fba.h
Previous file: linux/drivers/s390/block/dasd_eckd.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c
@@ -12,19 +12,21 @@
 #include <linux/kernel.h>
 #include <asm/debug.h>
 
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/hdreg.h>	/* HDIO_GETGEO                      */
 #include <linux/blk.h>
+
 #include <asm/ccwcache.h>
 #include <asm/idals.h>
-#include <asm/dasd.h>
-
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
 
+#include "dasd_int.h"
 #include "dasd_fba.h"
+#include "dasd_3370_erp.h"
+#include "dasd_9336_erp.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
@@ -39,44 +41,38 @@
 dasd_discipline_t dasd_fba_discipline;
 
 typedef struct
-dasd_fba_private_t {
+    dasd_fba_private_t {
 	dasd_fba_characteristics_t rdc_data;
 } dasd_fba_private_t;
 
 #ifdef CONFIG_DASD_DYNAMIC
 static
-devreg_t dasd_fba_known_devices[] =
-{
+devreg_t dasd_fba_known_devices[] = {
 	{
-		ci:
-		{hc:
-		 {ctype:0x6310,
-                  dtype:0x9336}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                      DEVREG_MATCH_DEV_TYPE| 
-                      DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	},
+	      ci: { hc: {ctype:0x6310, dtype:0x9336}},
+	      flag:(DEVREG_MATCH_CU_TYPE |
+                    DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS),
+              oper_func:dasd_oper_handler
+        },
 	{
-		ci:
-		{hc:
-		 {ctype:0x3880,
-                  dtype:0x3370}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                      DEVREG_MATCH_DEV_TYPE| 
-                      DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	}
+                ci: { hc: {ctype:0x3880, dtype:0x3370}},
+                flag:(DEVREG_MATCH_CU_TYPE |
+                      DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        }
 };
 #endif
-static inline void
+static inline int
 define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
-	       int blksize, int beg, int nr)
+	       int blksize, int beg, int nr, ccw_req_t* cqr,
+               dasd_device_t* device)
 {
+        int rc=0;
 	memset (DE_data, 0, sizeof (DE_fba_data_t));
 	ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
 	ccw->count = 16;
-	set_normalized_cda (ccw, __pa (DE_data));
+	if (rc=dasd_set_normalized_cda (ccw, __pa (DE_data), cqr, device))
+                return rc;
 	if (rw == WRITE)
 		(DE_data->mask).perm = 0x0;
 	else if (rw == READ)
@@ -86,16 +82,17 @@
 	DE_data->blk_size = blksize;
 	DE_data->ext_loc = beg;
 	DE_data->ext_end = nr - 1;
+        return rc;
 }
 
 static inline void
 locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr,
-	       int block_ct)
+	       int block_ct, ccw_req_t* cqr, dasd_device_t* device)
 {
 	memset (LO_data, 0, sizeof (LO_fba_data_t));
 	ccw->cmd_code = DASD_FBA_CCW_LOCATE;
 	ccw->count = 8;
-	set_normalized_cda (ccw, __pa (LO_data));
+	dasd_set_normalized_cda (ccw, __pa (LO_data), cqr, device);
 	if (rw == WRITE)
 		LO_data->operation.cmd = 0x5;
 	else if (rw == READ)
@@ -109,9 +106,9 @@
 static int
 dasd_fba_id_check (s390_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 == 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;
@@ -127,37 +124,43 @@
 
 	if (device == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
-		   "Null device pointer passed to characteristics checker\n");
-		return -ENODEV;
+			"Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
 	}
-        if ( device->private != NULL ) {
-                kfree(device->private);
-        }
-        device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL);
+	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;
+		printk (KERN_WARNING PRINTK_HEADER
+			"memory allocation failed for private data\n");
+                rc = -ENOMEM;
+                goto fail;
 	}
 	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);
-            kfree(private);
-            device->private=NULL;
-            return 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) %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,
+		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;
+        goto out;
+ fail:
+        if ( rc ) {
+                kfree(device->private);
+                device->private = NULL;
+        }
+        
+ out:
+	return rc;
 }
 
 static int
@@ -187,7 +190,7 @@
 		device->sizes.s2b_shift++;
 
 	device->sizes.blocks = (private->rdc_data.blk_bdsa);
-        device->sizes.pt_block = 1;
+	device->sizes.pt_block = 1;
 
 	return rc;
 }
@@ -221,7 +224,7 @@
 	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;
+		    return dasd_era_none;
 
 	switch (device->devinfo.sid_data.dev_model) {
 	case 0x3370:
@@ -236,17 +239,16 @@
 static dasd_erp_action_fn_t
 dasd_fba_erp_action (ccw_req_t * cqr)
 {
-	return default_erp_action;
+	return dasd_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;
+	if (cqr->function == dasd_default_erp_action)
+		return dasd_default_erp_postaction;
 	printk (KERN_WARNING PRINTK_HEADER
-		"unknown ERP action %p\n",
-		cqr->function);
+		"unknown ERP action %p\n", cqr->function);
 	return NULL;
 }
 
@@ -255,7 +257,7 @@
 {
 	ccw_req_t *rw_cp = NULL;
 	int rw_cmd;
-	int bhct, i;
+	int bhct, i = 0;
 	long size;
 	ccw1_t *ccw;
 	DE_fba_data_t *DE_data;
@@ -263,7 +265,7 @@
 	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->cmd == READ) {
 		rw_cmd = DASD_FBA_CCW_READ;
 	} else if (req->cmd == WRITE) {
@@ -273,20 +275,30 @@
 		return NULL;
 	}
 	/* Build the request */
-	/* count bhs to prevent errors, when bh smaller than block */
+	/* count hs to prevent errors, when bh smaller than block */
+        bh = req -> bh;
 	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++;
-	}
-
-	rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
-				    1 + 2*bhct,
-				    sizeof (DE_fba_data_t) +
-				    bhct*sizeof (LO_fba_data_t));
+        while ( bh != NULL ) {
+                if (bh->b_size < byt_per_blk) {
+                        BUG();
+                }
+                bhct += bh->b_size >> (device->sizes.s2b_shift+9);
+                bh = bh->b_reqnext;
+        }
+        
+        if (private->rdc_data.mode.bits.data_chain) {
+                rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
+                                            2 + bhct,
+                                            sizeof (DE_fba_data_t) +
+                                            sizeof (LO_fba_data_t),
+                                            device);
+        } else {
+                rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
+                                            1 + 2 * bhct,
+                                            sizeof (DE_fba_data_t) +
+                                            bhct * sizeof (LO_fba_data_t),
+                                            device);
+        }
 	if (!rw_cp) {
 		return NULL;
 	}
@@ -294,64 +306,77 @@
 	LO_data = rw_cp->data + sizeof (DE_fba_data_t);
 	ccw = rw_cp->cpaddr;
 
-	define_extent (ccw, DE_data, req->cmd, byt_per_blk,
-		       req->sector, req->nr_sectors);
+	if (define_extent (ccw, DE_data, req->cmd, byt_per_blk,
+                           req->sector, req->nr_sectors, rw_cp, device)) {
+                goto clear_rw_cp;
+        }
 	ccw->flags |= CCW_FLAG_CC;
-
-	for (i = 0, bh = req->bh; bh;) {
-		if (bh->b_size > byt_per_blk) {
-			for (size = 0; size < bh->b_size; size += byt_per_blk) {
-                                ccw++;
-                                locate_record (ccw, LO_data, req->cmd, i, 1);
-                                ccw->flags |= CCW_FLAG_CC;
-				ccw++;
-                                ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI;
-				ccw->cmd_code = rw_cmd;
-				ccw->count = byt_per_blk;
-				set_normalized_cda (ccw, __pa (bh->b_data + size));
-                                i++;
-                                LO_data++;
-			}
-			bh = bh->b_reqnext;
-		} else {	/* group N bhs to fit into byt_per_blk */
-			for (size = 0; bh != NULL && size < byt_per_blk;) {
-                                ccw++;
-                                locate_record (ccw, LO_data, req->cmd, i, 1);
+        ccw ++;
+        locate_record (ccw, LO_data, req->cmd, 0, 
+                       private->rdc_data.mode.bits.data_chain ? bhct : 1, rw_cp, device);
+        if (ccw->cda == 0) {
+                goto clear_rw_cp;
+        }
+        ccw->flags |= CCW_FLAG_CC;
+        
+        bh = req -> bh;
+        i = 0;
+        while ( bh != NULL ) {
+                for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                        ccw ++;
+                        ccw->cmd_code = rw_cmd;
+                        ccw->count = byt_per_blk;
+                        if (dasd_set_normalized_cda (ccw,__pa (bh->b_data + size), rw_cp, device)) {
+                                goto clear_rw_cp;
+                        }
+                        if (private->rdc_data.mode.bits.data_chain) {
+                                ccw->flags |= CCW_FLAG_DC;
+                        } else {
                                 ccw->flags |= CCW_FLAG_CC;
-				ccw++;
-				if (private->rdc_data.mode.bits.data_chain) {
-					ccw->flags |= CCW_FLAG_DC|CCW_FLAG_SLI;
-				} else {
-					PRINT_WARN ("Cannot chain chunks smaller than one block\n");
-					ccw_free_request (rw_cp);
-					return NULL;
-				}
-				ccw->cmd_code = rw_cmd;
-				ccw->count = bh->b_size;
-				set_normalized_cda (ccw, __pa (bh->b_data));
-				size += bh->b_size;
-				bh = bh->b_reqnext;
-                                i++;
-                                LO_data++;
-			}
-			ccw->flags &= ~CCW_FLAG_DC;
-			ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI;
-			if (size != byt_per_blk) {
-				PRINT_WARN ("Cannot fulfill request smaller than block\n");
-				ccw_free_request (rw_cp);
-				return NULL;
-			}
-		}
-	}
+                        }
+                }
+                bh = bh->b_reqnext;
+                if ( bh != NULL &&
+                     !(private->rdc_data.mode.bits.data_chain)) {
+                        ccw++;
+                        i++;
+                        LO_data++;
+                        locate_record (ccw, LO_data, req->cmd, i, 1, rw_cp, device);
+                        if (ccw->cda == 0) {
+                                goto clear_rw_cp;
+                        }
+                        ccw->flags |= CCW_FLAG_CC;
+                }
+        }
 	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
 
 	rw_cp->device = device;
 	rw_cp->expires = 5 * TOD_MIN;		/* 5 minutes */
 	rw_cp->req = req;
 	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
+        goto out;
+ clear_rw_cp:
+        dasd_free_request (rw_cp, device);
+        rw_cp = NULL;
+ out:
 	return rw_cp;
 }
 
+static int
+dasd_fba_fill_info (dasd_device_t * device, dasd_information_t * info)
+{
+	int rc = 0;
+	info->label_block = 1;
+	info->FBA_layout = 1;
+	info->characteristics_size = sizeof (dasd_fba_characteristics_t);
+	memcpy (info->characteristics,
+		&((dasd_fba_private_t *) device->private)->rdc_data,
+		sizeof (dasd_fba_characteristics_t));
+	info->confdata_size = 0;
+	return rc;
+}
+
+
 static char *
 dasd_fba_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
 {
@@ -367,25 +392,26 @@
 	return page;
 }
 
-dasd_discipline_t dasd_fba_discipline =
-{
+dasd_discipline_t dasd_fba_discipline = {
+        owner: THIS_MODULE,
 	name:"FBA ",
 	ebcname:"FBA ",
-	max_blocks:((PAGE_SIZE >> 1)/sizeof(ccw1_t)-1),
+	max_blocks:((PAGE_SIZE >> 1) / sizeof (ccw1_t) - 1),
 	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,
+	term_IO:dasd_term_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_handler:dasd_int_handler,
+	fill_info:dasd_fba_fill_info,
 };
 
-
 int
 dasd_fba_init (void)
 {
@@ -393,18 +419,22 @@
 	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);
-#ifdef CONFIG_DASD_DYNAMIC 
-        {
-            int i;
-            for (i = 0; i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t); i++) {
-		printk (KERN_INFO PRINTK_HEADER
-			"We are interested in: CU %04X/%02x\n",
-			dasd_fba_known_devices[i].ci.hc.ctype,
-			dasd_fba_known_devices[i].ci.hc.cmode);
-		s390_device_register (&dasd_fba_known_devices[i]);
-            }
-        }
+	dasd_discipline_add (&dasd_fba_discipline);
+#ifdef CONFIG_DASD_DYNAMIC
+	{
+		int i;
+		for (i = 0;
+		     i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t);
+		     i++) {
+			printk (KERN_INFO PRINTK_HEADER
+				"We are interested in: Dev %04X/%02X @ CU %04X/%02x\n",
+				dasd_fba_known_devices[i].ci.hc.dtype,
+				dasd_fba_known_devices[i].ci.hc.dmode,
+				dasd_fba_known_devices[i].ci.hc.ctype,
+				dasd_fba_known_devices[i].ci.hc.cmode);
+			s390_device_register (&dasd_fba_known_devices[i]);
+		}
+	}
 #endif				/* CONFIG_DASD_DYNAMIC */
         return rc;
 }
@@ -417,16 +447,31 @@
         {
 	int i;
         for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) {
-                printk (KERN_INFO PRINTK_HEADER
-                        "We were interested in: CU %04X/%02x\n",
-                        dasd_fba_known_devices[i].ci.hc.ctype,
-                        dasd_fba_known_devices[i].ci.hc.cmode);
                 s390_device_unregister(&dasd_fba_known_devices[i]);
         }
         }
 #endif /* CONFIG_DASD_DYNAMIC */
-        dasd_discipline_deq(&dasd_fba_discipline);
+        dasd_discipline_del(&dasd_fba_discipline);
+}
+
+#ifdef MODULE
+int
+init_module (void)
+{
+	int rc = 0;
+	rc = dasd_fba_init ();
+	return rc;
 }
+
+void
+cleanup_module (void)
+{
+	dasd_fba_cleanup ();
+	return;
+}
+#endif
+
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)