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