patch-2.4.22 linux-2.4.22/drivers/s390/block/dasd_eckd.c

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

diff -urN linux-2.4.21/drivers/s390/block/dasd_eckd.c linux-2.4.22/drivers/s390/block/dasd_eckd.c
@@ -1,10 +1,13 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd_eckd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-                    Carsten Otte <Cotte@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
@@ -42,7 +45,6 @@
 #undef PRINTK_HEADER
 #endif				/* PRINTK_HEADER */
 #define PRINTK_HEADER DASD_NAME"(eckd):"
-#undef CDL_PRINTK
 
 #define ECKD_C0(i) (i->home_bytes)
 #define ECKD_F(i) (i->formula)
@@ -55,21 +57,27 @@
 #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
+#endif
+
 dasd_discipline_t dasd_eckd_discipline;
 
-typedef struct
-dasd_eckd_private_t {
+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;
+	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_DYNAMIC
 static
 devreg_t dasd_eckd_known_devices[] = {
         {
-                ci: { hc: {ctype:0x3880, dtype: 3390}},
+                ci: { hc: {ctype:0x3880, dtype: 0x3390}},
                 flag:(DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE | 
                       DEVREG_TYPE_DEVCHARS),
                 oper_func:dasd_oper_handler
@@ -143,7 +151,10 @@
 			break;
 		}
 	default:
-		INTERNAL_ERROR ("unknown formula%d\n", rdc->formula);
+
+		MESSAGE (KERN_ERR,
+                         "unknown formula%d", 
+                         rdc->formula);
 	}
 	return bpr;
 }
@@ -190,10 +201,35 @@
 	return rpt;
 }
 
+static inline void
+check_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 int
 define_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 trk, int totrk, 
+               int cmd, dasd_device_t * device, ccw_req_t* cqr)
 {
         int rc=0;
 	ch_t geo, beg, end;
@@ -207,8 +243,10 @@
 	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;
 
@@ -224,40 +262,86 @@
 	case DASD_ECKD_CCW_READ_KD_MT:
 	case DASD_ECKD_CCW_READ_COUNT:
 		data->mask.perm = 0x1;
-		data->attributes.operation = 0x3;	/* enable seq. caching */
+		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 = 0x3;	/* enable seq. caching */
+		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 = 0x1;	/* format through cache */
+		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 = 0x1;	/* format through cache */
+		data->attributes.operation = DASD_BYPASS_CACHE;
+
+                check_XRC (de_ccw,
+                           data,
+                           device);
 		break;
 	default:
-		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
+
+		MESSAGE (KERN_ERR,
+                         "unknown opcode 0x%x", 
+                         cmd);
+
 		break;
 	}
-	data->attributes.mode = 0x3;
+
+	data->attributes.mode = 0x3; /* ECKD */
+
 	if (private->rdc_data.cu_type == 0x2105
-	    && !(private->uses_cdl && trk < 2)
-	    ) {
-		data->reserved |= 0x40;
+	    && !(private->uses_cdl && trk < 2) ) {
+                
+		data->ga_extended |= 0x40;
 	}
-	data->beg_ext.cyl = beg.cyl;
+        
+        /* 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.cyl  = end.cyl;
 	data->end_ext.head = end.head;
+
         return rc;
 }
 
@@ -266,7 +350,11 @@
 	       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 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;
@@ -276,10 +364,14 @@
 	ch_t seek = { trk / (geo.head), trk % (geo.head) };
 	int sector = 0;
 
-#ifdef CDL_PRINTK
-	printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n", trk,
-		rec_on_trk, no_rec, cmd, reclen);
-#endif
+        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;
@@ -365,7 +457,10 @@
 		data->operation.operation = 0x0b;
 		break;
 	default:
-		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
+
+                MESSAGE (KERN_ERR,
+                         "unknown opcode 0x%x",
+                         cmd);
 	}
 	memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
 	memcpy (&(data->search_arg), &seek, sizeof (ch_t));
@@ -391,79 +486,113 @@
 static int
 dasd_eckd_check_characteristics (struct dasd_device_t *device)
 {
-	int rc = 0;
+	int   rc = 0;
 	void *conf_data;
-	void *rdc_data;
-	int conf_len;
+        void *rdc_data;
+	int   conf_len;
 	dasd_eckd_private_t *private;
 
 	if (device == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"Null device pointer passed to characteristics checker\n");
+
+		MESSAGE (KERN_WARNING, "%s",
+                         "Null device pointer passed to characteristics "
+                         "checker");
+
                 return -ENODEV;
 	}
-	device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL);
+	device->private = kmalloc (sizeof (dasd_eckd_private_t), 
+                                   GFP_KERNEL);
+
 	if (device->private == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"memory allocation failed for private data\n");
+
+		MESSAGE (KERN_WARNING, "%s",
+			"memory allocation failed for private data");
+
 		rc = -ENOMEM;
                 goto fail;
 	}
-	private = (dasd_eckd_private_t *) device->private;
+
+	private  = (dasd_eckd_private_t *) device->private;
 	rdc_data = (void *) &(private->rdc_data);
-	rc = read_dev_chars (device->devinfo.irq, &rdc_data, 64);
+
+        /* Read Device Characteristics */
+	rc = read_dev_chars (device->devinfo.irq, 
+                             &rdc_data, 
+                             64);
 	if (rc) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"Read device characteristics returned error %d\n", rc);
+
+		MESSAGE (KERN_WARNING,
+			"Read device characteristics returned error %d",
+                         rc);
+
                 goto fail;
         }
-	printk (KERN_INFO PRINTK_HEADER
-		"%04X on sch %d: %04X/%02X(CU:%04X/%02X) "
-                "Cyl:%d Head:%d Sec:%d\n",
-		device->devinfo.devno, device->devinfo.irq,
-		private->rdc_data.dev_type, private->rdc_data.dev_model,
-		private->rdc_data.cu_type, private->rdc_data.cu_model.model,
-		private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl,
-		private->rdc_data.sec_per_trk);
-	rc = read_conf_data (device->devinfo.irq, &conf_data, &conf_len,
+
+        DEV_MESSAGE (KERN_INFO, device,
+                     "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
+                     private->rdc_data.dev_type, 
+                     private->rdc_data.dev_model,
+                     private->rdc_data.cu_type, 
+                     private->rdc_data.cu_model.model,
+                     private->rdc_data.no_cyl, 
+                     private->rdc_data.trk_per_cyl,
+                     private->rdc_data.sec_per_trk);
+
+        /* set default cache operations */
+        private->attrib.operation = DASD_SEQ_ACCESS;
+        private->attrib.nr_cyl    = 0x02;
+        
+        /* Read Configuration Data */
+        rc = read_conf_data (device->devinfo.irq, 
+                             &conf_data, 
+                             &conf_len,
                              LPM_ANYPATH);
 
         if (rc == -EOPNOTSUPP) {
                 rc = 0; /* this one is ok */
         }
 	if (rc) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"Read configuration data returned error %d\n", rc);
+
+		MESSAGE (KERN_WARNING,
+                         "Read configuration data returned error %d",
+                         rc);
+
                 goto fail;
 	}
         if (conf_data == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No configuration data retrieved\n");
+
+		MESSAGE (KERN_WARNING, "%s",
+                         "No configuration data retrieved");
+
                 goto out; /* no errror */
 	} 
         if (conf_len != sizeof (dasd_eckd_confdata_t)) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"sizes of configuration data mismatch"
-                        "%d (read) vs %ld (expected)\n",
-			conf_len, sizeof (dasd_eckd_confdata_t));
+
+		MESSAGE (KERN_WARNING,
+                         "sizes of configuration data mismatch"
+                         "%d (read) vs %ld (expected)",
+                         conf_len, 
+                         sizeof (dasd_eckd_confdata_t));
+
                 goto out; /* no errror */
 	} 
         memcpy (&private->conf_data, conf_data, 
                 sizeof (dasd_eckd_confdata_t));
-        printk (KERN_INFO PRINTK_HEADER
-                "%04X on sch %d: %04X/%02X(CU:%04X/%02X): "
-                "Configuration data read\n",
-                device->devinfo.devno, device->devinfo.irq,
+
+        DEV_MESSAGE (KERN_INFO, device,
+                "%04X/%02X(CU:%04X/%02X): Configuration data read",
                 private->rdc_data.dev_type, 
                 private->rdc_data.dev_model,
                 private->rdc_data.cu_type, 
                 private->rdc_data.cu_model.model);
         goto out;
+
  fail:
-        if ( rc ) {
+        if (device->private) {
                 kfree (device->private);
                 device->private = NULL;
         }
+        
  out:
 	return rc;
 }
@@ -498,8 +627,9 @@
 				 2 * sizeof (LO_eckd_data_t),
                                  device);
 	if (cqr == NULL) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "No memory to allocate initialization request\n");
+
+                MESSAGE (KERN_WARNING, "%s",
+                        "No memory to allocate initialization request");
                 goto out;
 	}
 	DE_data = cqr->data;
@@ -557,13 +687,17 @@
         }
 	cqr->device = device;
 	cqr->retries = 0;
+        cqr->buildclk = get_clock ();
 	cqr->status = CQR_STATUS_FILLED;
         dasd_chanq_enq (&device->queue, cqr);
         goto out;
+
  clear_cqr:
         dasd_free_request (cqr,device);
-        printk (KERN_WARNING PRINTK_HEADER
-                "No memory to allocate initialization request\n");
+
+        MESSAGE (KERN_WARNING, "%s",
+                "No memory to allocate initialization request");
+
         cqr=NULL;
  out:
 	return cqr;
@@ -578,14 +712,17 @@
 	char *cdl_msg;
         int status;
 	int i;
+
 	private->uses_cdl = 1;
         status = device->init_cqr->status;
 	dasd_chanq_deq (&device->queue, device->init_cqr);
 	dasd_free_request (device->init_cqr, device);
 	/* Free the cqr and cleanup device->sizes */
         if ( status != CQR_STATUS_DONE ) {
-                DASD_MESSAGE (KERN_WARNING,device,"%s",
-                              "volume analysis returned unformatted disk");
+
+                DEV_MESSAGE (KERN_WARNING, device, "%s",
+                             "volume analysis returned unformatted disk");
+
                 return -EMEDIUMTYPE;
         }
 	/* Check Track 0 for Compatible Disk Layout */
@@ -614,8 +751,9 @@
 		}
 	} else {
 		if (private->count_area[3].record == 1) {
-			DASD_MESSAGE (KERN_WARNING, device, "%s",
-				      "Trk 0: no records after VTOC!");
+
+			DEV_MESSAGE (KERN_WARNING, device, "%s",
+                                     "Trk 0: no records after VTOC!");
 		}
 	}
 	if (count_area != NULL &&	/* we found notthing violating our disk layout */
@@ -631,8 +769,10 @@
 		}
 	}
 	if (device->sizes.bp_block == 0) {
-		DASD_MESSAGE (KERN_WARNING, device, "%s",
-			      "Volume has incompatible disk layout");
+
+		DEV_MESSAGE (KERN_WARNING, device, "%s",
+                             "Volume has incompatible disk layout");
+
 		return -EMEDIUMTYPE;
 	}
 	device->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
@@ -647,18 +787,21 @@
 						device->sizes.bp_block));
 	cdl_msg =
 	    private->
-	    uses_cdl ? "compatible disk layout" : "classic disk layout";
+	    uses_cdl ? "compatible disk layout" : "linux disk layout";
+
+	DEV_MESSAGE (KERN_INFO, device, 
+                     "(%dkB blks): %dkB at %dkB/trk %s",
+                     (device->sizes.bp_block >> 10),
+                     ((private->rdc_data.no_cyl *
+                       private->rdc_data.trk_per_cyl *
+                       recs_per_track (&private->rdc_data, 0,
+                                       device->sizes.bp_block) *
+                       (device->sizes.bp_block >> 9)) >> 1),
+                     ((recs_per_track (&private->rdc_data, 0,
+                                       device->sizes.bp_block) *
+                       device->sizes.bp_block) >> 10),
+                     cdl_msg);
 
-	DASD_MESSAGE (KERN_INFO, device, "(%dkB blks): %dkB at %dkB/trk %s",
-		      (device->sizes.bp_block >> 10),
-		      (private->rdc_data.no_cyl *
-		       private->rdc_data.trk_per_cyl *
-		       recs_per_track (&private->rdc_data, 0,
-				       device->sizes.bp_block) *
-		       (device->sizes.bp_block >> 9)) >> 1,
-		      (recs_per_track (&private->rdc_data, 0,
-				       device->sizes.bp_block) *
-		       device->sizes.bp_block) >> 10, cdl_msg);
 	return 0;
 }
 
@@ -703,13 +846,21 @@
 	int wrccws = rpt;
 	int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
         
-	if (fdata->start_unit >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)){
-                DASD_MESSAGE (KERN_INFO, device, "Track no %d too big!", fdata->start_unit);
+	if (fdata->start_unit >= 
+            (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)){
+
+                DEV_MESSAGE (KERN_INFO, device, 
+                             "Track no %d too big!", 
+                             fdata->start_unit);
+
                 return NULL;
         }
         if ( fdata->start_unit > fdata->stop_unit) {
-                DASD_MESSAGE (KERN_INFO, device, "Track %d reached! ending.",
-                              fdata->start_unit);
+
+                DEV_MESSAGE (KERN_INFO, device, 
+                             "Track %d reached! ending.",
+                             fdata->start_unit);
+
 		return NULL;
 	}
 	switch (fdata->blksize) {
@@ -719,8 +870,11 @@
 	case 4096:
 		break;
 	default:
-		printk (KERN_WARNING PRINTK_HEADER
-			"Invalid blocksize %d...terminating!\n", fdata->blksize);
+
+		MESSAGE (KERN_WARNING,
+                         "Invalid blocksize %d...terminating!", 
+                         fdata->blksize);
+
 		return NULL;
 	}
 	switch (fdata->intensity) {
@@ -734,8 +888,11 @@
 	case 0x0c:
 		break;
 	default:
-		printk (KERN_WARNING PRINTK_HEADER
-			"Invalid flags 0x%x...terminating!\n", fdata->intensity);
+
+		MESSAGE (KERN_WARNING,
+                         "Invalid flags 0x%x...terminating!", 
+                         fdata->intensity);
+
 		return NULL;
 	}
 
@@ -745,9 +902,12 @@
 	    (fdata->start_unit % private->rdc_data.no_cyl == 0 &&
 	     (fdata->start_unit / private->rdc_data.no_cyl) %
 	     (private->rdc_data.no_cyl / 20))) {
-		DASD_MESSAGE (KERN_INFO, device,
-			      "Format Cylinder: %d Flags: %d",
-			      fdata->start_unit / private->rdc_data.trk_per_cyl, fdata->intensity);
+
+		DBF_DEV_EVENT (DBF_NOTICE, device,
+                               "Format Cylinder: %d Flags: %d",
+                               fdata->start_unit / private->rdc_data.trk_per_cyl,
+                               fdata->intensity);
+
 	}
 	if ((fdata->intensity & ~0x8) & 0x04) {
 		wrccws = 1;
@@ -789,14 +949,14 @@
 		switch (fdata->intensity & ~0x08) {
 		case 0x03:
 			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
-				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS,
+                                           DASD_ECKD_CCW_WRITE_HOME_ADDRESS,
                                            device, fcp)) {
                                 goto clear_fcp;
                         }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
 			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,
+                                           DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,
                                            device->sizes.bp_block, fcp)) {
                                 goto clear_fcp;
                         }
@@ -811,7 +971,7 @@
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
 			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
+                                           DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
                                            device->sizes.bp_block, fcp)) {
                                 goto clear_fcp;
                         }
@@ -837,11 +997,19 @@
 			last_ccw++;
 			break;
 		default:
-			PRINT_WARN ("Unknown format flags...%d\n", fdata->intensity);
+
+			MESSAGE (KERN_WARNING,
+                                 "Unknown format flags...%d", 
+                                 fdata->intensity);
+
 			return NULL;
 		}
 		if (fdata->intensity & 0x02) {
-			PRINT_WARN ("Unsupported format flag...%d\n", fdata->intensity);
+
+			MESSAGE (KERN_WARNING,
+                                 "Unsupported format flag...%d", 
+                                 fdata->intensity);
+
 			return NULL;
 		}
 		if (fdata->intensity & 0x01) {	/* write record zero */
@@ -913,6 +1081,7 @@
 		}
 		(last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
 		fcp->device = device;
+                fcp->buildclk = get_clock ();
 		fcp->status = CQR_STATUS_FILLED;
 	}
         goto out;
@@ -939,8 +1108,10 @@
 	case 0x9343:
 		return dasd_9343_erp_examine (cqr, stat);
 	default:
-		printk (KERN_WARNING PRINTK_HEADER
-			"default (unknown CU type) - RECOVERABLE return \n");
+
+		MESSAGE (KERN_WARNING, "%s",
+                         "default (unknown CU type) - RECOVERABLE return");
+
 		return dasd_era_recover;
 	}
 }
@@ -1015,26 +1186,36 @@
 	int byt_per_blk = device->sizes.bp_block;
 	int shift = device->sizes.s2b_shift;
 	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
-	int btrk = (req->sector >> shift) / blk_per_trk;
-	int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk;
-	int recid = req->sector >> shift;
+        unsigned long reloc_sector = req->sector + 
+                device->major_info->gendisk.part[MINOR(req->rq_dev)].start_sect;
+        int btrk = (reloc_sector >> shift) / blk_per_trk; 
+	int etrk = ((reloc_sector + req->nr_sectors - 1) >> shift) / blk_per_trk;
+	int recid = reloc_sector >> shift;
 	int locate4k_set = 0;
 	int nlocs = 0;
+	int errcode;
 
 	if (req->cmd == READ) {
 		rw_cmd = DASD_ECKD_CCW_READ_MT;
 	} else if (req->cmd == WRITE) {
 		rw_cmd = DASD_ECKD_CCW_WRITE_MT;
 	} else {
-		PRINT_ERR ("Unknown command %d\n", req->cmd);
-		return NULL;
+
+		MESSAGE (KERN_ERR,
+                         "Unknown command %d", 
+                         req->cmd);
+
+		return ERR_PTR(-EINVAL);
 	}
 	/* 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)
-                        BUG();
+		if (bh->b_size < byt_per_blk) {
+			MESSAGE(KERN_ERR, "ignoring bogus sized request: %d<%d",
+					  bh->b_size, byt_per_blk);
+                        return ERR_PTR(-EINVAL);
+		}
                 bhct+= bh->b_size >> (device->sizes.s2b_shift+9);
 	}
 	if (btrk < 2 && private->uses_cdl) {
@@ -1050,12 +1231,13 @@
                                     sizeof (LO_eckd_data_t),
                                     device);
 	if (!rw_cp) {
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 	}
 	DE_data = rw_cp->data;
 	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
 	ccw = rw_cp->cpaddr;
-	if (define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device, rw_cp)) {
+	if ((errcode = define_extent (ccw, DE_data, btrk, etrk, 
+                                      rw_cmd, device, rw_cp))) {
                 goto clear_rw_cp;
         }
 	ccw->flags |= CCW_FLAG_CC;
@@ -1068,25 +1250,25 @@
                                     && private->uses_cdl) {
                                         /* Do a locate record for our special blocks */
                                         int cmd = dasd_eckd_cdl_cmd (device,recid, req->cmd);
-                                        if (locate_record (ccw, 
+                                        if ((errcode = locate_record (ccw, 
                                                        LO_data++,
                                                        recid / blk_per_trk, 
                                                        recid % blk_per_trk + 1, 
                                                        1, cmd, device,
-                                                           dasd_eckd_cdl_reclen(device, recid), rw_cp)) {
+                                                       dasd_eckd_cdl_reclen(device, recid), rw_cp))) {
                                                 goto clear_rw_cp;
                                         }
                                 } else {
                                         // Do a locate record for standard blocks */
-                                        if (locate_record (ccw, 
+                                        if ((errcode = locate_record (ccw, 
                                                        LO_data++,
                                                        recid /blk_per_trk,
                                                        recid %blk_per_trk + 1,
-                                                       (((req->sector +
+                                                       (((reloc_sector +
                                                           req->nr_sectors) >>
                                                          shift) - recid), 
                                                        rw_cmd, device,
-                                                           device->sizes.bp_block, rw_cp)) {
+                                                       device->sizes.bp_block, rw_cp))) {
                                                 goto clear_rw_cp;
                                         }
                                         locate4k_set = 1;
@@ -1105,25 +1287,32 @@
                                             0xE5, byt_per_blk - ccw->count);
                                 }
                         }
-                        if (dasd_set_normalized_cda (ccw, __pa (bh->b_data+size), rw_cp, device)) {
+                        if ((errcode = dasd_set_normalized_cda (ccw, __pa (bh->b_data+size), 
+                                                                rw_cp, device))) {
                                 goto clear_rw_cp;
                         }
                         recid++;
                 }
                 bh = bh->b_reqnext;
 	}
-	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
-	rw_cp->device = device;
+	ccw->flags    &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
+	rw_cp->device  = device;
 	rw_cp->expires = 5 * TOD_MIN;	/* 5 minutes */
-	rw_cp->req = req;
-	rw_cp->lpm = LPM_ANYPATH;
-	rw_cp->retries = 2;
-	asm volatile ("STCK %0":"=m" (rw_cp->buildclk));
-	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
+	rw_cp->req     = req;
+	rw_cp->lpm     = LPM_ANYPATH;
+	rw_cp->retries = 256;
+
+	rw_cp->buildclk = get_clock ();
+
+	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;
+        dasd_free_request (rw_cp, 
+                           device);
+        rw_cp=ERR_PTR(errcode);
  out:
 	return rw_cp;
 }
@@ -1176,18 +1365,31 @@
 ccw_req_t *
 dasd_eckd_reserve (struct dasd_device_t * device)
 {
-	ccw_req_t *cqr =
-	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
+	ccw_req_t *cqr;
+
+        cqr = dasd_alloc_request (dasd_eckd_discipline.name, 
+                                  1 + 1, 32, device);
 	if (cqr == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No memory to allocate initialization request\n");
+
+		MESSAGE (KERN_WARNING, "%s",
+                         "No memory to allocate initialization request");
+
 		return NULL;
 	}
 	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
+        cqr->cpaddr->flags |= CCW_FLAG_SLI;
+        cqr->cpaddr->count = 32;
+
+	if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data), 
+                                     cqr, device)) {
+                dasd_free_request (cqr, device);
+                return NULL;
+        }
+        
 	cqr->device  = device;
 	cqr->retries = 0;
 	cqr->expires = 10 * TOD_SEC;
-        cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */
+	cqr->buildclk = get_clock ();
 	cqr->status  = CQR_STATUS_FILLED;
 	return cqr; 
 }
@@ -1202,18 +1404,31 @@
 ccw_req_t *
 dasd_eckd_release (struct dasd_device_t * device)
 {
-	ccw_req_t *cqr =
-	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
+	ccw_req_t *cqr;
+
+        cqr = dasd_alloc_request (dasd_eckd_discipline.name, 
+                                  1 + 1, 32, device);
 	if (cqr == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No memory to allocate initialization request\n");
+
+		MESSAGE (KERN_WARNING, "%s",
+                         "No memory to allocate initialization request");
+
 		return NULL;
 	}
 	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
+        cqr->cpaddr->flags |= CCW_FLAG_SLI;
+        cqr->cpaddr->count = 32;
+
+	if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data), 
+                                     cqr, device)) {
+                dasd_free_request (cqr, device);
+                return NULL;
+        }
+
 	cqr->device  = device;
 	cqr->retries = 0;
 	cqr->expires = 10 * TOD_SEC;
-        cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */
+	cqr->buildclk = get_clock ();
 	cqr->status  = CQR_STATUS_FILLED;
 	return cqr;
 
@@ -1229,18 +1444,31 @@
 ccw_req_t *
 dasd_eckd_steal_lock (struct dasd_device_t * device)
 {
-	ccw_req_t *cqr =
-	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
+	ccw_req_t *cqr;
+
+        cqr = dasd_alloc_request (dasd_eckd_discipline.name, 
+                                  1 + 1, 32, device);
 	if (cqr == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No memory to allocate initialization request\n");
+
+		MESSAGE (KERN_WARNING, "%s",
+			"No memory to allocate initialization request");
+
 		return NULL;
 	}
 	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK;
+        cqr->cpaddr->flags |= CCW_FLAG_SLI;
+        cqr->cpaddr->count = 32;
+
+	if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data), 
+                                     cqr, device)) {
+                dasd_free_request (cqr, device);
+                return NULL;
+        }
+        
 	cqr->device  = device;
 	cqr->retries = 0;
 	cqr->expires = 10 * TOD_SEC;
-        cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */
+	cqr->buildclk = get_clock ();
 	cqr->status  = CQR_STATUS_FILLED;
 	return cqr;
 }
@@ -1274,14 +1502,17 @@
 }
 
 static int
-dasd_eckd_fill_info (dasd_device_t * device, dasd_information_t * info)
+dasd_eckd_fill_info (dasd_device_t * device, dasd_information2_t * info)
 {
 	int rc = 0;
 	info->label_block = 2;
-	if (((dasd_eckd_private_t *) device->private)->uses_cdl)
+	if (((dasd_eckd_private_t *) device->private)->uses_cdl) {
 		info->FBA_layout = 0;
-	else
-		info->FBA_layout = 1;
+                info->format = DASD_FORMAT_CDL;
+        } else {
+                info->FBA_layout = 1;
+                info->format = DASD_FORMAT_LDL;
+        }
 	info->characteristics_size = sizeof (dasd_eckd_characteristics_t);
 	memcpy (info->characteristics,
 		&((dasd_eckd_private_t *) device->private)->rdc_data,
@@ -1293,6 +1524,138 @@
 	return rc;
 }
 
+/*
+ * DASD_ECKD_READ_STATS
+ * 
+ * DESCRIPTION
+ *   build the channel program to read the performance statistics
+ *   of the attached subsystem
+ */
+ccw_req_t *
+dasd_eckd_read_stats (struct dasd_device_t * device)
+{
+
+        int                    rc;
+	ccw1_t                 *ccw;
+	ccw_req_t              *cqr;
+	dasd_psf_prssd_data_t  *prssdp;
+	dasd_rssd_perf_stats_t *statsp;
+
+        cqr = dasd_alloc_request (dasd_eckd_discipline.name, 
+                                  1 /* PSF */ + 1 /* RSSD */,
+                                  (sizeof (dasd_psf_prssd_data_t) +  
+                                   sizeof (dasd_rssd_perf_stats_t) ), 
+                                  device);
+
+	if (cqr == NULL) {
+                
+                MESSAGE (KERN_WARNING, "%s",
+                         "No memory to allocate initialization request");
+                
+		return NULL;
+	}
+
+	cqr->device  = device;
+	cqr->retries = 0;
+	cqr->expires = 10 * TOD_SEC;
+
+        /* Prepare for Read Subsystem Data */
+	prssdp = (dasd_psf_prssd_data_t *) cqr->data;
+
+	memset (prssdp, 0, sizeof (dasd_psf_prssd_data_t));
+
+	prssdp->order     = PSF_ORDER_PRSSD;
+	prssdp->suborder  = 0x01; /* Perfomance Statistics */
+	prssdp->varies[1] = 0x01; /* Perf Statistics for the Subsystem */
+
+	ccw = cqr->cpaddr;
+
+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+	ccw->count    = sizeof (dasd_psf_prssd_data_t);
+	ccw->flags   |= CCW_FLAG_CC;
+
+	if ((rc = dasd_set_normalized_cda (ccw,__pa (prssdp), cqr, device))) {
+
+                dasd_free_request (cqr, 
+                                   device);
+                return NULL;
+        }
+
+	ccw++;
+
+        /* Read Subsystem Data - Performance Statistics */
+	statsp = (dasd_rssd_perf_stats_t *) (prssdp + 1);
+	memset (statsp, 0, sizeof (dasd_rssd_perf_stats_t));
+
+	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+	ccw->count    = sizeof (dasd_rssd_perf_stats_t);
+
+	if ((rc = dasd_set_normalized_cda (ccw,__pa (statsp), cqr, device))) {
+
+                dasd_free_request (cqr, 
+                                   device);
+                return NULL;
+        }
+        cqr->buildclk = get_clock ();
+	cqr->status   = CQR_STATUS_FILLED;
+
+	return cqr; 
+} /* end  dasd_eckd_rstat */
+
+/*
+ * DASD_ECKD_RET_STATS
+ * 
+ * DESCRIPTION
+ *   returns pointer to Performance Statistics Data.
+ */
+dasd_rssd_perf_stats_t *
+dasd_eckd_ret_stats (ccw_req_t *cqr)
+{
+        
+        dasd_psf_prssd_data_t  *prssdp;
+	dasd_rssd_perf_stats_t *statsp;
+        
+	if (cqr == NULL) {
+
+		return NULL;
+	}
+
+        /* Prepare for Read Subsystem Data */
+	prssdp = (dasd_psf_prssd_data_t *)  cqr->data;
+	statsp = (dasd_rssd_perf_stats_t *) (prssdp + 1);
+
+	return statsp;
+
+} /* end  dasd_eckd_rstat */
+
+
+/*
+ * DASD_ECKD_SET_ATTRUB
+ * 
+ * DESCRIPTION
+ *   stores the attributes for cache operation to be used in Define Extend (DE).
+ */
+int
+dasd_eckd_set_attrib (dasd_device_t *device,
+                      attrib_data_t *attrib)
+{
+        int rc = 0;
+	dasd_eckd_private_t *private;
+
+        private = (dasd_eckd_private_t *) device->private;
+        private->attrib = *attrib;
+
+        DBF_DEV_EVENT (DBF_ERR, device,
+                     "cache operation mode set to "
+                     "%x (%i cylinder prestage)",
+                     private->attrib.operation,
+                     private->attrib.nr_cyl);
+        
+
+        return rc;
+        
+} /* end dasd_eckd_set_attrib */
+
 static char*
 dasd_eckd_dump_sense (struct dasd_device_t *device, 
                       ccw_req_t            *req)
@@ -1304,8 +1667,10 @@
 	int len, sl, sct;
 
 	if (page == NULL) {
-                printk (KERN_ERR PRINTK_HEADER
-                        "No memory to dump sense data\n");
+
+                MESSAGE (KERN_ERR, "%s",
+                        "No memory to dump sense data");
+
 		return NULL;
 	}
 
@@ -1318,17 +1683,27 @@
 	len += sprintf (page + len, KERN_ERR PRINTK_HEADER
 			"Failing CCW: %p\n", (void *) (long) stat->cpa);
 	{
+
 		ccw1_t *act = req->cpaddr;
 		int i = req->cplength;
+
 		do {
-#ifdef ERP_DEBUG
-			printk (KERN_ERR "CCW %p: %08X %08X\n",
-				act, ((int *) act)[0], ((int *) act)[1]);
-			printk (KERN_ERR "DAT: %08X %08X %08X %08X\n",
-				((int *) act->cda)[0], ((int *) act->cda)[1],
-				((int *) act->cda)[2], ((int *) act->cda)[3]);
-#endif				/* ERP_DEBUG */
+
+			DBF_EVENT (DBF_INFO, 
+                                   "CCW %p: %08X %08X",
+                                   act, 
+                                   ((int *) act)[0], 
+                                   ((int *) act)[1]);
+
+			DBF_EVENT (DBF_INFO, 
+                                   "DAT: %08X %08X %08X %08X",
+                                   ((int *) (addr_t) act->cda)[0], 
+                                   ((int *) (addr_t) act->cda)[1],
+                                   ((int *) (addr_t) act->cda)[2], 
+                                   ((int *) (addr_t) act->cda)[3]);
+
 			act++;
+
 		} while (--i);
 	}
 	if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
@@ -1353,13 +1728,15 @@
 		} else {
 			/* 32 Byte Sense Data */
 			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
-					"32 Byte: Format: %x Exception class %x\n",
+					"32 Byte: Format: %x "
+                                        "Exception class %x\n",
 					sense[6] & 0x0f, sense[22] >> 4);
 		}
 	}
 
-        printk ("Sense data:\n%s", 
-                page);
+        MESSAGE (KERN_ERR,
+                 "Sense data:\n%s", 
+                 page);
 
         free_page ((unsigned long) page);
         
@@ -1371,7 +1748,7 @@
         owner: THIS_MODULE,
 	name:"ECKD",
 	ebcname:"ECKD",
-	max_blocks:255,
+	max_blocks:240,
 	id_check:dasd_eckd_id_check,
 	check_characteristics:dasd_eckd_check_characteristics,
 	init_analysis:dasd_eckd_init_analysis,
@@ -1391,14 +1768,21 @@
         steal_lock:dasd_eckd_steal_lock,
 	merge_cp:dasd_eckd_merge_cp,
 	fill_info:dasd_eckd_fill_info,
+        read_stats:dasd_eckd_read_stats,
+        ret_stats:dasd_eckd_ret_stats,
+        set_attrib:dasd_eckd_set_attrib,
+	list:LIST_HEAD_INIT(dasd_eckd_discipline.list),
 };
 
 int
 dasd_eckd_init (void)
 {
 	int rc = 0;
-	printk (KERN_INFO PRINTK_HEADER
-		"%s discipline initializing\n", dasd_eckd_discipline.name);
+
+	MESSAGE (KERN_INFO,
+		"%s discipline initializing", 
+                 dasd_eckd_discipline.name);
+
 	ASCEBC (dasd_eckd_discipline.ebcname, 4);
 	dasd_discipline_add (&dasd_eckd_discipline);
 #ifdef CONFIG_DASD_DYNAMIC
@@ -1407,10 +1791,12 @@
 		for (i = 0;
 		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
 		     i++) {
-			printk (KERN_INFO PRINTK_HEADER
-				"We are interested in: CU %04X/%02x\n",
-				dasd_eckd_known_devices[i].ci.hc.ctype,
-				dasd_eckd_known_devices[i].ci.hc.cmode);
+
+			MESSAGE (KERN_INFO,
+                                 "We are interested in: CU %04X/%02x",
+                                 dasd_eckd_known_devices[i].ci.hc.ctype,
+                                 dasd_eckd_known_devices[i].ci.hc.cmode);
+
 			s390_device_register (&dasd_eckd_known_devices[i]);
 		}
 	}
@@ -1421,18 +1807,23 @@
 void
 dasd_eckd_cleanup (void)
 {
-	printk (KERN_INFO PRINTK_HEADER
-		"%s discipline cleaning up\n", dasd_eckd_discipline.name);
+
+	MESSAGE (KERN_INFO,
+		"%s discipline cleaning up", 
+                 dasd_eckd_discipline.name);
+
 #ifdef CONFIG_DASD_DYNAMIC
 	{
 		int i;
 		for (i = 0;
 		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
 		     i++) {
-			printk (KERN_INFO PRINTK_HEADER
-				"We were interested in: CU %04X/%02x\n",
-				dasd_eckd_known_devices[i].ci.hc.ctype,
-				dasd_eckd_known_devices[i].ci.hc.cmode);
+
+			MESSAGE (KERN_INFO,
+                                 "We were interested in: CU %04X/%02x",
+                                 dasd_eckd_known_devices[i].ci.hc.ctype,
+                                 dasd_eckd_known_devices[i].ci.hc.cmode);
+
 			s390_device_unregister (&dasd_eckd_known_devices[i]);
 		}
 	}

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