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
58dasd_discipline_t dasd_eckd_discipline;
59
60typedef struct
61dasd_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
69static
70devreg_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
95int sizes_trk0[] = { 28, 148, 84 };
96#define LABEL_SIZE 140
97
98static inline unsigned int
99round_up_multiple (unsigned int no, unsigned int mult)
100{
101	int rem = no % mult;
102	return (rem ? no - rem + mult : no);
103}
104
105static inline unsigned int
106ceil_quot (unsigned int d1, unsigned int d2)
107{
108	return (d1 + (d2 - 1)) / d2;
109}
110
111static inline int
112bytes_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
151static inline unsigned int
152bytes_per_track (dasd_eckd_characteristics_t * rdc)
153{
154	return *(unsigned int *) (rdc->byte_per_track) >> 8;
155}
156
157static inline unsigned int
158recs_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
193static inline int
194define_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
264static inline int
265locate_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
376static int
377dasd_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
391static int
392dasd_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
471static inline int
472dasd_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
486static ccw_req_t *
487dasd_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
572static int
573dasd_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 unformatted disk");
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",
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
665static int
666dasd_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
686static ccw_req_t *
687dasd_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",
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
926static dasd_era_t
927dasd_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
948static dasd_erp_action_fn_t
949dasd_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
964static dasd_erp_postaction_fn_t
965dasd_eckd_erp_postaction (ccw_req_t * cqr)
966{
967	return dasd_default_erp_postaction;
968}
969
970
971inline unsigned char
972dasd_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
1003static ccw_req_t *
1004dasd_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 = byt_per_blk;
1101                        if (!locate4k_set) {
1102                                ccw->count = dasd_eckd_cdl_reclen (device,recid);
1103                                if (ccw->count < byt_per_blk) {
1104                                    memset (bh->b_data + size + ccw->count,
1105                                            0xE5, byt_per_blk - ccw->count);
1106                                }
1107                        }
1108                        if (dasd_set_normalized_cda (ccw, __pa (bh->b_data+size), rw_cp, device)) {
1109                                goto clear_rw_cp;
1110                        }
1111                        recid++;
1112                }
1113                bh = bh->b_reqnext;
1114	}
1115	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
1116	rw_cp->device = device;
1117	rw_cp->expires = 5 * TOD_MIN;	/* 5 minutes */
1118	rw_cp->req = req;
1119	rw_cp->lpm = LPM_ANYPATH;
1120	rw_cp->retries = 2;
1121	asm volatile ("STCK %0":"=m" (rw_cp->buildclk));
1122	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
1123        goto out;
1124 clear_rw_cp:
1125        dasd_free_request (rw_cp, device);
1126        rw_cp=NULL;
1127 out:
1128	return rw_cp;
1129}
1130
1131
1132/*
1133 * DASD_ECKD_RESERVE
1134 *
1135 * DESCRIPTION
1136 *    Buils a channel programm to reserve a device.
1137 *    Options are set to 'synchronous wait for interrupt' and
1138 *    'timeout the request'. This leads to an terminate IO if
1139 *    the interrupt is outstanding for a certain time.
1140 */
1141ccw_req_t *
1142dasd_eckd_reserve (struct dasd_device_t * device)
1143{
1144	ccw_req_t *cqr =
1145	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
1146	if (cqr == NULL) {
1147		printk (KERN_WARNING PRINTK_HEADER
1148			"No memory to allocate initialization request\n");
1149		return NULL;
1150	}
1151	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
1152	cqr->device  = device;
1153	cqr->retries = 0;
1154	cqr->expires = 10 * TOD_SEC;
1155        cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */
1156	cqr->status  = CQR_STATUS_FILLED;
1157	return cqr;
1158}
1159
1160/*
1161 * DASD_ECKD_RELEASE
1162 *
1163 * DESCRIPTION
1164 *    Buils a channel programm to releases a prior reserved
1165 *    (see dasd_eckd_reserve) device.
1166 */
1167ccw_req_t *
1168dasd_eckd_release (struct dasd_device_t * device)
1169{
1170	ccw_req_t *cqr =
1171	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
1172	if (cqr == NULL) {
1173		printk (KERN_WARNING PRINTK_HEADER
1174			"No memory to allocate initialization request\n");
1175		return NULL;
1176	}
1177	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
1178	cqr->device  = device;
1179	cqr->retries = 0;
1180	cqr->expires = 10 * TOD_SEC;
1181        cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */
1182	cqr->status  = CQR_STATUS_FILLED;
1183	return cqr;
1184
1185}
1186
1187/*
1188 * DASD_ECKD_STEAL_LOCK
1189 *
1190 * DESCRIPTION
1191 *    Buils a channel programm to break a device's reservation.
1192 *    (unconditional reserve)
1193 */
1194ccw_req_t *
1195dasd_eckd_steal_lock (struct dasd_device_t * device)
1196{
1197	ccw_req_t *cqr =
1198	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
1199	if (cqr == NULL) {
1200		printk (KERN_WARNING PRINTK_HEADER
1201			"No memory to allocate initialization request\n");
1202		return NULL;
1203	}
1204	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK;
1205	cqr->device  = device;
1206	cqr->retries = 0;
1207	cqr->expires = 10 * TOD_SEC;
1208        cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */
1209	cqr->status  = CQR_STATUS_FILLED;
1210	return cqr;
1211}
1212
1213static inline ccw1_t *
1214dasd_eckd_find_cmd (ccw_req_t * cqr, int cmd)
1215{
1216	ccw1_t *cp;
1217
1218	cp = cqr->cpaddr;
1219	do {
1220		if (cp->cmd_code == cmd)
1221			return cp;
1222		if (cp->cmd_code == CCW_CMD_TIC) {
1223			cp = (ccw1_t *) (long) cp->cda;
1224			continue;
1225		}
1226		if (cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) {
1227			cp++;
1228			continue;
1229		}
1230		break;
1231	} while (1);
1232	return NULL;
1233}
1234
1235static ccw_req_t *
1236dasd_eckd_merge_cp (dasd_device_t * device)
1237{
1238	return NULL;
1239}
1240
1241static int
1242dasd_eckd_fill_info (dasd_device_t * device, dasd_information_t * info)
1243{
1244	int rc = 0;
1245	info->label_block = 2;
1246	if (((dasd_eckd_private_t *) device->private)->uses_cdl)
1247		info->FBA_layout = 0;
1248	else
1249		info->FBA_layout = 1;
1250	info->characteristics_size = sizeof (dasd_eckd_characteristics_t);
1251	memcpy (info->characteristics,
1252		&((dasd_eckd_private_t *) device->private)->rdc_data,
1253		sizeof (dasd_eckd_characteristics_t));
1254	info->confdata_size = sizeof (dasd_eckd_confdata_t);
1255	memcpy (info->configuration_data,
1256		&((dasd_eckd_private_t *) device->private)->conf_data,
1257		sizeof (dasd_eckd_confdata_t));
1258	return rc;
1259}
1260
1261static char*
1262dasd_eckd_dump_sense (struct dasd_device_t *device,
1263                      ccw_req_t            *req)
1264{
1265
1266	char *page = (char *) get_free_page (GFP_ATOMIC);
1267	devstat_t *stat = &device->dev_status;
1268	char *sense = stat->ii.sense.data;
1269	int len, sl, sct;
1270
1271	if (page == NULL) {
1272                printk (KERN_ERR PRINTK_HEADER
1273                        "No memory to dump sense data\n");
1274		return NULL;
1275	}
1276
1277	len = sprintf (page, KERN_ERR PRINTK_HEADER
1278		       "device %04X on irq %d: I/O status report:\n",
1279		       device->devinfo.devno, device->devinfo.irq);
1280	len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1281			"in req: %p CS: 0x%02X DS: 0x%02X\n",
1282			req, stat->cstat, stat->dstat);
1283	len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1284			"Failing CCW: %p\n", (void *) (long) stat->cpa);
1285	{
1286		ccw1_t *act = req->cpaddr;
1287		int i = req->cplength;
1288		do {
1289#ifdef ERP_DEBUG
1290			printk (KERN_ERR "CCW %p: %08X %08X\n",
1291				act, ((int *) act)[0], ((int *) act)[1]);
1292			printk (KERN_ERR "DAT: %08X %08X %08X %08X\n",
1293				((int *) act->cda)[0], ((int *) act->cda)[1],
1294				((int *) act->cda)[2], ((int *) act->cda)[3]);
1295#endif				/* ERP_DEBUG */
1296			act++;
1297		} while (--i);
1298	}
1299	if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
1300		for (sl = 0; sl < 4; sl++) {
1301			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1302					"Sense(hex) %2d-%2d:",
1303					(8 * sl), ((8 * sl) + 7));
1304
1305			for (sct = 0; sct < 8; sct++) {
1306				len += sprintf (page + len, " %02x",
1307						sense[8 * sl + sct]);
1308			}
1309			len += sprintf (page + len, "\n");
1310		}
1311
1312		if (sense[27] & DASD_SENSE_BIT_0) {
1313			/* 24 Byte Sense Data */
1314			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1315					"24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
1316					sense[7] >> 4, sense[7] & 0x0f,
1317					sense[1] & 0x10 ? "" : "no");
1318		} else {
1319			/* 32 Byte Sense Data */
1320			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1321					"32 Byte: Format: %x Exception class %x\n",
1322					sense[6] & 0x0f, sense[22] >> 4);
1323		}
1324	}
1325
1326        printk ("Sense data:\n%s",
1327                page);
1328
1329        free_page ((unsigned long) page);
1330
1331	return NULL;
1332}
1333
1334
1335dasd_discipline_t dasd_eckd_discipline = {
1336        owner: THIS_MODULE,
1337	name:"ECKD",
1338	ebcname:"ECKD",
1339	max_blocks:255,
1340	id_check:dasd_eckd_id_check,
1341	check_characteristics:dasd_eckd_check_characteristics,
1342	init_analysis:dasd_eckd_init_analysis,
1343	do_analysis:dasd_eckd_do_analysis,
1344	fill_geometry:dasd_eckd_fill_geometry,
1345	start_IO:dasd_start_IO,
1346	term_IO:dasd_term_IO,
1347	format_device:dasd_eckd_format_device,
1348	examine_error:dasd_eckd_examine_error,
1349	erp_action:dasd_eckd_erp_action,
1350	erp_postaction:dasd_eckd_erp_postaction,
1351	build_cp_from_req:dasd_eckd_build_cp_from_req,
1352	dump_sense:dasd_eckd_dump_sense,
1353	int_handler:dasd_int_handler,
1354	reserve:dasd_eckd_reserve,
1355	release:dasd_eckd_release,
1356        steal_lock:dasd_eckd_steal_lock,
1357	merge_cp:dasd_eckd_merge_cp,
1358	fill_info:dasd_eckd_fill_info,
1359};
1360
1361int
1362dasd_eckd_init (void)
1363{
1364	int rc = 0;
1365	printk (KERN_INFO PRINTK_HEADER
1366		"%s discipline initializing\n", dasd_eckd_discipline.name);
1367	ASCEBC (dasd_eckd_discipline.ebcname, 4);
1368	dasd_discipline_add (&dasd_eckd_discipline);
1369#ifdef CONFIG_DASD_DYNAMIC
1370	{
1371		int i;
1372		for (i = 0;
1373		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
1374		     i++) {
1375			printk (KERN_INFO PRINTK_HEADER
1376				"We are interested in: CU %04X/%02x\n",
1377				dasd_eckd_known_devices[i].ci.hc.ctype,
1378				dasd_eckd_known_devices[i].ci.hc.cmode);
1379			s390_device_register (&dasd_eckd_known_devices[i]);
1380		}
1381	}
1382#endif				/* CONFIG_DASD_DYNAMIC */
1383	return rc;
1384}
1385
1386void
1387dasd_eckd_cleanup (void)
1388{
1389	printk (KERN_INFO PRINTK_HEADER
1390		"%s discipline cleaning up\n", dasd_eckd_discipline.name);
1391#ifdef CONFIG_DASD_DYNAMIC
1392	{
1393		int i;
1394		for (i = 0;
1395		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
1396		     i++) {
1397			printk (KERN_INFO PRINTK_HEADER
1398				"We were interested in: CU %04X/%02x\n",
1399				dasd_eckd_known_devices[i].ci.hc.ctype,
1400				dasd_eckd_known_devices[i].ci.hc.cmode);
1401			s390_device_unregister (&dasd_eckd_known_devices[i]);
1402		}
1403	}
1404#endif				/* CONFIG_DASD_DYNAMIC */
1405	dasd_discipline_del (&dasd_eckd_discipline);
1406}
1407
1408#ifdef MODULE
1409int
1410init_module (void)
1411{
1412	int rc = 0;
1413	rc = dasd_eckd_init ();
1414	return rc;
1415}
1416
1417void
1418cleanup_module (void)
1419{
1420	dasd_eckd_cleanup ();
1421	return;
1422}
1423#endif
1424
1425/*
1426 * Overrides for Emacs so that we follow Linus's tabbing style.
1427 * Emacs will notice this stuff at the end of the file and automatically
1428 * adjust the settings for this buffer only.  This must remain at the end
1429 * of the file.
1430 * ---------------------------------------------------------------------------
1431 * Local variables:
1432 * c-indent-level: 4
1433 * c-brace-imaginary-offset: 0
1434 * c-brace-offset: -4
1435 * c-argdecl-indent: 4
1436 * c-label-offset: -4
1437 * c-continued-statement-offset: 4
1438 * c-continued-brace-offset: 0
1439 * indent-tabs-mode: nil
1440 * tab-width: 8
1441 * End:
1442 */
1443