1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/config.h>
27#include <linux/stddef.h>
28#include <linux/kernel.h>
29#include <linux/slab.h>
30#include <linux/hdreg.h>
31#include <linux/blk.h>
32
33#include <asm/debug.h>
34#include <asm/ccwcache.h>
35#include <asm/idals.h>
36#include <asm/ebcdic.h>
37#include <asm/io.h>
38#include <asm/irq.h>
39#include <asm/s390dyn.h>
40
41#include "dasd_int.h"
42#include "dasd_eckd.h"
43
44#ifdef PRINTK_HEADER
45#undef PRINTK_HEADER
46#endif
47#define PRINTK_HEADER DASD_NAME"(eckd):"
48
49#define ECKD_C0(i) (i->home_bytes)
50#define ECKD_F(i) (i->formula)
51#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1))
52#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2))
53#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3))
54#define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0)
55#define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0)
56#define ECKD_F6(i) (i->factor6)
57#define ECKD_F7(i) (i->factor7)
58#define ECKD_F8(i) (i->factor8)
59
60#ifdef MODULE
61#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
62MODULE_LICENSE("GPL");
63#endif
64#endif
65
66dasd_discipline_t dasd_eckd_discipline;
67
68typedef struct dasd_eckd_private_t {
69 dasd_eckd_characteristics_t rdc_data;
70 dasd_eckd_confdata_t conf_data;
71 eckd_count_t count_area[5];
72 int uses_cdl;
73 attrib_data_t attrib;
74} dasd_eckd_private_t;
75
76#ifdef CONFIG_DASD_DYNAMIC
77static
78devreg_t dasd_eckd_known_devices[] = {
79 {
80 ci: { hc: {ctype:0x3880, dtype: 0x3390}},
81 flag:(DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE |
82 DEVREG_TYPE_DEVCHARS),
83 oper_func:dasd_oper_handler
84 },
85 {
86 ci: { hc: {ctype:0x3990}},
87 flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
88 oper_func:dasd_oper_handler
89 },
90 {
91 ci: { hc: {ctype:0x2105}},
92 flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
93 oper_func:dasd_oper_handler
94 },
95 {
96 ci: { hc: {ctype:0x9343}},
97 flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
98 oper_func:dasd_oper_handler
99 }
100};
101#endif
102
103int sizes_trk0[] = { 28, 148, 84 };
104#define LABEL_SIZE 140
105
106static inline unsigned int
107round_up_multiple (unsigned int no, unsigned int mult)
108{
109 int rem = no % mult;
110 return (rem ? no - rem + mult : no);
111}
112
113static inline unsigned int
114ceil_quot (unsigned int d1, unsigned int d2)
115{
116 return (d1 + (d2 - 1)) / d2;
117}
118
119static inline int
120bytes_per_record (dasd_eckd_characteristics_t * rdc, int kl,
121 int dl )
122{
123 int bpr = 0;
124 switch (rdc->formula) {
125 case 0x01:{
126 unsigned int fl1, fl2;
127 fl1 = round_up_multiple (ECKD_F2 (rdc) + dl,
128 ECKD_F1 (rdc));
129 fl2 = round_up_multiple (kl ? ECKD_F2 (rdc) + kl : 0,
130 ECKD_F1 (rdc));
131 bpr = fl1 + fl2;
132 break;
133 }
134 case 0x02:{
135 unsigned int fl1, fl2, int1, int2;
136 int1 = ceil_quot (dl + ECKD_F6 (rdc),
137 ECKD_F5 (rdc) << 1);
138 int2 = ceil_quot (kl + ECKD_F6 (rdc),
139 ECKD_F5 (rdc) << 1);
140 fl1 = round_up_multiple (ECKD_F1 (rdc) *
141 ECKD_F2 (rdc) +
142 (dl + ECKD_F6 (rdc) +
143 ECKD_F4 (rdc) * int1),
144 ECKD_F1 (rdc));
145 fl2 = round_up_multiple (ECKD_F1 (rdc) *
146 ECKD_F3 (rdc) +
147 (kl + ECKD_F6 (rdc) +
148 ECKD_F4 (rdc) * int2),
149 ECKD_F1 (rdc));
150 bpr = fl1 + fl2;
151 break;
152 }
153 default:
154
155 MESSAGE (KERN_ERR,
156 "unknown formula%d",
157 rdc->formula);
158 }
159 return bpr;
160}
161
162static inline unsigned int
163bytes_per_track (dasd_eckd_characteristics_t * rdc)
164{
165 return *(unsigned int *) (rdc->byte_per_track) >> 8;
166}
167
168static inline unsigned int
169recs_per_track (dasd_eckd_characteristics_t * rdc,
170 unsigned int kl, unsigned int dl)
171{
172 int rpt = 0;
173 int dn;
174 switch (rdc->dev_type) {
175 case 0x3380:
176 if (kl)
177 return 1499 / (15 +
178 7 + ceil_quot (kl + 12, 32) +
179 ceil_quot (dl + 12, 32));
180 else
181 return 1499 / (15 + ceil_quot (dl + 12, 32));
182 case 0x3390:
183 dn = ceil_quot (dl + 6, 232) + 1;
184 if (kl) {
185 int kn = ceil_quot (kl + 6, 232) + 1;
186 return 1729 / (10 +
187 9 + ceil_quot (kl + 6 * kn, 34) +
188 9 + ceil_quot (dl + 6 * dn, 34));
189 } else
190 return 1729 / (10 + 9 + ceil_quot (dl + 6 * dn, 34));
191 case 0x9345:
192 dn = ceil_quot (dl + 6, 232) + 1;
193 if (kl) {
194 int kn = ceil_quot (kl + 6, 232) + 1;
195 return 1420 / (18 +
196 7 + ceil_quot (kl + 6 * kn, 34) +
197 ceil_quot (dl + 6 * dn, 34));
198 } else
199 return 1420 / (18 + 7 + ceil_quot (dl + 6 * dn, 34));
200 }
201 return rpt;
202}
203
204static inline void
205check_XRC (ccw1_t *de_ccw,
206 DE_eckd_data_t *data,
207 dasd_device_t *device)
208{
209
210 dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
211
212
213 if (private->rdc_data.facilities.XRC_supported) {
214
215 data->ga_extended |= 0x08;
216 data->ga_extended |= 0x02;
217
218 data->ep_sys_time = get_clock ();
219
220 de_ccw->count = sizeof (DE_eckd_data_t);
221 de_ccw->flags |= CCW_FLAG_SLI;
222 }
223
224 return;
225
226}
227
228static inline int
229define_extent (ccw1_t * de_ccw,
230 DE_eckd_data_t * data,
231 int trk, int totrk,
232 int cmd, dasd_device_t * device, ccw_req_t* cqr)
233{
234 int rc=0;
235 ch_t geo, beg, end;
236 dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
237
238 geo.cyl = private->rdc_data.no_cyl;
239 geo.head = private->rdc_data.trk_per_cyl;
240 beg.cyl = trk / geo.head;
241 beg.head = trk % geo.head;
242 end.cyl = totrk / geo.head;
243 end.head = totrk % geo.head;
244
245 memset (de_ccw, 0, sizeof (ccw1_t));
246
247 de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
248 de_ccw->count = 16;
249
250 if ((rc=dasd_set_normalized_cda (de_ccw, __pa (data), cqr, device)))
251 return rc;
252
253 memset (data, 0, sizeof (DE_eckd_data_t));
254 switch (cmd) {
255 case DASD_ECKD_CCW_READ_HOME_ADDRESS:
256 case DASD_ECKD_CCW_READ_RECORD_ZERO:
257 case DASD_ECKD_CCW_READ:
258 case DASD_ECKD_CCW_READ_MT:
259 case DASD_ECKD_CCW_READ_CKD:
260 case DASD_ECKD_CCW_READ_CKD_MT:
261 case DASD_ECKD_CCW_READ_KD:
262 case DASD_ECKD_CCW_READ_KD_MT:
263 case DASD_ECKD_CCW_READ_COUNT:
264 data->mask.perm = 0x1;
265 data->attributes.operation = private->attrib.operation;
266 break;
267 case DASD_ECKD_CCW_WRITE:
268 case DASD_ECKD_CCW_WRITE_MT:
269 case DASD_ECKD_CCW_WRITE_KD:
270 case DASD_ECKD_CCW_WRITE_KD_MT:
271 data->mask.perm = 0x02;
272 data->attributes.operation = private->attrib.operation;
273
274 check_XRC (de_ccw,
275 data,
276 device);
277 break;
278 case DASD_ECKD_CCW_WRITE_CKD:
279 case DASD_ECKD_CCW_WRITE_CKD_MT:
280 data->attributes.operation = DASD_BYPASS_CACHE;
281
282 check_XRC (de_ccw,
283 data,
284 device);
285 break;
286 case DASD_ECKD_CCW_ERASE:
287 case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
288 case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
289 data->mask.perm = 0x3;
290 data->mask.auth = 0x1;
291 data->attributes.operation = DASD_BYPASS_CACHE;
292
293 check_XRC (de_ccw,
294 data,
295 device);
296 break;
297 default:
298
299 MESSAGE (KERN_ERR,
300 "unknown opcode 0x%x",
301 cmd);
302
303 break;
304 }
305
306 data->attributes.mode = 0x3;
307
308 if (private->rdc_data.cu_type == 0x2105
309 && !(private->uses_cdl && trk < 2) ) {
310
311 data->ga_extended |= 0x40;
312 }
313
314
315 if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
316 data->attributes.operation == DASD_SEQ_ACCESS ) {
317
318 if (end.cyl + private->attrib.nr_cyl < geo.cyl) {
319
320 end.cyl += private->attrib.nr_cyl;
321
322 DBF_DEV_EVENT (DBF_NOTICE, device,
323 "Enhanced DE Cylinder from %x to %x",
324 (totrk / geo.head),
325 end.cyl);
326
327
328 } else {
329 end.cyl = (geo.cyl -1);
330
331 DBF_DEV_EVENT (DBF_NOTICE, device,
332 "Enhanced DE Cylinder from %x to "
333 "End of device %x",
334 (totrk / geo.head),
335 end.cyl);
336
337 }
338 }
339
340 data->beg_ext.cyl = beg.cyl;
341 data->beg_ext.head = beg.head;
342 data->end_ext.cyl = end.cyl;
343 data->end_ext.head = end.head;
344
345 return rc;
346}
347
348static inline int
349locate_record (ccw1_t * lo_ccw,
350 LO_eckd_data_t * data,
351 int trk,
352 int rec_on_trk,
353 int no_rec,
354 int cmd,
355 dasd_device_t * device,
356 int reclen,
357 ccw_req_t* cqr)
358{
359 int rc=0;
360 dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
361 ch_t geo = { private->rdc_data.no_cyl,
362 private->rdc_data.trk_per_cyl
363 };
364 ch_t seek = { trk / (geo.head), trk % (geo.head) };
365 int sector = 0;
366
367 DBF_EVENT (DBF_INFO,
368 "Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d",
369 trk,
370 rec_on_trk,
371 no_rec,
372 cmd,
373 reclen);
374
375 memset (lo_ccw, 0, sizeof (ccw1_t));
376 lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
377 lo_ccw->count = 16;
378 if ((rc=dasd_set_normalized_cda (lo_ccw, __pa (data), cqr, device)))
379 return rc;
380
381 memset (data, 0, sizeof (LO_eckd_data_t));
382 if (rec_on_trk) {
383 switch (private->rdc_data.dev_type) {
384 case 0x3390:{
385 int dn, d;
386 dn = ceil_quot (reclen + 6, 232);
387 d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34);
388 sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8;
389 break;
390 }
391 case 0x3380:{
392 int d;
393 d = 7 + ceil_quot (reclen + 12, 32);
394 sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;
395 break;
396 }
397 case 0x9345:
398 default:
399 sector = 0;
400 }
401 }
402 data->sector = sector;
403 data->count = no_rec;
404 switch (cmd) {
405 case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
406 data->operation.orientation = 0x3;
407 data->operation.operation = 0x03;
408 break;
409 case DASD_ECKD_CCW_READ_HOME_ADDRESS:
410 data->operation.orientation = 0x3;
411 data->operation.operation = 0x16;
412 break;
413 case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
414 data->operation.orientation = 0x1;
415 data->operation.operation = 0x03;
416 data->count++;
417 break;
418 case DASD_ECKD_CCW_READ_RECORD_ZERO:
419 data->operation.orientation = 0x3;
420 data->operation.operation = 0x16;
421 data->count++;
422 break;
423 case DASD_ECKD_CCW_WRITE:
424 case DASD_ECKD_CCW_WRITE_MT:
425 case DASD_ECKD_CCW_WRITE_KD:
426 case DASD_ECKD_CCW_WRITE_KD_MT:
427 data->auxiliary.last_bytes_used = 0x1;
428 data->length = reclen;
429 data->operation.operation = 0x01;
430 break;
431 case DASD_ECKD_CCW_WRITE_CKD:
432 case DASD_ECKD_CCW_WRITE_CKD_MT:
433 data->auxiliary.last_bytes_used = 0x1;
434 data->length = reclen;
435 data->operation.operation = 0x03;
436 break;
437 case DASD_ECKD_CCW_READ:
438 case DASD_ECKD_CCW_READ_MT:
439 case DASD_ECKD_CCW_READ_KD:
440 case DASD_ECKD_CCW_READ_KD_MT:
441 data->auxiliary.last_bytes_used = 0x1;
442 data->length = reclen;
443 data->operation.operation = 0x06;
444 break;
445 case DASD_ECKD_CCW_READ_CKD:
446 case DASD_ECKD_CCW_READ_CKD_MT:
447 data->auxiliary.last_bytes_used = 0x1;
448 data->length = reclen;
449 data->operation.operation = 0x16;
450 break;
451 case DASD_ECKD_CCW_READ_COUNT:
452 data->operation.operation = 0x06;
453 break;
454 case DASD_ECKD_CCW_ERASE:
455 data->length = reclen;
456 data->auxiliary.last_bytes_used = 0x1;
457 data->operation.operation = 0x0b;
458 break;
459 default:
460
461 MESSAGE (KERN_ERR,
462 "unknown opcode 0x%x",
463 cmd);
464 }
465 memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
466 memcpy (&(data->search_arg), &seek, sizeof (ch_t));
467 data->search_arg.record = rec_on_trk;
468 return rc;
469}
470
471static int
472dasd_eckd_id_check (s390_dev_info_t * info)
473{
474 if (info->sid_data.cu_type == 0x3990 ||
475 info->sid_data.cu_type == 0x2105)
476 if (info->sid_data.dev_type == 0x3390) return 0;
477 if (info->sid_data.cu_type == 0x3990 ||
478 info->sid_data.cu_type == 0x2105)
479 if (info->sid_data.dev_type == 0x3380) return 0;
480 if (info->sid_data.cu_type == 0x9343)
481 if (info->sid_data.dev_type == 0x9345)
482 return 0;
483 return -ENODEV;
484}
485
486static int
487dasd_eckd_check_characteristics (struct dasd_device_t *device)
488{
489 int rc = 0;
490 void *conf_data;
491 void *rdc_data;
492 int conf_len;
493 dasd_eckd_private_t *private;
494
495 if (device == NULL) {
496
497 MESSAGE (KERN_WARNING, "%s",
498 "Null device pointer passed to characteristics "
499 "checker");
500
501 return -ENODEV;
502 }
503 device->private = kmalloc (sizeof (dasd_eckd_private_t),
504 GFP_KERNEL);
505
506 if (device->private == NULL) {
507
508 MESSAGE (KERN_WARNING, "%s",
509 "memory allocation failed for private data");
510
511 rc = -ENOMEM;
512 goto fail;
513 }
514
515 private = (dasd_eckd_private_t *) device->private;
516 rdc_data = (void *) &(private->rdc_data);
517
518
519 rc = read_dev_chars (device->devinfo.irq,
520 &rdc_data,
521 64);
522 if (rc) {
523
524 MESSAGE (KERN_WARNING,
525 "Read device characteristics returned error %d",
526 rc);
527
528 goto fail;
529 }
530
531 DEV_MESSAGE (KERN_INFO, device,
532 "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
533 private->rdc_data.dev_type,
534 private->rdc_data.dev_model,
535 private->rdc_data.cu_type,
536 private->rdc_data.cu_model.model,
537 private->rdc_data.no_cyl,
538 private->rdc_data.trk_per_cyl,
539 private->rdc_data.sec_per_trk);
540
541
542 private->attrib.operation = DASD_NORMAL_CACHE;
543 private->attrib.nr_cyl = 0;
544
545
546 rc = read_conf_data (device->devinfo.irq,
547 &conf_data,
548 &conf_len,
549 LPM_ANYPATH);
550
551 if (rc == -EOPNOTSUPP) {
552 rc = 0;
553 }
554 if (rc) {
555
556 MESSAGE (KERN_WARNING,
557 "Read configuration data returned error %d",
558 rc);
559
560 goto fail;
561 }
562 if (conf_data == NULL) {
563
564 MESSAGE (KERN_WARNING, "%s",
565 "No configuration data retrieved");
566
567 goto out;
568 }
569 if (conf_len != sizeof (dasd_eckd_confdata_t)) {
570
571 MESSAGE (KERN_WARNING,
572 "sizes of configuration data mismatch"
573 "%d (read) vs %ld (expected)",
574 conf_len,
575 sizeof (dasd_eckd_confdata_t));
576
577 goto out;
578 }
579 memcpy (&private->conf_data, conf_data,
580 sizeof (dasd_eckd_confdata_t));
581
582 DEV_MESSAGE (KERN_INFO, device,
583 "%04X/%02X(CU:%04X/%02X): Configuration data read",
584 private->rdc_data.dev_type,
585 private->rdc_data.dev_model,
586 private->rdc_data.cu_type,
587 private->rdc_data.cu_model.model);
588 goto out;
589
590 fail:
591 if (device->private) {
592 kfree (device->private);
593 device->private = NULL;
594 }
595
596 out:
597 return rc;
598}
599
600static inline int
601dasd_eckd_cdl_reclen (dasd_device_t * device, int recid)
602{
603 dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
604 int byt_per_blk = device->sizes.bp_block;
605 int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
606 if (recid < 3)
607 return sizes_trk0[recid];
608 if (recid < blk_per_trk)
609 return byt_per_blk;
610 if (recid < 2 * blk_per_trk)
611 return LABEL_SIZE;
612 return byt_per_blk;
613}
614
615static ccw_req_t *
616dasd_eckd_init_analysis (struct dasd_device_t *device)
617{
618 ccw_req_t *cqr = NULL;
619 ccw1_t *ccw;
620 DE_eckd_data_t *DE_data;
621 LO_eckd_data_t *LO_data;
622 dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
623 eckd_count_t *count_data = private->count_area;
624
625 cqr = dasd_alloc_request (dasd_eckd_discipline.name, 8 + 1,
626 sizeof (DE_eckd_data_t) +
627 2 * sizeof (LO_eckd_data_t),
628 device);
629 if (cqr == NULL) {
630
631 MESSAGE (KERN_WARNING, "%s",
632 "No memory to allocate initialization request");
633 goto out;
634 }
635 DE_data = cqr->data;
636 LO_data = cqr->data + sizeof (DE_eckd_data_t);
637 ccw = cqr->cpaddr;
638 if (define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device, cqr)) {
639 goto clear_cqr;
640 }
641 ccw->flags |= CCW_FLAG_CC;
642 ccw++;
643 if (locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT,
644 device, 0, cqr)) {
645 goto clear_cqr;
646 }
647 ccw->flags |= CCW_FLAG_CC;
648 ccw++;
649 ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
650 ccw->count = 8;
651 if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
652 goto clear_cqr;
653 }
654 ccw->flags |= CCW_FLAG_CC;
655 ccw++;
656 ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
657 ccw->count = 8;
658 if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
659 goto clear_cqr;
660 }
661 ccw->flags |= CCW_FLAG_CC;
662 ccw++;
663 ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
664 ccw->count = 8;
665 if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
666 goto clear_cqr;
667 }
668 ccw->flags |= CCW_FLAG_CC;
669 ccw++;
670 ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
671 ccw->count = 8;
672 if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
673 goto clear_cqr;
674 }
675 ccw->flags |= CCW_FLAG_CC;
676 ccw++;
677 if (locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT,
678 device, 0, cqr)) {
679 goto clear_cqr;
680 }
681 ccw->flags |= CCW_FLAG_CC;
682 ccw++;
683 ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
684 ccw->count = 8;
685 if (dasd_set_normalized_cda (ccw, __pa (count_data), cqr, device)) {
686 goto clear_cqr;
687 }
688 cqr->device = device;
689 cqr->retries = 0;
690 cqr->buildclk = get_clock ();
691 cqr->status = CQR_STATUS_FILLED;
692 dasd_chanq_enq (&device->queue, cqr);
693 goto out;
694
695 clear_cqr:
696 dasd_free_request (cqr,device);
697
698 MESSAGE (KERN_WARNING, "%s",
699 "No memory to allocate initialization request");
700
701 cqr=NULL;
702 out:
703 return cqr;
704}
705
706static int
707dasd_eckd_do_analysis (struct dasd_device_t *device)
708{
709 int sb, rpt;
710 dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
711 eckd_count_t *count_area = NULL;
712 char *cdl_msg;
713 int status;
714 int i;
715
716 private->uses_cdl = 1;
717 status = device->init_cqr->status;
718 dasd_chanq_deq (&device->queue, device->init_cqr);
719 dasd_free_request (device->init_cqr, device);
720
721 if ( status != CQR_STATUS_DONE ) {
722
723 DEV_MESSAGE (KERN_WARNING, device, "%s",
724 "volume analysis returned unformatted disk");
725
726 return -EMEDIUMTYPE;
727 }
728
729 for (i = 0; i < 3; i++) {
730 if ((i < 3) &&
731 ((private->count_area[i].kl != 4) ||
732 (private->count_area[i].dl !=
733 dasd_eckd_cdl_reclen (device, i) - 4))) {
734 private->uses_cdl = 0;
735 break;
736 }
737 }
738 if (i == 3) {
739 count_area = &private->count_area[4];
740 }
741 if (private->uses_cdl == 0) {
742 for (i = 0; i < 5; i++) {
743 if ((private->count_area[i].kl != 0) ||
744 (private->count_area[i].dl !=
745 private->count_area[0].dl)) {
746 break;
747 }
748 }
749 if (i == 5) {
750 count_area = &private->count_area[0];
751 }
752 } else {
753 if (private->count_area[3].record == 1) {
754
755 DEV_MESSAGE (KERN_WARNING, device, "%s",
756 "Trk 0: no records after VTOC!");
757 }
758 }
759 if (count_area != NULL &&
760 count_area->kl == 0) {
761
762 switch (count_area->dl) {
763 case 512:
764 case 1024:
765 case 2048:
766 case 4096:
767 device->sizes.bp_block = count_area->dl;
768 break;
769 }
770 }
771 if (device->sizes.bp_block == 0) {
772
773 DEV_MESSAGE (KERN_WARNING, device, "%s",
774 "Volume has incompatible disk layout");
775
776 return -EMEDIUMTYPE;
777 }
778 device->sizes.s2b_shift = 0;
779 device->sizes.pt_block = 2;
780 for (sb = 512; sb < device->sizes.bp_block; sb = sb << 1)
781 device->sizes.s2b_shift++;
782
783 rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block);
784 device->sizes.blocks = (private->rdc_data.no_cyl *
785 private->rdc_data.trk_per_cyl *
786 recs_per_track (&private->rdc_data, 0,
787 device->sizes.bp_block));
788 cdl_msg =
789 private->
790 uses_cdl ? "compatible disk layout" : "linux disk layout";
791
792 DEV_MESSAGE (KERN_INFO, device,
793 "(%dkB blks): %dkB at %dkB/trk %s",
794 (device->sizes.bp_block >> 10),
795 ((private->rdc_data.no_cyl *
796 private->rdc_data.trk_per_cyl *
797 recs_per_track (&private->rdc_data, 0,
798 device->sizes.bp_block) *
799 (device->sizes.bp_block >> 9)) >> 1),
800 ((recs_per_track (&private->rdc_data, 0,
801 device->sizes.bp_block) *
802 device->sizes.bp_block) >> 10),
803 cdl_msg);
804
805 return 0;
806}
807
808static int
809dasd_eckd_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo)
810{
811 int rc = 0;
812 dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
813 switch (device->sizes.bp_block) {
814 case 512:
815 case 1024:
816 case 2048:
817 case 4096:
818 geo->sectors = recs_per_track (&(private->rdc_data),
819 0, device->sizes.bp_block);
820 break;
821 default:
822 break;
823 }
824 geo->cylinders = private->rdc_data.no_cyl;
825 geo->heads = private->rdc_data.trk_per_cyl;
826 return rc;
827}
828
829static ccw_req_t *
830dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata)
831{
832 int i;
833 ccw_req_t *fcp = NULL;
834 DE_eckd_data_t *DE_data = NULL;
835 LO_eckd_data_t *LO_data = NULL;
836 eckd_count_t *ct_data = NULL;
837 eckd_count_t *r0_data = NULL;
838 eckd_home_t *ha_data = NULL;
839 ccw1_t *last_ccw = NULL;
840 void *last_data = NULL;
841 dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
842
843 int rpt = recs_per_track (&(private->rdc_data), 0, fdata->blksize);
844 int cyl = fdata->start_unit / private->rdc_data.trk_per_cyl;
845 int head = fdata->start_unit % private->rdc_data.trk_per_cyl;
846 int wrccws = rpt;
847 int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
848
849 if (fdata->start_unit >=
850 (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)){
851
852 DEV_MESSAGE (KERN_INFO, device,
853 "Track no %d too big!",
854 fdata->start_unit);
855
856 return NULL;
857 }
858 if ( fdata->start_unit > fdata->stop_unit) {
859
860 DEV_MESSAGE (KERN_INFO, device,
861 "Track %d reached! ending.",
862 fdata->start_unit);
863
864 return NULL;
865 }
866 switch (fdata->blksize) {
867 case 512:
868 case 1024:
869 case 2048:
870 case 4096:
871 break;
872 default:
873
874 MESSAGE (KERN_WARNING,
875 "Invalid blocksize %d...terminating!",
876 fdata->blksize);
877
878 return NULL;
879 }
880 switch (fdata->intensity) {
881 case 0x00:
882 case 0x01:
883 case 0x03:
884 case 0x04:
885 case 0x08:
886 case 0x09:
887 case 0x0b:
888 case 0x0c:
889 break;
890 default:
891
892 MESSAGE (KERN_WARNING,
893 "Invalid flags 0x%x...terminating!",
894 fdata->intensity);
895
896 return NULL;
897 }
898
899
900 if ((private->rdc_data.no_cyl < 20) ?
901 (fdata->start_unit % private->rdc_data.no_cyl == 0) :
902 (fdata->start_unit % private->rdc_data.no_cyl == 0 &&
903 (fdata->start_unit / private->rdc_data.no_cyl) %
904 (private->rdc_data.no_cyl / 20))) {
905
906 DBF_DEV_EVENT (DBF_NOTICE, device,
907 "Format Cylinder: %d Flags: %d",
908 fdata->start_unit / private->rdc_data.trk_per_cyl,
909 fdata->intensity);
910
911 }
912 if ((fdata->intensity & ~0x8) & 0x04) {
913 wrccws = 1;
914 rpt = 1;
915 } else {
916 if (fdata->intensity & 0x1) {
917 wrccws++;
918 datasize += sizeof (eckd_count_t);
919 }
920 if (fdata->intensity & 0x2) {
921 wrccws++;
922 datasize += sizeof (eckd_home_t);
923 }
924 }
925 fcp = dasd_alloc_request (dasd_eckd_discipline.name,
926 wrccws + 2 + 1,
927 datasize + rpt * sizeof (eckd_count_t),
928 device );
929 if (fcp != NULL) {
930 fcp->device = device;
931 fcp->retries = 2;
932 last_data = fcp->data;
933 DE_data = (DE_eckd_data_t *) last_data;
934 last_data = (void *) (DE_data + 1);
935 LO_data = (LO_eckd_data_t *) last_data;
936 last_data = (void *) (LO_data + 1);
937 if (fdata->intensity & 0x2) {
938 ha_data = (eckd_home_t *) last_data;
939 last_data = (void *) (ha_data + 1);
940 }
941 if (fdata->intensity & 0x1) {
942 r0_data = (eckd_count_t *) last_data;
943 last_data = (void *) (r0_data + 1);
944 }
945 ct_data = (eckd_count_t *) last_data;
946
947 last_ccw = fcp->cpaddr;
948
949 switch (fdata->intensity & ~0x08) {
950 case 0x03:
951 if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
952 DASD_ECKD_CCW_WRITE_HOME_ADDRESS,
953 device, fcp)) {
954 goto clear_fcp;
955 }
956 last_ccw->flags |= CCW_FLAG_CC;
957 last_ccw++;
958 if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
959 DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,
960 device->sizes.bp_block, fcp)) {
961 goto clear_fcp;
962 }
963 last_ccw->flags |= CCW_FLAG_CC;
964 last_ccw++;
965 break;
966 case 0x01:
967 if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
968 DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, fcp)) {
969 goto clear_fcp;
970 }
971 last_ccw->flags |= CCW_FLAG_CC;
972 last_ccw++;
973 if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
974 DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
975 device->sizes.bp_block, fcp)) {
976 goto clear_fcp;
977 }
978 last_ccw->flags |= CCW_FLAG_CC;
979 last_ccw++;
980 memset (r0_data, 0, sizeof (eckd_count_t));
981 break;
982 case 0x04:
983 fdata->blksize = 8;
984 case 0x00:
985 if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
986 DASD_ECKD_CCW_WRITE_CKD, device, fcp)) {
987 dasd_free_request (fcp, device);
988 return NULL;
989 }
990 last_ccw->flags |= CCW_FLAG_CC;
991 last_ccw++;
992 if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
993 DASD_ECKD_CCW_WRITE_CKD, device, fdata->blksize, fcp)) {
994 goto clear_fcp;
995 }
996 last_ccw->flags |= CCW_FLAG_CC;
997 last_ccw++;
998 break;
999 default:
1000
1001 MESSAGE (KERN_WARNING,
1002 "Unknown format flags...%d",
1003 fdata->intensity);
1004
1005 return NULL;
1006 }
1007 if (fdata->intensity & 0x02) {
1008
1009 MESSAGE (KERN_WARNING,
1010 "Unsupported format flag...%d",
1011 fdata->intensity);
1012
1013 return NULL;
1014 }
1015 if (fdata->intensity & 0x01) {
1016 r0_data->cyl = cyl;
1017 r0_data->head = head;
1018 r0_data->record = 0;
1019 r0_data->kl = 0;
1020 r0_data->dl = 8;
1021 last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
1022 last_ccw->count = 8;
1023 last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
1024 if (dasd_set_normalized_cda (last_ccw, __pa (r0_data), fcp, device)) {
1025 goto clear_fcp;
1026 }
1027 last_ccw++;
1028 }
1029 if ((fdata->intensity & ~0x08) & 0x04) {
1030 memset (ct_data, 0, sizeof (eckd_count_t));
1031 ct_data->cyl = cyl;
1032 ct_data->head = head;
1033 ct_data->record = 1;
1034 ct_data->kl = 0;
1035 ct_data->dl = 0;
1036 last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
1037 last_ccw->count = 8;
1038 last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
1039 if (dasd_set_normalized_cda (last_ccw, __pa (ct_data), fcp, device)) {
1040 goto clear_fcp;
1041 }
1042 last_ccw++;
1043 } else {
1044 for (i = 0; i < rpt; i++) {
1045 memset (ct_data + i, 0, sizeof (eckd_count_t));
1046 (ct_data + i)->cyl = cyl;
1047 (ct_data + i)->head = head;
1048 (ct_data + i)->record = i + 1;
1049 (ct_data + i)->kl = 0;
1050 if (fdata->intensity & 0x08) {
1051
1052 switch (fdata->start_unit) {
1053 case 0:
1054 if (i < 3) {
1055 (ct_data + i)->kl = 4;
1056
1057 (ct_data + i)->dl =
1058 sizes_trk0[i] - 4;
1059 } else
1060 (ct_data + i)->dl = fdata->blksize;
1061 break;
1062 case 1:
1063 (ct_data + i)->kl = 44;
1064 (ct_data + i)->dl = LABEL_SIZE - 44;
1065 break;
1066 default:
1067 (ct_data + i)->dl = fdata->blksize;
1068 break;
1069 }
1070 } else
1071 (ct_data + i)->dl = fdata->blksize;
1072 last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
1073 last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
1074 last_ccw->count = 8;
1075 if (dasd_set_normalized_cda (last_ccw,
1076 __pa (ct_data + i), fcp, device)) {
1077 goto clear_fcp;
1078 }
1079 last_ccw++;
1080 }
1081 }
1082 (last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
1083 fcp->device = device;
1084 fcp->buildclk = get_clock ();
1085 fcp->status = CQR_STATUS_FILLED;
1086 }
1087 goto out;
1088 clear_fcp:
1089 dasd_free_request (fcp, device);
1090 fcp=NULL;
1091 out:
1092 return fcp;
1093}
1094
1095static dasd_era_t
1096dasd_eckd_examine_error (ccw_req_t * cqr, devstat_t * stat)
1097{
1098 dasd_device_t *device = (dasd_device_t *) cqr->device;
1099
1100 if (stat->cstat == 0x00 &&
1101 stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
1102 return dasd_era_none;
1103
1104 switch (device->devinfo.sid_data.cu_type) {
1105 case 0x3990:
1106 case 0x2105:
1107 return dasd_3990_erp_examine (cqr, stat);
1108 case 0x9343:
1109 return dasd_9343_erp_examine (cqr, stat);
1110 default:
1111
1112 MESSAGE (KERN_WARNING, "%s",
1113 "default (unknown CU type) - RECOVERABLE return");
1114
1115 return dasd_era_recover;
1116 }
1117}
1118
1119static dasd_erp_action_fn_t
1120dasd_eckd_erp_action (ccw_req_t * cqr)
1121{
1122 dasd_device_t *device = (dasd_device_t *) cqr->device;
1123
1124 switch (device->devinfo.sid_data.cu_type) {
1125 case 0x3990:
1126 case 0x2105:
1127 return dasd_3990_erp_action;
1128 case 0x9343:
1129
1130 default:
1131 return dasd_default_erp_action;
1132 }
1133}
1134
1135static dasd_erp_postaction_fn_t
1136dasd_eckd_erp_postaction (ccw_req_t * cqr)
1137{
1138 return dasd_default_erp_postaction;
1139}
1140
1141
1142inline unsigned char
1143dasd_eckd_cdl_cmd (dasd_device_t * device, int recid, int cmd)
1144{
1145 dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
1146 int byt_per_blk = device->sizes.bp_block;
1147 int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
1148 switch (cmd) {
1149 case READ:
1150 if (recid < 3)
1151 return DASD_ECKD_CCW_READ_KD_MT;
1152 if (recid < blk_per_trk)
1153 return DASD_ECKD_CCW_READ_MT;
1154 if (recid < 2 * blk_per_trk)
1155 return DASD_ECKD_CCW_READ_KD_MT;
1156 return DASD_ECKD_CCW_READ_MT;
1157 break;
1158 case WRITE:
1159 if (recid < 3)
1160 return DASD_ECKD_CCW_WRITE_KD_MT;
1161 if (recid < blk_per_trk)
1162 return DASD_ECKD_CCW_WRITE_MT;
1163 if (recid < 2 * blk_per_trk)
1164 return DASD_ECKD_CCW_WRITE_KD_MT;
1165 return DASD_ECKD_CCW_WRITE_MT;
1166 break;
1167 default:
1168 BUG ();
1169 }
1170 return 0;
1171}
1172
1173
1174static ccw_req_t *
1175dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
1176{
1177 ccw_req_t *rw_cp = NULL;
1178 int rw_cmd;
1179 int bhct;
1180 long size;
1181 ccw1_t *ccw;
1182 DE_eckd_data_t *DE_data;
1183 LO_eckd_data_t *LO_data;
1184 struct buffer_head *bh;
1185 dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
1186 int byt_per_blk = device->sizes.bp_block;
1187 int shift = device->sizes.s2b_shift;
1188 int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
1189 unsigned long reloc_sector = req->sector +
1190 device->major_info->gendisk.part[MINOR(req->rq_dev)].start_sect;
1191 int btrk = (reloc_sector >> shift) / blk_per_trk;
1192 int etrk = ((reloc_sector + req->nr_sectors - 1) >> shift) / blk_per_trk;
1193 int recid = reloc_sector >> shift;
1194 int locate4k_set = 0;
1195 int nlocs = 0;
1196 int errcode;
1197
1198 if (req->cmd == READ) {
1199 rw_cmd = DASD_ECKD_CCW_READ_MT;
1200 } else if (req->cmd == WRITE) {
1201 rw_cmd = DASD_ECKD_CCW_WRITE_MT;
1202 } else {
1203
1204 MESSAGE (KERN_ERR,
1205 "Unknown command %d",
1206 req->cmd);
1207
1208 return ERR_PTR(-EINVAL);
1209 }
1210
1211
1212 bhct = 0;
1213 for (bh = req->bh; bh; bh = bh->b_reqnext) {
1214 if (bh->b_size < byt_per_blk) {
1215 MESSAGE(KERN_ERR, "ignoring bogus sized request: %d<%d",
1216 bh->b_size, byt_per_blk);
1217 return ERR_PTR(-EINVAL);
1218 }
1219 bhct+= bh->b_size >> (device->sizes.s2b_shift+9);
1220 }
1221 if (btrk < 2 && private->uses_cdl) {
1222 if (etrk < 2)
1223 nlocs = bhct;
1224 else
1225 nlocs = 2 * blk_per_trk - recid;
1226 }
1227 rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
1228 2 + nlocs + bhct + 1,
1229 sizeof (DE_eckd_data_t) + (1 +
1230 nlocs) *
1231 sizeof (LO_eckd_data_t),
1232 device);
1233 if (!rw_cp) {
1234 return ERR_PTR(-ENOMEM);
1235 }
1236 DE_data = rw_cp->data;
1237 LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
1238 ccw = rw_cp->cpaddr;
1239 if ((errcode = define_extent (ccw, DE_data, btrk, etrk,
1240 rw_cmd, device, rw_cp))) {
1241 goto clear_rw_cp;
1242 }
1243 ccw->flags |= CCW_FLAG_CC;
1244 for (bh = req->bh; bh != NULL;) {
1245 for (size = 0; size < bh->b_size; size += byt_per_blk) {
1246 if (!locate4k_set) {
1247
1248 ccw++;
1249 if ((recid / blk_per_trk) < 2
1250 && private->uses_cdl) {
1251
1252 int cmd = dasd_eckd_cdl_cmd (device,recid, req->cmd);
1253 if ((errcode = locate_record (ccw,
1254 LO_data++,
1255 recid / blk_per_trk,
1256 recid % blk_per_trk + 1,
1257 1, cmd, device,
1258 dasd_eckd_cdl_reclen(device, recid), rw_cp))) {
1259 goto clear_rw_cp;
1260 }
1261 } else {
1262
1263 if ((errcode = locate_record (ccw,
1264 LO_data++,
1265 recid /blk_per_trk,
1266 recid %blk_per_trk + 1,
1267 (((reloc_sector +
1268 req->nr_sectors) >>
1269 shift) - recid),
1270 rw_cmd, device,
1271 device->sizes.bp_block, rw_cp))) {
1272 goto clear_rw_cp;
1273 }
1274 locate4k_set = 1;
1275 }
1276 ccw->flags |= CCW_FLAG_CC;
1277 }
1278 ccw++;
1279 ccw->flags |= CCW_FLAG_CC;
1280 ccw->cmd_code = locate4k_set ? rw_cmd :
1281 dasd_eckd_cdl_cmd (device, recid, req->cmd);
1282 ccw->count = byt_per_blk;
1283 if (!locate4k_set) {
1284 ccw->count = dasd_eckd_cdl_reclen (device,recid);
1285 if (ccw->count < byt_per_blk) {
1286 memset (bh->b_data + size + ccw->count,
1287 0xE5, byt_per_blk - ccw->count);
1288 }
1289 }
1290 if ((errcode = dasd_set_normalized_cda (ccw, __pa (bh->b_data+size),
1291 rw_cp, device))) {
1292 goto clear_rw_cp;
1293 }
1294 recid++;
1295 }
1296 bh = bh->b_reqnext;
1297 }
1298 ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
1299 rw_cp->device = device;
1300 rw_cp->expires = 5 * TOD_MIN;
1301 rw_cp->req = req;
1302 rw_cp->lpm = LPM_ANYPATH;
1303 rw_cp->retries = 256;
1304
1305 rw_cp->buildclk = get_clock ();
1306
1307 check_then_set (&rw_cp->status,
1308 CQR_STATUS_EMPTY,
1309 CQR_STATUS_FILLED);
1310
1311 goto out;
1312 clear_rw_cp:
1313 dasd_free_request (rw_cp,
1314 device);
1315 rw_cp=ERR_PTR(errcode);
1316 out:
1317 return rw_cp;
1318}
1319
1320#if 0
1321int
1322dasd_eckd_cleanup_request (ccw_req_t * cqr)
1323{
1324 int ret = 0;
1325 struct request *req = cqr->req;
1326 dasd_device_t *device = cqr->device;
1327 int byt_per_blk = device->sizes.bp_block;
1328
1329 for (bh = req->bh; bh != NULL;) {
1330 if (bh->b_size > byt_per_blk) {
1331 for (size = 0; size < bh->b_size; size += byt_per_blk) {
1332 ccw++;
1333 ccw->flags |= CCW_FLAG_CC;
1334 ccw->cmd_code = rw_cmd;
1335 ccw->count = byt_per_blk;
1336 set_normalized_cda (ccw,
1337 __pa (bh->b_data + size));
1338 }
1339 bh = bh->b_reqnext;
1340 } else {
1341 for (size = 0; bh != NULL && size < byt_per_blk;) {
1342 ccw++;
1343 ccw->flags |= CCW_FLAG_DC;
1344 ccw->cmd_code = rw_cmd;
1345 ccw->count = bh->b_size;
1346 set_normalized_cda (ccw, __pa (bh->b_data));
1347 size += bh->b_size;
1348 bh = bh->b_reqnext;
1349 }
1350 }
1351 }
1352 return ret;
1353}
1354#endif
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365ccw_req_t *
1366dasd_eckd_reserve (struct dasd_device_t * device)
1367{
1368 ccw_req_t *cqr;
1369
1370 cqr = dasd_alloc_request (dasd_eckd_discipline.name,
1371 1 + 1, 32, device);
1372 if (cqr == NULL) {
1373
1374 MESSAGE (KERN_WARNING, "%s",
1375 "No memory to allocate initialization request");
1376
1377 return NULL;
1378 }
1379 cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
1380 cqr->cpaddr->flags |= CCW_FLAG_SLI;
1381 cqr->cpaddr->count = 32;
1382
1383 if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data),
1384 cqr, device)) {
1385 dasd_free_request (cqr, device);
1386 return NULL;
1387 }
1388
1389 cqr->device = device;
1390 cqr->retries = 0;
1391 cqr->expires = 10 * TOD_SEC;
1392 cqr->buildclk = get_clock ();
1393 cqr->status = CQR_STATUS_FILLED;
1394 return cqr;
1395}
1396
1397
1398
1399
1400
1401
1402
1403
1404ccw_req_t *
1405dasd_eckd_release (struct dasd_device_t * device)
1406{
1407 ccw_req_t *cqr;
1408
1409 cqr = dasd_alloc_request (dasd_eckd_discipline.name,
1410 1 + 1, 32, device);
1411 if (cqr == NULL) {
1412
1413 MESSAGE (KERN_WARNING, "%s",
1414 "No memory to allocate initialization request");
1415
1416 return NULL;
1417 }
1418 cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
1419 cqr->cpaddr->flags |= CCW_FLAG_SLI;
1420 cqr->cpaddr->count = 32;
1421
1422 if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data),
1423 cqr, device)) {
1424 dasd_free_request (cqr, device);
1425 return NULL;
1426 }
1427
1428 cqr->device = device;
1429 cqr->retries = 0;
1430 cqr->expires = 10 * TOD_SEC;
1431 cqr->buildclk = get_clock ();
1432 cqr->status = CQR_STATUS_FILLED;
1433 return cqr;
1434
1435}
1436
1437
1438
1439
1440
1441
1442
1443
1444ccw_req_t *
1445dasd_eckd_steal_lock (struct dasd_device_t * device)
1446{
1447 ccw_req_t *cqr;
1448
1449 cqr = dasd_alloc_request (dasd_eckd_discipline.name,
1450 1 + 1, 32, device);
1451 if (cqr == NULL) {
1452
1453 MESSAGE (KERN_WARNING, "%s",
1454 "No memory to allocate initialization request");
1455
1456 return NULL;
1457 }
1458 cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK;
1459 cqr->cpaddr->flags |= CCW_FLAG_SLI;
1460 cqr->cpaddr->count = 32;
1461
1462 if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data),
1463 cqr, device)) {
1464 dasd_free_request (cqr, device);
1465 return NULL;
1466 }
1467
1468 cqr->device = device;
1469 cqr->retries = 0;
1470 cqr->expires = 10 * TOD_SEC;
1471 cqr->buildclk = get_clock ();
1472 cqr->status = CQR_STATUS_FILLED;
1473 return cqr;
1474}
1475
1476static inline ccw1_t *
1477dasd_eckd_find_cmd (ccw_req_t * cqr, int cmd)
1478{
1479 ccw1_t *cp;
1480
1481 cp = cqr->cpaddr;
1482 do {
1483 if (cp->cmd_code == cmd)
1484 return cp;
1485 if (cp->cmd_code == CCW_CMD_TIC) {
1486 cp = (ccw1_t *) (long) cp->cda;
1487 continue;
1488 }
1489 if (cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) {
1490 cp++;
1491 continue;
1492 }
1493 break;
1494 } while (1);
1495 return NULL;
1496}
1497
1498static ccw_req_t *
1499dasd_eckd_merge_cp (dasd_device_t * device)
1500{
1501 return NULL;
1502}
1503
1504static int
1505dasd_eckd_fill_info (dasd_device_t * device, dasd_information2_t * info)
1506{
1507 int rc = 0;
1508 info->label_block = 2;
1509 if (((dasd_eckd_private_t *) device->private)->uses_cdl) {
1510 info->FBA_layout = 0;
1511 info->format = DASD_FORMAT_CDL;
1512 } else {
1513 info->FBA_layout = 1;
1514 info->format = DASD_FORMAT_LDL;
1515 }
1516 info->characteristics_size = sizeof (dasd_eckd_characteristics_t);
1517 memcpy (info->characteristics,
1518 &((dasd_eckd_private_t *) device->private)->rdc_data,
1519 sizeof (dasd_eckd_characteristics_t));
1520 info->confdata_size = sizeof (dasd_eckd_confdata_t);
1521 memcpy (info->configuration_data,
1522 &((dasd_eckd_private_t *) device->private)->conf_data,
1523 sizeof (dasd_eckd_confdata_t));
1524 return rc;
1525}
1526
1527
1528
1529
1530
1531
1532
1533
1534ccw_req_t *
1535dasd_eckd_read_stats (struct dasd_device_t * device)
1536{
1537
1538 int rc;
1539 ccw1_t *ccw;
1540 ccw_req_t *cqr;
1541 dasd_psf_prssd_data_t *prssdp;
1542 dasd_rssd_perf_stats_t *statsp;
1543
1544 cqr = dasd_alloc_request (dasd_eckd_discipline.name,
1545 1 + 1 ,
1546 (sizeof (dasd_psf_prssd_data_t) +
1547 sizeof (dasd_rssd_perf_stats_t) ),
1548 device);
1549
1550 if (cqr == NULL) {
1551
1552 MESSAGE (KERN_WARNING, "%s",
1553 "No memory to allocate initialization request");
1554
1555 return NULL;
1556 }
1557
1558 cqr->device = device;
1559 cqr->retries = 0;
1560 cqr->expires = 10 * TOD_SEC;
1561
1562
1563 prssdp = (dasd_psf_prssd_data_t *) cqr->data;
1564
1565 memset (prssdp, 0, sizeof (dasd_psf_prssd_data_t));
1566
1567 prssdp->order = PSF_ORDER_PRSSD;
1568 prssdp->suborder = 0x01;
1569 prssdp->varies[1] = 0x01;
1570
1571 ccw = cqr->cpaddr;
1572
1573 ccw->cmd_code = DASD_ECKD_CCW_PSF;
1574 ccw->count = sizeof (dasd_psf_prssd_data_t);
1575 ccw->flags |= CCW_FLAG_CC;
1576
1577 if ((rc = dasd_set_normalized_cda (ccw,__pa (prssdp), cqr, device))) {
1578
1579 dasd_free_request (cqr,
1580 device);
1581 return NULL;
1582 }
1583
1584 ccw++;
1585
1586
1587 statsp = (dasd_rssd_perf_stats_t *) (prssdp + 1);
1588 memset (statsp, 0, sizeof (dasd_rssd_perf_stats_t));
1589
1590 ccw->cmd_code = DASD_ECKD_CCW_RSSD;
1591 ccw->count = sizeof (dasd_rssd_perf_stats_t);
1592
1593 if ((rc = dasd_set_normalized_cda (ccw,__pa (statsp), cqr, device))) {
1594
1595 dasd_free_request (cqr,
1596 device);
1597 return NULL;
1598 }
1599 cqr->buildclk = get_clock ();
1600 cqr->status = CQR_STATUS_FILLED;
1601
1602 return cqr;
1603}
1604
1605
1606
1607
1608
1609
1610
1611dasd_rssd_perf_stats_t *
1612dasd_eckd_ret_stats (ccw_req_t *cqr)
1613{
1614
1615 dasd_psf_prssd_data_t *prssdp;
1616 dasd_rssd_perf_stats_t *statsp;
1617
1618 if (cqr == NULL) {
1619
1620 return NULL;
1621 }
1622
1623
1624 prssdp = (dasd_psf_prssd_data_t *) cqr->data;
1625 statsp = (dasd_rssd_perf_stats_t *) (prssdp + 1);
1626
1627 return statsp;
1628
1629}
1630
1631
1632
1633
1634
1635
1636
1637
1638int
1639dasd_eckd_get_attrib (dasd_device_t *device,
1640 attrib_data_t *attrib)
1641{
1642 dasd_eckd_private_t *private;
1643
1644 private = (dasd_eckd_private_t *) device->private;
1645 *attrib = private->attrib;
1646
1647 return 0;
1648
1649}
1650
1651
1652
1653
1654
1655
1656
1657int
1658dasd_eckd_set_attrib (dasd_device_t *device,
1659 attrib_data_t *attrib)
1660{
1661 dasd_eckd_private_t *private;
1662
1663 private = (dasd_eckd_private_t *) device->private;
1664 private->attrib = *attrib;
1665
1666 DBF_DEV_EVENT (DBF_ERR, device,
1667 "cache operation mode set to "
1668 "%x (%i cylinder prestage)",
1669 private->attrib.operation,
1670 private->attrib.nr_cyl);
1671
1672 return 0;
1673
1674}
1675
1676static void
1677dasd_eckd_dump_sense (struct dasd_device_t *device,
1678 ccw_req_t *req)
1679{
1680
1681 char *page = (char *) get_free_page (GFP_ATOMIC);
1682 devstat_t *stat = &device->dev_status;
1683 char *sense = stat->ii.sense.data;
1684 int len, sl, sct;
1685
1686 if (page == NULL) {
1687
1688 MESSAGE (KERN_ERR, "%s",
1689 "No memory to dump sense data");
1690
1691 return;
1692 }
1693
1694 len = sprintf (page, KERN_ERR PRINTK_HEADER
1695 "device %04X on irq %d: I/O status report:\n",
1696 device->devinfo.devno, device->devinfo.irq);
1697 len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1698 "in req: %p CS: 0x%02X DS: 0x%02X\n",
1699 req, stat->cstat, stat->dstat);
1700 len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1701 "Failing CCW: %p\n", (void *) (long) stat->cpa);
1702 {
1703
1704 ccw1_t *act = req->cpaddr;
1705 int i = req->cplength;
1706
1707 do {
1708
1709 DBF_EVENT (DBF_INFO,
1710 "CCW %p: %08X %08X",
1711 act,
1712 ((int *) act)[0],
1713 ((int *) act)[1]);
1714
1715 DBF_EVENT (DBF_INFO,
1716 "DAT: %08X %08X %08X %08X",
1717 ((int *) (addr_t) act->cda)[0],
1718 ((int *) (addr_t) act->cda)[1],
1719 ((int *) (addr_t) act->cda)[2],
1720 ((int *) (addr_t) act->cda)[3]);
1721
1722 act++;
1723
1724 } while (--i);
1725 }
1726 if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
1727 for (sl = 0; sl < 4; sl++) {
1728 len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1729 "Sense(hex) %2d-%2d:",
1730 (8 * sl), ((8 * sl) + 7));
1731
1732 for (sct = 0; sct < 8; sct++) {
1733 len += sprintf (page + len, " %02x",
1734 sense[8 * sl + sct]);
1735 }
1736 len += sprintf (page + len, "\n");
1737 }
1738
1739 if (sense[27] & DASD_SENSE_BIT_0) {
1740
1741 len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1742 "24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
1743 sense[7] >> 4, sense[7] & 0x0f,
1744 sense[1] & 0x10 ? "" : "no");
1745 } else {
1746
1747 len += sprintf (page + len, KERN_ERR PRINTK_HEADER
1748 "32 Byte: Format: %x "
1749 "Exception class %x\n",
1750 sense[6] & 0x0f, sense[22] >> 4);
1751 }
1752 }
1753
1754 MESSAGE_LOG (KERN_ERR,
1755 "Sense data:\n%s",
1756 page);
1757
1758 free_page ((unsigned long) page);
1759}
1760
1761
1762dasd_discipline_t dasd_eckd_discipline = {
1763 owner: THIS_MODULE,
1764 name:"ECKD",
1765 ebcname:"ECKD",
1766 max_blocks:240,
1767 id_check:dasd_eckd_id_check,
1768 check_characteristics:dasd_eckd_check_characteristics,
1769 init_analysis:dasd_eckd_init_analysis,
1770 do_analysis:dasd_eckd_do_analysis,
1771 fill_geometry:dasd_eckd_fill_geometry,
1772 start_IO:dasd_start_IO,
1773 term_IO:dasd_term_IO,
1774 format_device:dasd_eckd_format_device,
1775 examine_error:dasd_eckd_examine_error,
1776 erp_action:dasd_eckd_erp_action,
1777 erp_postaction:dasd_eckd_erp_postaction,
1778 build_cp_from_req:dasd_eckd_build_cp_from_req,
1779 dump_sense:dasd_eckd_dump_sense,
1780 int_handler:dasd_int_handler,
1781 reserve:dasd_eckd_reserve,
1782 release:dasd_eckd_release,
1783 steal_lock:dasd_eckd_steal_lock,
1784 merge_cp:dasd_eckd_merge_cp,
1785 fill_info:dasd_eckd_fill_info,
1786 read_stats:dasd_eckd_read_stats,
1787 ret_stats:dasd_eckd_ret_stats,
1788 get_attrib:dasd_eckd_get_attrib,
1789 set_attrib:dasd_eckd_set_attrib,
1790 list:LIST_HEAD_INIT(dasd_eckd_discipline.list),
1791};
1792
1793int
1794dasd_eckd_init (void)
1795{
1796 int rc = 0;
1797
1798 MESSAGE (KERN_INFO,
1799 "%s discipline initializing",
1800 dasd_eckd_discipline.name);
1801
1802 ASCEBC (dasd_eckd_discipline.ebcname, 4);
1803 dasd_discipline_add (&dasd_eckd_discipline);
1804#ifdef CONFIG_DASD_DYNAMIC
1805 {
1806 int i;
1807 for (i = 0;
1808 i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
1809 i++) {
1810
1811 MESSAGE (KERN_INFO,
1812 "We are interested in: CU %04X/%02x",
1813 dasd_eckd_known_devices[i].ci.hc.ctype,
1814 dasd_eckd_known_devices[i].ci.hc.cmode);
1815
1816 s390_device_register (&dasd_eckd_known_devices[i]);
1817 }
1818 }
1819#endif
1820 return rc;
1821}
1822
1823void
1824dasd_eckd_cleanup (void)
1825{
1826
1827 MESSAGE (KERN_INFO,
1828 "%s discipline cleaning up",
1829 dasd_eckd_discipline.name);
1830
1831#ifdef CONFIG_DASD_DYNAMIC
1832 {
1833 int i;
1834 for (i = 0;
1835 i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
1836 i++) {
1837
1838 MESSAGE (KERN_INFO,
1839 "We were interested in: CU %04X/%02x",
1840 dasd_eckd_known_devices[i].ci.hc.ctype,
1841 dasd_eckd_known_devices[i].ci.hc.cmode);
1842
1843 s390_device_unregister (&dasd_eckd_known_devices[i]);
1844 }
1845 }
1846#endif
1847 dasd_discipline_del (&dasd_eckd_discipline);
1848}
1849
1850#ifdef MODULE
1851int
1852init_module (void)
1853{
1854 int rc = 0;
1855 rc = dasd_eckd_init ();
1856 return rc;
1857}
1858
1859void
1860cleanup_module (void)
1861{
1862 dasd_eckd_cleanup ();
1863 return;
1864}
1865#endif
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885