File: /usr/src/linux/drivers/s390/block/dasd_eckd.c

1     /* 
2      * File...........: linux/drivers/s390/block/dasd_eckd.c
3      * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4                         Carsten Otte <Cotte@de.ibm.com>
5      * Bugreports.to..: <Linux390@de.ibm.com>
6      * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
7     
8      * History of changes (starts July 2000)
9      * 07/11/00 Enabled rotational position sensing
10      * 07/14/00 Reorganized the format process for better ERP
11      * 07/20/00 added experimental support for 2105 control unit (ESS)
12      * 07/24/00 increased expiration time and added the missing zero
13      * 08/07/00 added some bits to define_extent for ESS support
14      * 09/20/00 added reserve and release ioctls
15      * 10/04/00 changed RW-CCWS to R/W Key and Data
16      * 10/10/00 reverted last change according to ESS exploitation
17      * 10/10/00 now dequeuing init_cqr before freeing *ouch*
18      * 26/10/00 fixed ITPM20144ASC (problems when accesing a device formatted by VIF)
19      * 01/23/01 fixed kmalloc statement in dump_sense to be GFP_ATOMIC
20      *          fixed partition handling and HDIO_GETGEO
21      */
22     
23     #include <linux/config.h>
24     #include <linux/stddef.h>
25     #include <linux/kernel.h>
26     #include <linux/slab.h>
27     #include <linux/hdreg.h>	/* HDIO_GETGEO                      */
28     #include <linux/blk.h>
29     
30     #include <asm/debug.h>
31     #include <asm/ccwcache.h>
32     #include <asm/idals.h>
33     #include <asm/ebcdic.h>
34     #include <asm/io.h>
35     #include <asm/irq.h>
36     #include <asm/s390dyn.h>
37     
38     #include "dasd_int.h"
39     #include "dasd_eckd.h"
40     
41     #ifdef PRINTK_HEADER
42     #undef PRINTK_HEADER
43     #endif				/* PRINTK_HEADER */
44     #define PRINTK_HEADER DASD_NAME"(eckd):"
45     #undef CDL_PRINTK
46     
47     #define ECKD_C0(i) (i->home_bytes)
48     #define ECKD_F(i) (i->formula)
49     #define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1))
50     #define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2))
51     #define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3))
52     #define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0)
53     #define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0)
54     #define ECKD_F6(i) (i->factor6)
55     #define ECKD_F7(i) (i->factor7)
56     #define ECKD_F8(i) (i->factor8)
57     
58     dasd_discipline_t dasd_eckd_discipline;
59     
60     typedef struct
61     dasd_eckd_private_t {
62     	dasd_eckd_characteristics_t rdc_data;
63     	dasd_eckd_confdata_t conf_data;
64     	eckd_count_t count_area[5];
65     	int uses_cdl;
66     } dasd_eckd_private_t;
67     
68     #ifdef CONFIG_DASD_DYNAMIC
69     static
70     devreg_t dasd_eckd_known_devices[] = {
71             {
72                     ci: { hc: {ctype:0x3880, dtype: 3390}},
73                     flag:(DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE | 
74                           DEVREG_TYPE_DEVCHARS),
75                     oper_func:dasd_oper_handler
76             },
77             {
78                     ci: { hc: {ctype:0x3990}},
79                     flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
80                     oper_func:dasd_oper_handler
81             },
82     	{
83                     ci: { hc: {ctype:0x2105}},
84                     flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
85                     oper_func:dasd_oper_handler
86             },
87     	{
88                     ci: { hc: {ctype:0x9343}},
89                     flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
90                     oper_func:dasd_oper_handler
91             }
92     };
93     #endif
94     
95     int sizes_trk0[] = { 28, 148, 84 };
96     #define LABEL_SIZE 140
97     
98     static inline unsigned int
99     round_up_multiple (unsigned int no, unsigned int mult)
100     {
101     	int rem = no % mult;
102     	return (rem ? no - rem + mult : no);
103     }
104     
105     static inline unsigned int
106     ceil_quot (unsigned int d1, unsigned int d2)
107     {
108     	return (d1 + (d2 - 1)) / d2;
109     }
110     
111     static inline int
112     bytes_per_record (dasd_eckd_characteristics_t * rdc, int kl,	/* key length */
113     		  int dl /* data length */ )
114     {
115     	int bpr = 0;
116     	switch (rdc->formula) {
117     	case 0x01:{
118     			unsigned int fl1, fl2;
119     			fl1 = round_up_multiple (ECKD_F2 (rdc) + dl,
120     						 ECKD_F1 (rdc));
121     			fl2 = round_up_multiple (kl ? ECKD_F2 (rdc) + kl : 0,
122     						 ECKD_F1 (rdc));
123     			bpr = fl1 + fl2;
124     			break;
125     		}
126     	case 0x02:{
127     			unsigned int fl1, fl2, int1, int2;
128     			int1 = ceil_quot (dl + ECKD_F6 (rdc),
129     					  ECKD_F5 (rdc) << 1);
130     			int2 = ceil_quot (kl + ECKD_F6 (rdc),
131     					  ECKD_F5 (rdc) << 1);
132     			fl1 = round_up_multiple (ECKD_F1 (rdc) *
133     						 ECKD_F2 (rdc) +
134     						 (dl + ECKD_F6 (rdc) +
135     						  ECKD_F4 (rdc) * int1),
136     						 ECKD_F1 (rdc));
137     			fl2 = round_up_multiple (ECKD_F1 (rdc) *
138     						 ECKD_F3 (rdc) +
139     						 (kl + ECKD_F6 (rdc) +
140     						  ECKD_F4 (rdc) * int2),
141     						 ECKD_F1 (rdc));
142     			bpr = fl1 + fl2;
143     			break;
144     		}
145     	default:
146     		INTERNAL_ERROR ("unknown formula%d\n", rdc->formula);
147     	}
148     	return bpr;
149     }
150     
151     static inline unsigned int
152     bytes_per_track (dasd_eckd_characteristics_t * rdc)
153     {
154     	return *(unsigned int *) (rdc->byte_per_track) >> 8;
155     }
156     
157     static inline unsigned int
158     recs_per_track (dasd_eckd_characteristics_t * rdc,
159     		unsigned int kl, unsigned int dl)
160     {
161     	int rpt = 0;
162     	int dn;
163     	switch (rdc->dev_type) {
164     	case 0x3380:
165     		if (kl)
166     			return 1499 / (15 +
167     				       7 + ceil_quot (kl + 12, 32) +
168     				       ceil_quot (dl + 12, 32));
169     		else
170     			return 1499 / (15 + ceil_quot (dl + 12, 32));
171     	case 0x3390:
172     		dn = ceil_quot (dl + 6, 232) + 1;
173     		if (kl) {
174     			int kn = ceil_quot (kl + 6, 232) + 1;
175     			return 1729 / (10 +
176     				       9 + ceil_quot (kl + 6 * kn, 34) +
177     				       9 + ceil_quot (dl + 6 * dn, 34));
178     		} else
179     			return 1729 / (10 + 9 + ceil_quot (dl + 6 * dn, 34));
180     	case 0x9345:
181     		dn = ceil_quot (dl + 6, 232) + 1;
182     		if (kl) {
183     			int kn = ceil_quot (kl + 6, 232) + 1;
184     			return 1420 / (18 +
185     				       7 + ceil_quot (kl + 6 * kn, 34) +
186     				       ceil_quot (dl + 6 * dn, 34));
187     		} else
188     			return 1420 / (18 + 7 + ceil_quot (dl + 6 * dn, 34));
189     	}
190     	return rpt;
191     }
192     
193     static inline int
194     define_extent (ccw1_t * de_ccw,
195     	       DE_eckd_data_t * data,
196     	       int trk, int totrk, int cmd, dasd_device_t * device, ccw_req_t* cqr)
197     {
198             int rc=0;
199     	ch_t geo, beg, end;
200     	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
201     
202     	geo.cyl = private->rdc_data.no_cyl;
203     	geo.head = private->rdc_data.trk_per_cyl;
204     	beg.cyl = trk / geo.head;
205     	beg.head = trk % geo.head;
206     	end.cyl = totrk / geo.head;
207     	end.head = totrk % geo.head;
208     
209     	memset (de_ccw, 0, sizeof (ccw1_t));
210     	de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
211     	de_ccw->count = 16;
212     	if (rc=dasd_set_normalized_cda (de_ccw, __pa (data), cqr, device)) 
213                     return rc;
214     
215     	memset (data, 0, sizeof (DE_eckd_data_t));
216     	switch (cmd) {
217     	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
218     	case DASD_ECKD_CCW_READ_RECORD_ZERO:
219     	case DASD_ECKD_CCW_READ:
220     	case DASD_ECKD_CCW_READ_MT:
221     	case DASD_ECKD_CCW_READ_CKD:	/* Fallthrough */
222     	case DASD_ECKD_CCW_READ_CKD_MT:
223     	case DASD_ECKD_CCW_READ_KD:
224     	case DASD_ECKD_CCW_READ_KD_MT:
225     	case DASD_ECKD_CCW_READ_COUNT:
226     		data->mask.perm = 0x1;
227     		data->attributes.operation = 0x3;	/* enable seq. caching */
228     		break;
229     	case DASD_ECKD_CCW_WRITE:
230     	case DASD_ECKD_CCW_WRITE_MT:
231     	case DASD_ECKD_CCW_WRITE_KD:
232     	case DASD_ECKD_CCW_WRITE_KD_MT:
233     		data->mask.perm = 0x02;
234     		data->attributes.operation = 0x3;	/* enable seq. caching */
235     		break;
236     	case DASD_ECKD_CCW_WRITE_CKD:
237     	case DASD_ECKD_CCW_WRITE_CKD_MT:
238     		data->attributes.operation = 0x1;	/* format through cache */
239     		break;
240     	case DASD_ECKD_CCW_ERASE:
241     	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
242     	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
243     		data->mask.perm = 0x3;
244     		data->mask.auth = 0x1;
245     		data->attributes.operation = 0x1;	/* format through cache */
246     		break;
247     	default:
248     		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
249     		break;
250     	}
251     	data->attributes.mode = 0x3;
252     	if (private->rdc_data.cu_type == 0x2105
253     	    && !(private->uses_cdl && trk < 2)
254     	    ) {
255     		data->reserved |= 0x40;
256     	}
257     	data->beg_ext.cyl = beg.cyl;
258     	data->beg_ext.head = beg.head;
259     	data->end_ext.cyl = end.cyl;
260     	data->end_ext.head = end.head;
261             return rc;
262     }
263     
264     static inline int
265     locate_record (ccw1_t * lo_ccw,
266     	       LO_eckd_data_t * data,
267     	       int trk,
268     	       int rec_on_trk,
269     	       int no_rec, int cmd, dasd_device_t * device, int reclen, ccw_req_t* cqr)
270     {
271             int rc=0;
272     	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
273     	ch_t geo = { private->rdc_data.no_cyl,
274     		private->rdc_data.trk_per_cyl
275     	};
276     	ch_t seek = { trk / (geo.head), trk % (geo.head) };
277     	int sector = 0;
278     
279     #ifdef CDL_PRINTK
280     	printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n", trk,
281     		rec_on_trk, no_rec, cmd, reclen);
282     #endif
283     	memset (lo_ccw, 0, sizeof (ccw1_t));
284     	lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
285     	lo_ccw->count = 16;
286     	if (rc=dasd_set_normalized_cda (lo_ccw, __pa (data), cqr, device))
287                     return rc;
288     
289     	memset (data, 0, sizeof (LO_eckd_data_t));
290             if (rec_on_trk) {
291                     switch (private->rdc_data.dev_type) {
292                     case 0x3390:{
293                             int dn, d;
294                             dn = ceil_quot (reclen + 6, 232);
295                             d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34);
296                             sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8;
297                             break;
298                     }
299                     case 0x3380:{
300                             int d;
301                             d = 7 + ceil_quot (reclen + 12, 32);
302                             sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;
303                             break;
304                     }
305                     case 0x9345:
306                     default:
307                             sector = 0;
308                     }
309             }
310             data->sector = sector;
311     	data->count = no_rec;
312     	switch (cmd) {
313     	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
314     		data->operation.orientation = 0x3;
315     		data->operation.operation = 0x03;
316     		break;
317     	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
318     		data->operation.orientation = 0x3;
319     		data->operation.operation = 0x16;
320     		break;
321     	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
322     		data->operation.orientation = 0x1;
323     		data->operation.operation = 0x03;
324     		data->count++;
325     		break;
326     	case DASD_ECKD_CCW_READ_RECORD_ZERO:
327     		data->operation.orientation = 0x3;
328     		data->operation.operation = 0x16;
329     		data->count++;
330     		break;
331     	case DASD_ECKD_CCW_WRITE:
332     	case DASD_ECKD_CCW_WRITE_MT:
333     	case DASD_ECKD_CCW_WRITE_KD:
334     	case DASD_ECKD_CCW_WRITE_KD_MT:
335     		data->auxiliary.last_bytes_used = 0x1;
336     		data->length = reclen;
337     		data->operation.operation = 0x01;
338     		break;
339     	case DASD_ECKD_CCW_WRITE_CKD:
340     	case DASD_ECKD_CCW_WRITE_CKD_MT:
341     		data->auxiliary.last_bytes_used = 0x1;
342     		data->length = reclen;
343     		data->operation.operation = 0x03;
344     		break;
345     	case DASD_ECKD_CCW_READ:
346     	case DASD_ECKD_CCW_READ_MT:
347     	case DASD_ECKD_CCW_READ_KD:
348     	case DASD_ECKD_CCW_READ_KD_MT:
349     		data->auxiliary.last_bytes_used = 0x1;
350     		data->length = reclen;
351     		data->operation.operation = 0x06;
352     		break;
353     	case DASD_ECKD_CCW_READ_CKD:
354     	case DASD_ECKD_CCW_READ_CKD_MT:
355     		data->auxiliary.last_bytes_used = 0x1;
356     		data->length = reclen;
357     		data->operation.operation = 0x16;
358     		break;
359     	case DASD_ECKD_CCW_READ_COUNT:
360     		data->operation.operation = 0x06;
361     		break;
362     	case DASD_ECKD_CCW_ERASE:
363                     data->length = reclen;
364                     data->auxiliary.last_bytes_used = 0x1;
365     		data->operation.operation = 0x0b;
366     		break;
367     	default:
368     		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
369     	}
370     	memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
371     	memcpy (&(data->search_arg), &seek, sizeof (ch_t));
372     	data->search_arg.record = rec_on_trk;
373             return rc;
374     }
375     
376     static int
377     dasd_eckd_id_check (s390_dev_info_t * info)
378     {
379     	if (info->sid_data.cu_type == 0x3990 ||
380     	    info->sid_data.cu_type == 0x2105)
381     		    if (info->sid_data.dev_type == 0x3390) return 0;
382     	if (info->sid_data.cu_type == 0x3990 ||
383     	    info->sid_data.cu_type == 0x2105)
384     		    if (info->sid_data.dev_type == 0x3380) return 0;
385     	if (info->sid_data.cu_type == 0x9343)
386     		if (info->sid_data.dev_type == 0x9345)
387     			return 0;
388     	return -ENODEV;
389     }
390     
391     static int
392     dasd_eckd_check_characteristics (struct dasd_device_t *device)
393     {
394     	int rc = 0;
395     	void *conf_data;
396     	void *rdc_data;
397     	int conf_len;
398     	dasd_eckd_private_t *private;
399     
400     	if (device == NULL) {
401     		printk (KERN_WARNING PRINTK_HEADER
402     			"Null device pointer passed to characteristics checker\n");
403                     return -ENODEV;
404     	}
405     	device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL);
406     	if (device->private == NULL) {
407     		printk (KERN_WARNING PRINTK_HEADER
408     			"memory allocation failed for private data\n");
409     		rc = -ENOMEM;
410                     goto fail;
411     	}
412     	private = (dasd_eckd_private_t *) device->private;
413     	rdc_data = (void *) &(private->rdc_data);
414     	rc = read_dev_chars (device->devinfo.irq, &rdc_data, 64);
415     	if (rc) {
416     		printk (KERN_WARNING PRINTK_HEADER
417     			"Read device characteristics returned error %d\n", rc);
418                     goto fail;
419             }
420     	printk (KERN_INFO PRINTK_HEADER
421     		"%04X on sch %d: %04X/%02X(CU:%04X/%02X) "
422                     "Cyl:%d Head:%d Sec:%d\n",
423     		device->devinfo.devno, device->devinfo.irq,
424     		private->rdc_data.dev_type, private->rdc_data.dev_model,
425     		private->rdc_data.cu_type, private->rdc_data.cu_model.model,
426     		private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl,
427     		private->rdc_data.sec_per_trk);
428     	rc = read_conf_data (device->devinfo.irq, &conf_data, &conf_len,
429                                  LPM_ANYPATH);
430     
431             if (rc == -EOPNOTSUPP) {
432                     rc = 0; /* this one is ok */
433             }
434     	if (rc) {
435     		printk (KERN_WARNING PRINTK_HEADER
436     			"Read configuration data returned error %d\n", rc);
437                     goto fail;
438     	}
439             if (conf_data == NULL) {
440     		printk (KERN_WARNING PRINTK_HEADER
441     			"No configuration data retrieved\n");
442                     goto out; /* no errror */
443     	} 
444             if (conf_len != sizeof (dasd_eckd_confdata_t)) {
445     		printk (KERN_WARNING PRINTK_HEADER
446     			"sizes of configuration data mismatch"
447                             "%d (read) vs %ld (expected)\n",
448     			conf_len, sizeof (dasd_eckd_confdata_t));
449                     goto out; /* no errror */
450     	} 
451             memcpy (&private->conf_data, conf_data, 
452                     sizeof (dasd_eckd_confdata_t));
453             printk (KERN_INFO PRINTK_HEADER
454                     "%04X on sch %d: %04X/%02X(CU:%04X/%02X): "
455                     "Configuration data read\n",
456                     device->devinfo.devno, device->devinfo.irq,
457                     private->rdc_data.dev_type, 
458                     private->rdc_data.dev_model,
459                     private->rdc_data.cu_type, 
460                     private->rdc_data.cu_model.model);
461             goto out;
462      fail:
463             if ( rc ) {
464                     kfree (device->private);
465                     device->private = NULL;
466             }
467      out:
468     	return rc;
469     }
470     
471     static inline int
472     dasd_eckd_cdl_reclen (dasd_device_t * device, int recid)
473     {
474     	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
475     	int byt_per_blk = device->sizes.bp_block;
476     	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
477     	if (recid < 3)
478     		return sizes_trk0[recid];
479     	if (recid < blk_per_trk)
480     		return byt_per_blk;
481     	if (recid < 2 * blk_per_trk)
482     		return LABEL_SIZE;
483     	return byt_per_blk;
484     }
485     
486     static ccw_req_t *
487     dasd_eckd_init_analysis (struct dasd_device_t *device)
488     {
489     	ccw_req_t *cqr = NULL;
490     	ccw1_t *ccw;
491     	DE_eckd_data_t *DE_data;
492     	LO_eckd_data_t *LO_data;
493     	dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
494     	eckd_count_t *count_data = private->count_area;
495     
496     	cqr = dasd_alloc_request (dasd_eckd_discipline.name, 8 + 1,
497     				 sizeof (DE_eckd_data_t) +
498     				 2 * sizeof (LO_eckd_data_t),
499                                      device);
500     	if (cqr == NULL) {
501                     printk (KERN_WARNING PRINTK_HEADER
502                             "No memory to allocate initialization request\n");
503                     goto out;
504     	}
505     	DE_data = cqr->data;
506     	LO_data = cqr->data + sizeof (DE_eckd_data_t);
507     	ccw = cqr->cpaddr;
508     	if (define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device, cqr)) {
509                     goto clear_cqr;
510             }        
511     	ccw->flags |= CCW_FLAG_CC;
512     	ccw++;
513     	if (locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT,
514                                device, 0, cqr)) {
515                     goto clear_cqr;
516             }       
517     	ccw->flags |= CCW_FLAG_CC;
518     	ccw++;
519     	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
520     	ccw->count = 8;
521     	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
522                     goto clear_cqr;
523             }
524     	ccw->flags |= CCW_FLAG_CC;
525     	ccw++;
526     	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
527     	ccw->count = 8;
528     	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
529                     goto clear_cqr;
530             }
531     	ccw->flags |= CCW_FLAG_CC;
532     	ccw++;
533     	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
534     	ccw->count = 8;
535     	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
536                     goto clear_cqr;
537             }
538     	ccw->flags |= CCW_FLAG_CC;
539     	ccw++;
540     	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
541     	ccw->count = 8;
542     	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
543                     goto clear_cqr;
544             }
545     	ccw->flags |= CCW_FLAG_CC;
546     	ccw++;
547     	if (locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT,
548                                device, 0, cqr)) {
549                     goto clear_cqr;
550             }       
551     	ccw->flags |= CCW_FLAG_CC;
552     	ccw++;
553     	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
554     	ccw->count = 8;
555     	if (dasd_set_normalized_cda (ccw, __pa (count_data), cqr, device)) {
556                     goto clear_cqr;
557             }
558     	cqr->device = device;
559     	cqr->retries = 0;
560     	cqr->status = CQR_STATUS_FILLED;
561             dasd_chanq_enq (&device->queue, cqr);
562             goto out;
563      clear_cqr:
564             dasd_free_request (cqr,device);
565             printk (KERN_WARNING PRINTK_HEADER
566                     "No memory to allocate initialization request\n");
567             cqr=NULL;
568      out:
569     	return cqr;
570     }
571     
572     static int
573     dasd_eckd_do_analysis (struct dasd_device_t *device)
574     {
575     	int sb, rpt;
576     	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
577     	eckd_count_t *count_area = NULL;
578     	char *cdl_msg;
579             int status;
580     	int i;
581     	private->uses_cdl = 1;
582             status = device->init_cqr->status;
583     	dasd_chanq_deq (&device->queue, device->init_cqr);
584     	dasd_free_request (device->init_cqr, device);
585     	/* Free the cqr and cleanup device->sizes */
586             if ( status != CQR_STATUS_DONE ) {
587                     DASD_MESSAGE (KERN_WARNING,device,"%s",
588                                   "volume analysis returned fatal error");
589                     return -EMEDIUMTYPE;
590             }
591     	/* Check Track 0 for Compatible Disk Layout */
592     	for (i = 0; i < 3; i++) {
593     		if ((i < 3) &&
594     		    ((private->count_area[i].kl != 4) ||
595     		     (private->count_area[i].dl !=
596     		      dasd_eckd_cdl_reclen (device, i) - 4))) {
597     			private->uses_cdl = 0;
598     			break;
599     		}
600     	}
601     	if (i == 3) {
602     		count_area = &private->count_area[4];
603     	}
604     	if (private->uses_cdl == 0) {
605     		for (i = 0; i < 5; i++) {
606     			if ((private->count_area[i].kl != 0) ||
607     			    (private->count_area[i].dl !=
608     			     private->count_area[0].dl)) {
609     				break;
610     			}
611     		}
612     		if (i == 5) {
613     			count_area = &private->count_area[0];
614     		}
615     	} else {
616     		if (private->count_area[3].record == 1) {
617     			DASD_MESSAGE (KERN_WARNING, device, "%s",
618     				      "Trk 0: no records after VTOC!");
619     		}
620     	}
621     	if (count_area != NULL &&	/* we found notthing violating our disk layout */
622     	    count_area->kl == 0) {
623                     /* find out blocksize */
624                     switch (count_area->dl) {
625                     case 512:
626     		case 1024:
627     		case 2048:
628     		case 4096:
629     			device->sizes.bp_block = count_area->dl;
630     			break;
631     		}
632     	}
633     	if (device->sizes.bp_block == 0) {
634     		DASD_MESSAGE (KERN_WARNING, device, "%s\n",
635     			      "Volume has incompatible disk layout");
636     		return -EMEDIUMTYPE;
637     	}
638     	device->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
639     	device->sizes.pt_block = 2;
640     	for (sb = 512; sb < device->sizes.bp_block; sb = sb << 1)
641     		device->sizes.s2b_shift++;
642     
643     	rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block);
644     	device->sizes.blocks = (private->rdc_data.no_cyl *
645     				private->rdc_data.trk_per_cyl *
646     				recs_per_track (&private->rdc_data, 0,
647     						device->sizes.bp_block));
648     	cdl_msg =
649     	    private->
650     	    uses_cdl ? "compatible disk layout" : "classic disk layout";
651     
652     	DASD_MESSAGE (KERN_INFO, device, "(%dkB blks): %dkB at %dkB/trk %s",
653     		      (device->sizes.bp_block >> 10),
654     		      (private->rdc_data.no_cyl *
655     		       private->rdc_data.trk_per_cyl *
656     		       recs_per_track (&private->rdc_data, 0,
657     				       device->sizes.bp_block) *
658     		       (device->sizes.bp_block >> 9)) >> 1,
659     		      (recs_per_track (&private->rdc_data, 0,
660     				       device->sizes.bp_block) *
661     		       device->sizes.bp_block) >> 10, cdl_msg);
662     	return 0;
663     }
664     
665     static int
666     dasd_eckd_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo)
667     {
668     	int rc = 0;
669     	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
670     	switch (device->sizes.bp_block) {
671     	case 512:
672     	case 1024:
673     	case 2048:
674     	case 4096:
675                 geo->sectors = recs_per_track (&(private->rdc_data), 
676                                                0, device->sizes.bp_block);
677                 break;
678     	default:
679                 break;
680     	}
681     	geo->cylinders = private->rdc_data.no_cyl;
682     	geo->heads = private->rdc_data.trk_per_cyl;
683     	return rc;
684     }
685     
686     static ccw_req_t *
687     dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata)
688     {
689     	int i;
690     	ccw_req_t *fcp = NULL;
691     	DE_eckd_data_t *DE_data = NULL;
692     	LO_eckd_data_t *LO_data = NULL;
693     	eckd_count_t *ct_data = NULL;
694     	eckd_count_t *r0_data = NULL;
695     	eckd_home_t *ha_data = NULL;
696     	ccw1_t *last_ccw = NULL;
697     	void *last_data = NULL;
698     	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
699     
700     	int rpt = recs_per_track (&(private->rdc_data), 0, fdata->blksize);
701     	int cyl = fdata->start_unit / private->rdc_data.trk_per_cyl;
702     	int head = fdata->start_unit % private->rdc_data.trk_per_cyl;
703     	int wrccws = rpt;
704     	int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
705             
706     	if (fdata->start_unit >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)){
707                     DASD_MESSAGE (KERN_INFO, device, "Track no %d too big!", fdata->start_unit);
708                     return NULL;
709             }
710             if ( fdata->start_unit > fdata->stop_unit) {
711                     DASD_MESSAGE (KERN_INFO, device, "Track %d reached! ending.",
712                                   fdata->start_unit);
713     		return NULL;
714     	}
715     	switch (fdata->blksize) {
716     	case 512:
717     	case 1024:
718     	case 2048:
719     	case 4096:
720     		break;
721     	default:
722     		printk (KERN_WARNING PRINTK_HEADER
723     			"Invalid blocksize %d...terminating!\n", fdata->blksize);
724     		return NULL;
725     	}
726     	switch (fdata->intensity) {
727     	case 0x00:
728     	case 0x01:
729     	case 0x03:
730     	case 0x04:		/* make track invalid */
731     	case 0x08:
732     	case 0x09:
733     	case 0x0b:
734     	case 0x0c:
735     		break;
736     	default:
737     		printk (KERN_WARNING PRINTK_HEADER
738     			"Invalid flags 0x%x...terminating!\n", fdata->intensity);
739     		return NULL;
740     	}
741     
742     	/* print status line */
743     	if ((private->rdc_data.no_cyl < 20) ?
744     	    (fdata->start_unit % private->rdc_data.no_cyl == 0) :
745     	    (fdata->start_unit % private->rdc_data.no_cyl == 0 &&
746     	     (fdata->start_unit / private->rdc_data.no_cyl) %
747     	     (private->rdc_data.no_cyl / 20))) {
748     		DASD_MESSAGE (KERN_INFO, device,
749     			      "Format Cylinder: %d Flags: %d\n",
750     			      fdata->start_unit / private->rdc_data.trk_per_cyl, fdata->intensity);
751     	}
752     	if ((fdata->intensity & ~0x8) & 0x04) {
753     		wrccws = 1;
754     		rpt = 1;
755     	} else {
756     		if (fdata->intensity & 0x1) {
757     			wrccws++;
758     			datasize += sizeof (eckd_count_t);
759     		}
760     		if (fdata->intensity & 0x2) {
761     			wrccws++;
762     			datasize += sizeof (eckd_home_t);
763     		}
764     	}
765     	fcp = dasd_alloc_request (dasd_eckd_discipline.name,
766     				 wrccws + 2 + 1,
767     				 datasize + rpt * sizeof (eckd_count_t),
768                                      device );
769     	if (fcp != NULL) {
770     		fcp->device = device;
771     		fcp->retries = 2;	/* set retry counter to enable ERP */
772     		last_data = fcp->data;
773     		DE_data = (DE_eckd_data_t *) last_data;
774     		last_data = (void *) (DE_data + 1);
775     		LO_data = (LO_eckd_data_t *) last_data;
776     		last_data = (void *) (LO_data + 1);
777     		if (fdata->intensity & 0x2) {
778     			ha_data = (eckd_home_t *) last_data;
779     			last_data = (void *) (ha_data + 1);
780     		}
781     		if (fdata->intensity & 0x1) {
782     			r0_data = (eckd_count_t *) last_data;
783     			last_data = (void *) (r0_data + 1);
784     		}
785     		ct_data = (eckd_count_t *) last_data;
786     
787     		last_ccw = fcp->cpaddr;
788     
789     		switch (fdata->intensity & ~0x08) {
790     		case 0x03:
791     			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
792     				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS,
793                                                device, fcp)) {
794                                     goto clear_fcp;
795                             }
796     			last_ccw->flags |= CCW_FLAG_CC;
797     			last_ccw++;
798     			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
799     				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,
800                                                device->sizes.bp_block, fcp)) {
801                                     goto clear_fcp;
802                             }
803     			last_ccw->flags |= CCW_FLAG_CC;
804     			last_ccw++;
805     			break;
806     		case 0x01:
807     			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
808                                                DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, fcp)) {
809                                     goto clear_fcp;
810                             }
811     			last_ccw->flags |= CCW_FLAG_CC;
812     			last_ccw++;
813     			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
814     				       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
815                                                device->sizes.bp_block, fcp)) {
816                                     goto clear_fcp;
817                             }
818     			last_ccw->flags |= CCW_FLAG_CC;
819     			last_ccw++;
820     			memset (r0_data, 0, sizeof (eckd_count_t));
821     			break;
822     		case 0x04:
823                             fdata->blksize = 8;
824     		case 0x00:
825     			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
826                                                DASD_ECKD_CCW_WRITE_CKD, device, fcp)) {
827                                     dasd_free_request (fcp, device);
828                                     return NULL;
829                             }
830     			last_ccw->flags |= CCW_FLAG_CC;
831     			last_ccw++;
832     			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
833                                                DASD_ECKD_CCW_WRITE_CKD, device, fdata->blksize, fcp)) {
834                                     goto clear_fcp;
835                             }
836     			last_ccw->flags |= CCW_FLAG_CC;
837     			last_ccw++;
838     			break;
839     		default:
840     			PRINT_WARN ("Unknown format flags...%d\n", fdata->intensity);
841     			return NULL;
842     		}
843     		if (fdata->intensity & 0x02) {
844     			PRINT_WARN ("Unsupported format flag...%d\n", fdata->intensity);
845     			return NULL;
846     		}
847     		if (fdata->intensity & 0x01) {	/* write record zero */
848     			r0_data->cyl = cyl;
849     			r0_data->head = head;
850     			r0_data->record = 0;
851     			r0_data->kl = 0;
852     			r0_data->dl = 8;
853     			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
854     			last_ccw->count = 8;
855     			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
856     			if (dasd_set_normalized_cda (last_ccw, __pa (r0_data), fcp, device)) {
857                                     goto clear_fcp;
858                             }
859     			last_ccw++;
860     		}
861     		if ((fdata->intensity & ~0x08) & 0x04) {	/* erase track */
862     			memset (ct_data, 0, sizeof (eckd_count_t));
863     			ct_data->cyl = cyl;
864     			ct_data->head = head;
865     			ct_data->record = 1;
866     			ct_data->kl = 0;
867     			ct_data->dl = 0;
868     			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
869     			last_ccw->count = 8;
870     			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
871     			if (dasd_set_normalized_cda (last_ccw, __pa (ct_data), fcp, device)) {
872                                     goto clear_fcp;
873                             }
874     			last_ccw++;
875     		} else {	/* write remaining records */
876     			for (i = 0; i < rpt; i++) {
877     				memset (ct_data + i, 0, sizeof (eckd_count_t));
878     				(ct_data + i)->cyl = cyl;
879     				(ct_data + i)->head = head;
880     				(ct_data + i)->record = i + 1;
881     				(ct_data + i)->kl = 0;
882     				if (fdata->intensity & 0x08) {
883     					// special handling when formatting CDL
884     					switch (fdata->start_unit) {
885     					case 0:
886     						if (i < 3) {
887     							(ct_data + i)->kl = 4;
888     							
889     							    (ct_data + i)->dl =
890     							    sizes_trk0[i] - 4;
891     						} else
892     							(ct_data + i)->dl = fdata->blksize;
893     						break;
894     					case 1:
895     						(ct_data + i)->kl = 44;
896     						(ct_data + i)->dl = LABEL_SIZE - 44;
897     						break;
898     					default:
899     						(ct_data + i)->dl = fdata->blksize;
900     						break;
901     					}
902     				} else
903     					(ct_data + i)->dl = fdata->blksize;
904     				last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
905     				last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
906     				last_ccw->count = 8;
907     				if (dasd_set_normalized_cda (last_ccw,
908                                                                  __pa (ct_data + i), fcp, device)) {
909                                     goto clear_fcp;
910                                     }
911     				last_ccw++;
912     			}
913     		}
914     		(last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
915     		fcp->device = device;
916     		fcp->status = CQR_STATUS_FILLED;
917     	}
918             goto out;
919      clear_fcp:
920             dasd_free_request (fcp, device);
921             fcp=NULL;
922      out:
923     	return fcp;
924     }
925     
926     static dasd_era_t
927     dasd_eckd_examine_error (ccw_req_t * cqr, devstat_t * stat)
928     {
929     	dasd_device_t *device = (dasd_device_t *) cqr->device;
930     
931     	if (stat->cstat == 0x00 &&
932     	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
933     		    return dasd_era_none;
934     
935     	switch (device->devinfo.sid_data.cu_type) {
936     	case 0x3990:
937     	case 0x2105:
938     		return dasd_3990_erp_examine (cqr, stat);
939     	case 0x9343:
940     		return dasd_9343_erp_examine (cqr, stat);
941     	default:
942     		printk (KERN_WARNING PRINTK_HEADER
943     			"default (unknown CU type) - RECOVERABLE return \n");
944     		return dasd_era_recover;
945     	}
946     }
947     
948     static dasd_erp_action_fn_t
949     dasd_eckd_erp_action (ccw_req_t * cqr)
950     {
951     	dasd_device_t *device = (dasd_device_t *) cqr->device;
952     
953     	switch (device->devinfo.sid_data.cu_type) {
954     	case 0x3990:
955     	case 0x2105:
956     		return dasd_3990_erp_action;
957     	case 0x9343:
958     		/* Return dasd_9343_erp_action; */
959     	default:
960     		return dasd_default_erp_action;
961     	}
962     }
963     
964     static dasd_erp_postaction_fn_t
965     dasd_eckd_erp_postaction (ccw_req_t * cqr)
966     {
967     	return dasd_default_erp_postaction;
968     }
969     
970     
971     inline unsigned char
972     dasd_eckd_cdl_cmd (dasd_device_t * device, int recid, int cmd)
973     {
974     	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
975     	int byt_per_blk = device->sizes.bp_block;
976     	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
977     	switch (cmd) {
978     	case READ:
979     		if (recid < 3)
980     			return DASD_ECKD_CCW_READ_KD_MT;
981     		if (recid < blk_per_trk)
982     			return DASD_ECKD_CCW_READ_MT;
983     		if (recid < 2 * blk_per_trk)
984     			return DASD_ECKD_CCW_READ_KD_MT;
985     		return DASD_ECKD_CCW_READ_MT;
986     		break;
987     	case WRITE:
988     		if (recid < 3)
989     			return DASD_ECKD_CCW_WRITE_KD_MT;
990     		if (recid < blk_per_trk)
991     			return DASD_ECKD_CCW_WRITE_MT;
992     		if (recid < 2 * blk_per_trk)
993     			return DASD_ECKD_CCW_WRITE_KD_MT;
994     		return DASD_ECKD_CCW_WRITE_MT;
995     		break;
996     	default:
997     		BUG ();
998     	}
999     	return 0;		// never executed
1000     }
1001     
1002     
1003     static ccw_req_t *
1004     dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
1005     {
1006     	ccw_req_t *rw_cp = NULL;
1007     	int rw_cmd;
1008     	int bhct;
1009     	long size;
1010     	ccw1_t *ccw;
1011     	DE_eckd_data_t *DE_data;
1012     	LO_eckd_data_t *LO_data;
1013     	struct buffer_head *bh;
1014     	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
1015     	int byt_per_blk = device->sizes.bp_block;
1016     	int shift = device->sizes.s2b_shift;
1017     	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
1018     	int btrk = (req->sector >> shift) / blk_per_trk;
1019     	int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk;
1020     	int recid = req->sector >> shift;
1021     	int locate4k_set = 0;
1022     	int nlocs = 0;
1023     
1024     	if (req->cmd == READ) {
1025     		rw_cmd = DASD_ECKD_CCW_READ_MT;
1026     	} else if (req->cmd == WRITE) {
1027     		rw_cmd = DASD_ECKD_CCW_WRITE_MT;
1028     	} else {
1029     		PRINT_ERR ("Unknown command %d\n", req->cmd);
1030     		return NULL;
1031     	}
1032     	/* Build the request */
1033     	/* count bhs to prevent errors, when bh smaller than block */
1034     	bhct = 0;
1035     	for (bh = req->bh; bh; bh = bh->b_reqnext) {
1036     		if (bh->b_size < byt_per_blk)
1037                             BUG();
1038                     bhct+= bh->b_size >> (device->sizes.s2b_shift+9);
1039     	}
1040     	if (btrk < 2 && private->uses_cdl) {
1041     		if (etrk < 2)
1042                             nlocs = bhct;
1043                     else
1044                             nlocs = 2 * blk_per_trk - recid;
1045     	}
1046     	rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 
1047                                         2 + nlocs + bhct + 1,
1048                                         sizeof (DE_eckd_data_t) + (1 +
1049                                                                    nlocs) *
1050                                         sizeof (LO_eckd_data_t),
1051                                         device);
1052     	if (!rw_cp) {
1053     		return NULL;
1054     	}
1055     	DE_data = rw_cp->data;
1056     	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
1057     	ccw = rw_cp->cpaddr;
1058     	if (define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device, rw_cp)) {
1059                     goto clear_rw_cp;
1060             }
1061     	ccw->flags |= CCW_FLAG_CC;
1062     	for (bh = req->bh; bh != NULL;) {
1063                     for (size = 0; size < bh->b_size; size += byt_per_blk) {
1064                             if (!locate4k_set) {
1065                                     // we need to chain a locate record before our rw-ccw
1066                                     ccw++;
1067                                     if ((recid / blk_per_trk) < 2
1068                                         && private->uses_cdl) {
1069                                             /* Do a locate record for our special blocks */
1070                                             int cmd = dasd_eckd_cdl_cmd (device,recid, req->cmd);
1071                                             if (locate_record (ccw, 
1072                                                            LO_data++,
1073                                                            recid / blk_per_trk, 
1074                                                            recid % blk_per_trk + 1, 
1075                                                            1, cmd, device,
1076                                                                dasd_eckd_cdl_reclen(device, recid), rw_cp)) {
1077                                                     goto clear_rw_cp;
1078                                             }
1079                                     } else {
1080                                             // Do a locate record for standard blocks */
1081                                             if (locate_record (ccw, 
1082                                                            LO_data++,
1083                                                            recid /blk_per_trk,
1084                                                            recid %blk_per_trk + 1,
1085                                                            (((req->sector +
1086                                                               req->nr_sectors) >>
1087                                                              shift) - recid), 
1088                                                            rw_cmd, device,
1089                                                                device->sizes.bp_block, rw_cp)) {
1090                                                     goto clear_rw_cp;
1091                                             }
1092                                             locate4k_set = 1;
1093                                     }
1094                                     ccw->flags |= CCW_FLAG_CC;
1095                             }
1096                             ccw++;
1097                             ccw->flags |= CCW_FLAG_CC;
1098                             ccw->cmd_code = locate4k_set ? rw_cmd :
1099                                     dasd_eckd_cdl_cmd (device, recid, req->cmd);
1100                             ccw->count = locate4k_set ? byt_per_blk :
1101                                     dasd_eckd_cdl_reclen (device, recid);
1102                             if (dasd_set_normalized_cda (ccw, __pa (bh->b_data+size), rw_cp, device)) {
1103                                     goto clear_rw_cp;
1104                             }
1105                             recid++;
1106                     }
1107                     bh = bh->b_reqnext;
1108     	}
1109     	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
1110     	rw_cp->device = device;
1111     	rw_cp->expires = 5 * TOD_MIN;	/* 5 minutes */
1112     	rw_cp->req = req;
1113     	rw_cp->lpm = LPM_ANYPATH;
1114     	rw_cp->retries = 2;
1115     	asm volatile ("STCK %0":"=m" (rw_cp->buildclk));
1116     	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
1117             goto out;
1118      clear_rw_cp:
1119             dasd_free_request (rw_cp, device);
1120             rw_cp=NULL;
1121      out:
1122     	return rw_cp;
1123     }
1124     
1125     #if 0
1126     int
1127     dasd_eckd_cleanup_request (ccw_req_t * cqr)
1128     {
1129     	int ret = 0;
1130     	struct request *req = cqr->req;
1131     	dasd_device_t *device = cqr->device;
1132     	int byt_per_blk = device->sizes.bp_block;
1133     
1134     	for (bh = req->bh; bh != NULL;) {
1135     		if (bh->b_size > byt_per_blk) {
1136     			for (size = 0; size < bh->b_size; size += byt_per_blk) {
1137     				ccw++;
1138     				ccw->flags |= CCW_FLAG_CC;
1139     				ccw->cmd_code = rw_cmd;
1140     				ccw->count = byt_per_blk;
1141     				set_normalized_cda (ccw,
1142     						    __pa (bh->b_data + size));
1143     			}
1144     			bh = bh->b_reqnext;
1145     		} else {	/* group N bhs to fit into byt_per_blk */
1146     			for (size = 0; bh != NULL && size < byt_per_blk;) {
1147     				ccw++;
1148     				ccw->flags |= CCW_FLAG_DC;
1149     				ccw->cmd_code = rw_cmd;
1150     				ccw->count = bh->b_size;
1151     				set_normalized_cda (ccw, __pa (bh->b_data));
1152     				size += bh->b_size;
1153     				bh = bh->b_reqnext;
1154     			}
1155     		}
1156     	}
1157     	return ret;
1158     }
1159     #endif
1160     ccw_req_t *
1161     dasd_eckd_reserve (struct dasd_device_t * device)
1162     {
1163     	ccw_req_t *cqr =
1164     	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
1165     	if (cqr == NULL) {
1166     		printk (KERN_WARNING PRINTK_HEADER
1167     			"No memory to allocate initialization request\n");
1168     		return NULL;
1169     	}
1170     	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
1171     	cqr->device = device;
1172     	cqr->retries = 0;
1173     	cqr->status = CQR_STATUS_FILLED;
1174     	return cqr;
1175     }
1176     
1177     ccw_req_t *
1178     dasd_eckd_release (struct dasd_device_t * device)
1179     {
1180     	ccw_req_t *cqr =
1181     	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
1182     	if (cqr == NULL) {
1183     		printk (KERN_WARNING PRINTK_HEADER
1184     			"No memory to allocate initialization request\n");
1185     		return NULL;
1186     	}
1187     	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
1188     	cqr->device = device;
1189     	cqr->retries = 0;
1190     	cqr->status = CQR_STATUS_FILLED;
1191     	return cqr;
1192     
1193     }
1194     
1195     static inline ccw1_t *
1196     dasd_eckd_find_cmd (ccw_req_t * cqr, int cmd)
1197     {
1198     	ccw1_t *cp;
1199     
1200     	cp = cqr->cpaddr;
1201     	do {
1202     		if (cp->cmd_code == cmd)
1203     			return cp;
1204     		if (cp->cmd_code == CCW_CMD_TIC) {
1205     			cp = (ccw1_t *) (long) cp->cda;
1206     			continue;
1207     		}
1208     		if (cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) {
1209     			cp++;
1210     			continue;
1211     		}
1212     		break;
1213     	} while (1);
1214     	return NULL;
1215     }
1216     
1217     static ccw_req_t *
1218     dasd_eckd_merge_cp (dasd_device_t * device)
1219     {
1220     	return NULL;
1221     }
1222     
1223     static int
1224     dasd_eckd_fill_info (dasd_device_t * device, dasd_information_t * info)
1225     {
1226     	int rc = 0;
1227     	info->label_block = 2;
1228     	if (((dasd_eckd_private_t *) device->private)->uses_cdl)
1229     		info->FBA_layout = 0;
1230     	else
1231     		info->FBA_layout = 1;
1232     	info->characteristics_size = sizeof (dasd_eckd_characteristics_t);
1233     	memcpy (info->characteristics,
1234     		&((dasd_eckd_private_t *) device->private)->rdc_data,
1235     		sizeof (dasd_eckd_characteristics_t));
1236     	info->confdata_size = sizeof (dasd_eckd_confdata_t);
1237     	memcpy (info->configuration_data,
1238     		&((dasd_eckd_private_t *) device->private)->conf_data,
1239     		sizeof (dasd_eckd_confdata_t));
1240     	return rc;
1241     }
1242     
1243     static char*
1244     dasd_eckd_dump_sense (struct dasd_device_t *device, 
1245                           ccw_req_t            *req)
1246     {
1247     
1248     	char *page = (char *) get_free_page (GFP_ATOMIC);
1249     	devstat_t *stat = &device->dev_status;
1250     	char *sense = stat->ii.sense.data;
1251     	int len, sl, sct;
1252     
1253     	if (page == NULL) {
1254                     printk (KERN_ERR PRINTK_HEADER
1255                             "No memory to dump sense data\n");
1256     		return NULL;
1257     	}
1258     
1259     	len = sprintf (page, KERN_ERR PRINTK_HEADER
1260     		       "device %04X on irq %d: I/O status report:\n",
1261     		       device->devinfo.devno, device->devinfo.irq);
1262     	len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1263     			"in req: %p CS: 0x%02X DS: 0x%02X\n",
1264     			req, stat->cstat, stat->dstat);
1265     	len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1266     			"Failing CCW: %p\n", (void *) (long) stat->cpa);
1267     	{
1268     		ccw1_t *act = req->cpaddr;
1269     		int i = req->cplength;
1270     		do {
1271     #ifdef ERP_DEBUG
1272     			printk (KERN_ERR "CCW %p: %08X %08X\n",
1273     				act, ((int *) act)[0], ((int *) act)[1]);
1274     			printk (KERN_ERR "DAT: %08X %08X %08X %08X\n",
1275     				((int *) act->cda)[0], ((int *) act->cda)[1],
1276     				((int *) act->cda)[2], ((int *) act->cda)[3]);
1277     #endif				/* ERP_DEBUG */
1278     			act++;
1279     		} while (--i);
1280     	}
1281     	if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
1282     		for (sl = 0; sl < 4; sl++) {
1283     			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1284     					"Sense(hex) %2d-%2d:",
1285     					(8 * sl), ((8 * sl) + 7));
1286     
1287     			for (sct = 0; sct < 8; sct++) {
1288     				len += sprintf (page + len, " %02x",
1289     						sense[8 * sl + sct]);
1290     			}
1291     			len += sprintf (page + len, "\n");
1292     		}
1293     
1294     		if (sense[27] & DASD_SENSE_BIT_0) {
1295     			/* 24 Byte Sense Data */
1296     			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1297     					"24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
1298     					sense[7] >> 4, sense[7] & 0x0f,
1299     					sense[1] & 0x10 ? "" : "no");
1300     		} else {
1301     			/* 32 Byte Sense Data */
1302     			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1303     					"32 Byte: Format: %x Exception class %x\n",
1304     					sense[6] & 0x0f, sense[22] >> 4);
1305     		}
1306     	}
1307     
1308             printk ("Sense data:\n%s", 
1309                     page);
1310     
1311             free_page ((unsigned long) page);
1312             
1313     	return NULL;
1314     }
1315     
1316     
1317     dasd_discipline_t dasd_eckd_discipline = {
1318             owner: THIS_MODULE,
1319     	name:"ECKD",
1320     	ebcname:"ECKD",
1321     	max_blocks:255,
1322     	id_check:dasd_eckd_id_check,
1323     	check_characteristics:dasd_eckd_check_characteristics,
1324     	init_analysis:dasd_eckd_init_analysis,
1325     	do_analysis:dasd_eckd_do_analysis,
1326     	fill_geometry:dasd_eckd_fill_geometry,
1327     	start_IO:dasd_start_IO,
1328     	term_IO:dasd_term_IO,
1329     	format_device:dasd_eckd_format_device,
1330     	examine_error:dasd_eckd_examine_error,
1331     	erp_action:dasd_eckd_erp_action,
1332     	erp_postaction:dasd_eckd_erp_postaction,
1333     	build_cp_from_req:dasd_eckd_build_cp_from_req,
1334     	dump_sense:dasd_eckd_dump_sense,
1335     	int_handler:dasd_int_handler,
1336     	reserve:dasd_eckd_reserve,
1337     	release:dasd_eckd_release,
1338     	merge_cp:dasd_eckd_merge_cp,
1339     	fill_info:dasd_eckd_fill_info,
1340     };
1341     
1342     int
1343     dasd_eckd_init (void)
1344     {
1345     	int rc = 0;
1346     	printk (KERN_INFO PRINTK_HEADER
1347     		"%s discipline initializing\n", dasd_eckd_discipline.name);
1348     	ASCEBC (dasd_eckd_discipline.ebcname, 4);
1349     	dasd_discipline_add (&dasd_eckd_discipline);
1350     #ifdef CONFIG_DASD_DYNAMIC
1351     	{
1352     		int i;
1353     		for (i = 0;
1354     		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
1355     		     i++) {
1356     			printk (KERN_INFO PRINTK_HEADER
1357     				"We are interested in: CU %04X/%02x\n",
1358     				dasd_eckd_known_devices[i].ci.hc.ctype,
1359     				dasd_eckd_known_devices[i].ci.hc.cmode);
1360     			s390_device_register (&dasd_eckd_known_devices[i]);
1361     		}
1362     	}
1363     #endif				/* CONFIG_DASD_DYNAMIC */
1364     	return rc;
1365     }
1366     
1367     void
1368     dasd_eckd_cleanup (void)
1369     {
1370     	printk (KERN_INFO PRINTK_HEADER
1371     		"%s discipline cleaning up\n", dasd_eckd_discipline.name);
1372     #ifdef CONFIG_DASD_DYNAMIC
1373     	{
1374     		int i;
1375     		for (i = 0;
1376     		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
1377     		     i++) {
1378     			printk (KERN_INFO PRINTK_HEADER
1379     				"We were interested in: CU %04X/%02x\n",
1380     				dasd_eckd_known_devices[i].ci.hc.ctype,
1381     				dasd_eckd_known_devices[i].ci.hc.cmode);
1382     			s390_device_unregister (&dasd_eckd_known_devices[i]);
1383     		}
1384     	}
1385     #endif				/* CONFIG_DASD_DYNAMIC */
1386     	dasd_discipline_del (&dasd_eckd_discipline);
1387     }
1388     
1389     #ifdef MODULE
1390     int
1391     init_module (void)
1392     {
1393     	int rc = 0;
1394     	rc = dasd_eckd_init ();
1395     	return rc;
1396     }
1397     
1398     void
1399     cleanup_module (void)
1400     {
1401     	dasd_eckd_cleanup ();
1402     	return;
1403     }
1404     #endif
1405     
1406     /*
1407      * Overrides for Emacs so that we follow Linus's tabbing style.
1408      * Emacs will notice this stuff at the end of the file and automatically
1409      * adjust the settings for this buffer only.  This must remain at the end
1410      * of the file.
1411      * ---------------------------------------------------------------------------
1412      * Local variables:
1413      * c-indent-level: 4 
1414      * c-brace-imaginary-offset: 0
1415      * c-brace-offset: -4
1416      * c-argdecl-indent: 4
1417      * c-label-offset: -4
1418      * c-continued-statement-offset: 4
1419      * c-continued-brace-offset: 0
1420      * indent-tabs-mode: nil
1421      * tab-width: 8
1422      * End:
1423      */
1424