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