1 /*
2 * File...........: linux/drivers/s390/block/dasd_eckd.c
3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4 * Horst Hummel <Horst.Hummel@de.ibm.com>
5 * Carsten Otte <Cotte@de.ibm.com>
6 * Bugreports.to..: <Linux390@de.ibm.com>
7 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
8 *
9 * $Revision $
10 *
11 * History of changes (starts July 2000)
12 * 07/11/00 Enabled rotational position sensing
13 * 07/14/00 Reorganized the format process for better ERP
14 * 07/20/00 added experimental support for 2105 control unit (ESS)
15 * 07/24/00 increased expiration time and added the missing zero
16 * 08/07/00 added some bits to define_extent for ESS support
17 * 09/20/00 added reserve and release ioctls
18 * 10/04/00 changed RW-CCWS to R/W Key and Data
19 * 10/10/00 reverted last change according to ESS exploitation
20 * 10/10/00 now dequeuing init_cqr before freeing *ouch*
21 * 26/10/00 fixed ITPM20144ASC (problems when accesing a device formatted by VIF)
22 * 01/23/01 fixed kmalloc statement in dump_sense to be GFP_ATOMIC
23 * fixed partition handling and HDIO_GETGEO
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> /* HDIO_GETGEO */
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 /* PRINTK_HEADER */
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))
62 MODULE_LICENSE("GPL");
63 #endif
64 #endif
65
66 dasd_discipline_t dasd_eckd_discipline;
67
68 typedef 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; /* e.g. cache operations */
74 } dasd_eckd_private_t;
75
76 #ifdef CONFIG_DASD_DYNAMIC
77 static
78 devreg_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
103 int sizes_trk0[] = { 28, 148, 84 };
104 #define LABEL_SIZE 140
105
106 static inline unsigned int
round_up_multiple(unsigned int no,unsigned int mult)107 round_up_multiple (unsigned int no, unsigned int mult)
108 {
109 int rem = no % mult;
110 return (rem ? no - rem + mult : no);
111 }
112
113 static inline unsigned int
ceil_quot(unsigned int d1,unsigned int d2)114 ceil_quot (unsigned int d1, unsigned int d2)
115 {
116 return (d1 + (d2 - 1)) / d2;
117 }
118
119 static inline int
bytes_per_record(dasd_eckd_characteristics_t * rdc,int kl,int dl)120 bytes_per_record (dasd_eckd_characteristics_t * rdc, int kl, /* key length */
121 int dl /* data length */ )
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
162 static inline unsigned int
bytes_per_track(dasd_eckd_characteristics_t * rdc)163 bytes_per_track (dasd_eckd_characteristics_t * rdc)
164 {
165 return *(unsigned int *) (rdc->byte_per_track) >> 8;
166 }
167
168 static inline unsigned int
recs_per_track(dasd_eckd_characteristics_t * rdc,unsigned int kl,unsigned int dl)169 recs_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
204 static inline void
check_XRC(ccw1_t * de_ccw,DE_eckd_data_t * data,dasd_device_t * device)205 check_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 /* switch on System Time Stamp - needed for XRC Support */
213 if (private->rdc_data.facilities.XRC_supported) {
214
215 data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
216 data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
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 } /* end check_XRC */
227
228 static inline int
define_extent(ccw1_t * de_ccw,DE_eckd_data_t * data,int trk,int totrk,int cmd,dasd_device_t * device,ccw_req_t * cqr)229 define_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: /* Fallthrough */
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; /* ECKD */
307
308 if (private->rdc_data.cu_type == 0x2105
309 && !(private->uses_cdl && trk < 2) ) {
310
311 data->ga_extended |= 0x40;
312 }
313
314 /* check for sequential prestage - enhance cylinder range */
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
348 static inline int
locate_record(ccw1_t * lo_ccw,LO_eckd_data_t * data,int trk,int rec_on_trk,int no_rec,int cmd,dasd_device_t * device,int reclen,ccw_req_t * cqr)349 locate_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
471 static int
dasd_eckd_id_check(s390_dev_info_t * info)472 dasd_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
486 static int
dasd_eckd_check_characteristics(struct dasd_device_t * device)487 dasd_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 /* Read Device Characteristics */
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 /* set default cache operations */
542 private->attrib.operation = DASD_NORMAL_CACHE;
543 private->attrib.nr_cyl = 0;
544
545 /* Read Configuration Data */
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; /* this one is ok */
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; /* no errror */
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; /* no errror */
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
600 static inline int
dasd_eckd_cdl_reclen(dasd_device_t * device,int recid)601 dasd_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
615 static ccw_req_t *
dasd_eckd_init_analysis(struct dasd_device_t * device)616 dasd_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
706 static int
dasd_eckd_do_analysis(struct dasd_device_t * device)707 dasd_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 /* Free the cqr and cleanup device->sizes */
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 /* Check Track 0 for Compatible Disk Layout */
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 && /* we found notthing violating our disk layout */
760 count_area->kl == 0) {
761 /* find out blocksize */
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; /* bits to shift 512 to get a block */
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
808 static int
dasd_eckd_fill_geometry(struct dasd_device_t * device,struct hd_geometry * geo)809 dasd_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
829 static ccw_req_t *
dasd_eckd_format_device(dasd_device_t * device,format_data_t * fdata)830 dasd_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: /* make track invalid */
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 /* print status line */
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; /* set retry counter to enable ERP */
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) { /* write record zero */
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) { /* erase track */
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 { /* write remaining records */
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 // special handling when formatting CDL
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
1095 static dasd_era_t
dasd_eckd_examine_error(ccw_req_t * cqr,devstat_t * stat)1096 dasd_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
1119 static dasd_erp_action_fn_t
dasd_eckd_erp_action(ccw_req_t * cqr)1120 dasd_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 /* Return dasd_9343_erp_action; */
1130 default:
1131 return dasd_default_erp_action;
1132 }
1133 }
1134
1135 static dasd_erp_postaction_fn_t
dasd_eckd_erp_postaction(ccw_req_t * cqr)1136 dasd_eckd_erp_postaction (ccw_req_t * cqr)
1137 {
1138 return dasd_default_erp_postaction;
1139 }
1140
1141
1142 inline unsigned char
dasd_eckd_cdl_cmd(dasd_device_t * device,int recid,int cmd)1143 dasd_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; // never executed
1171 }
1172
1173
1174 static ccw_req_t *
dasd_eckd_build_cp_from_req(dasd_device_t * device,struct request * req)1175 dasd_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 /* Build the request */
1211 /* count bhs to prevent errors, when bh smaller than block */
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 // we need to chain a locate record before our rw-ccw
1248 ccw++;
1249 if ((recid / blk_per_trk) < 2
1250 && private->uses_cdl) {
1251 /* Do a locate record for our special blocks */
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 // Do a locate record for standard blocks */
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; /* 5 minutes */
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
1321 int
1322 dasd_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 { /* group N bhs to fit into byt_per_blk */
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 * DASD_ECKD_RESERVE
1358 *
1359 * DESCRIPTION
1360 * Buils a channel programm to reserve a device.
1361 * Options are set to 'synchronous wait for interrupt' and
1362 * 'timeout the request'. This leads to an terminate IO if
1363 * the interrupt is outstanding for a certain time.
1364 */
1365 ccw_req_t *
dasd_eckd_reserve(struct dasd_device_t * device)1366 dasd_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 * DASD_ECKD_RELEASE
1399 *
1400 * DESCRIPTION
1401 * Buils a channel programm to releases a prior reserved
1402 * (see dasd_eckd_reserve) device.
1403 */
1404 ccw_req_t *
dasd_eckd_release(struct dasd_device_t * device)1405 dasd_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 * DASD_ECKD_STEAL_LOCK
1439 *
1440 * DESCRIPTION
1441 * Buils a channel programm to break a device's reservation.
1442 * (unconditional reserve)
1443 */
1444 ccw_req_t *
dasd_eckd_steal_lock(struct dasd_device_t * device)1445 dasd_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
1476 static inline ccw1_t *
dasd_eckd_find_cmd(ccw_req_t * cqr,int cmd)1477 dasd_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
1498 static ccw_req_t *
dasd_eckd_merge_cp(dasd_device_t * device)1499 dasd_eckd_merge_cp (dasd_device_t * device)
1500 {
1501 return NULL;
1502 }
1503
1504 static int
dasd_eckd_fill_info(dasd_device_t * device,dasd_information2_t * info)1505 dasd_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 * DASD_ECKD_READ_STATS
1529 *
1530 * DESCRIPTION
1531 * build the channel program to read the performance statistics
1532 * of the attached subsystem
1533 */
1534 ccw_req_t *
dasd_eckd_read_stats(struct dasd_device_t * device)1535 dasd_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 /* PSF */ + 1 /* RSSD */,
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 /* Prepare for Read Subsystem Data */
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; /* Perfomance Statistics */
1569 prssdp->varies[1] = 0x01; /* Perf Statistics for the Subsystem */
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 /* Read Subsystem Data - Performance Statistics */
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 } /* end dasd_eckd_rstat */
1604
1605 /*
1606 * DASD_ECKD_RET_STATS
1607 *
1608 * DESCRIPTION
1609 * returns pointer to Performance Statistics Data.
1610 */
1611 dasd_rssd_perf_stats_t *
dasd_eckd_ret_stats(ccw_req_t * cqr)1612 dasd_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 /* Prepare for Read Subsystem Data */
1624 prssdp = (dasd_psf_prssd_data_t *) cqr->data;
1625 statsp = (dasd_rssd_perf_stats_t *) (prssdp + 1);
1626
1627 return statsp;
1628
1629 } /* end dasd_eckd_rstat */
1630
1631
1632 /*
1633 * DASD_ECKD_GET_ATTRIB
1634 *
1635 * DESCRIPTION
1636 * returnes the cache attributes used in Define Extend (DE).
1637 */
1638 int
dasd_eckd_get_attrib(dasd_device_t * device,attrib_data_t * attrib)1639 dasd_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 } /* end dasd_eckd_get_attrib */
1650
1651 /*
1652 * DASD_ECKD_SET_ATTRIB
1653 *
1654 * DESCRIPTION
1655 * stores the attributes for cache operation to be used in Define Extend (DE).
1656 */
1657 int
dasd_eckd_set_attrib(dasd_device_t * device,attrib_data_t * attrib)1658 dasd_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 } /* end dasd_eckd_set_attrib */
1675
1676 static void
dasd_eckd_dump_sense(struct dasd_device_t * device,ccw_req_t * req)1677 dasd_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 /* 24 Byte Sense Data */
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 /* 32 Byte Sense Data */
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
1762 dasd_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
1793 int
dasd_eckd_init(void)1794 dasd_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 /* CONFIG_DASD_DYNAMIC */
1820 return rc;
1821 }
1822
1823 void
dasd_eckd_cleanup(void)1824 dasd_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 /* CONFIG_DASD_DYNAMIC */
1847 dasd_discipline_del (&dasd_eckd_discipline);
1848 }
1849
1850 #ifdef MODULE
1851 int
init_module(void)1852 init_module (void)
1853 {
1854 int rc = 0;
1855 rc = dasd_eckd_init ();
1856 return rc;
1857 }
1858
1859 void
cleanup_module(void)1860 cleanup_module (void)
1861 {
1862 dasd_eckd_cleanup ();
1863 return;
1864 }
1865 #endif
1866
1867 /*
1868 * Overrides for Emacs so that we follow Linus's tabbing style.
1869 * Emacs will notice this stuff at the end of the file and automatically
1870 * adjust the settings for this buffer only. This must remain at the end
1871 * of the file.
1872 * ---------------------------------------------------------------------------
1873 * Local variables:
1874 * c-indent-level: 4
1875 * c-brace-imaginary-offset: 0
1876 * c-brace-offset: -4
1877 * c-argdecl-indent: 4
1878 * c-label-offset: -4
1879 * c-continued-statement-offset: 4
1880 * c-continued-brace-offset: 0
1881 * indent-tabs-mode: nil
1882 * tab-width: 8
1883 * End:
1884 */
1885