1 /* 2 * File...........: linux/drivers/s390/block/dasd_fba.c 3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> 4 * Bugreports.to..: <Linux390@de.ibm.com> 5 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 6 * 7 */ 8 9 #include <linux/stddef.h> 10 #include <linux/kernel.h> 11 #include <asm/debug.h> 12 13 #include <linux/slab.h> 14 #include <linux/hdreg.h> /* HDIO_GETGEO */ 15 #include <linux/bio.h> 16 #include <linux/module.h> 17 #include <linux/init.h> 18 19 #include <asm/idals.h> 20 #include <asm/ebcdic.h> 21 #include <asm/io.h> 22 #include <asm/todclk.h> 23 #include <asm/ccwdev.h> 24 25 #include "dasd_int.h" 26 #include "dasd_fba.h" 27 28 #ifdef PRINTK_HEADER 29 #undef PRINTK_HEADER 30 #endif /* PRINTK_HEADER */ 31 #define PRINTK_HEADER "dasd(fba):" 32 33 #define DASD_FBA_CCW_WRITE 0x41 34 #define DASD_FBA_CCW_READ 0x42 35 #define DASD_FBA_CCW_LOCATE 0x43 36 #define DASD_FBA_CCW_DEFINE_EXTENT 0x63 37 38 MODULE_LICENSE("GPL"); 39 40 static struct dasd_discipline dasd_fba_discipline; 41 42 struct dasd_fba_private { 43 struct dasd_fba_characteristics rdc_data; 44 }; 45 46 static struct ccw_device_id dasd_fba_ids[] = { 47 { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), .driver_info = 0x1}, 48 { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), .driver_info = 0x2}, 49 { /* end of list */ }, 50 }; 51 52 MODULE_DEVICE_TABLE(ccw, dasd_fba_ids); 53 54 static struct ccw_driver dasd_fba_driver; /* see below */ 55 static int 56 dasd_fba_probe(struct ccw_device *cdev) 57 { 58 return dasd_generic_probe(cdev, &dasd_fba_discipline); 59 } 60 61 static int 62 dasd_fba_set_online(struct ccw_device *cdev) 63 { 64 return dasd_generic_set_online(cdev, &dasd_fba_discipline); 65 } 66 67 static struct ccw_driver dasd_fba_driver = { 68 .name = "dasd-fba", 69 .owner = THIS_MODULE, 70 .ids = dasd_fba_ids, 71 .probe = dasd_fba_probe, 72 .remove = dasd_generic_remove, 73 .set_offline = dasd_generic_set_offline, 74 .set_online = dasd_fba_set_online, 75 .notify = dasd_generic_notify, 76 }; 77 78 static void 79 define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw, 80 int blksize, int beg, int nr) 81 { 82 ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT; 83 ccw->flags = 0; 84 ccw->count = 16; 85 ccw->cda = (__u32) __pa(data); 86 memset(data, 0, sizeof (struct DE_fba_data)); 87 if (rw == WRITE) 88 (data->mask).perm = 0x0; 89 else if (rw == READ) 90 (data->mask).perm = 0x1; 91 else 92 data->mask.perm = 0x2; 93 data->blk_size = blksize; 94 data->ext_loc = beg; 95 data->ext_end = nr - 1; 96 } 97 98 static void 99 locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw, 100 int block_nr, int block_ct) 101 { 102 ccw->cmd_code = DASD_FBA_CCW_LOCATE; 103 ccw->flags = 0; 104 ccw->count = 8; 105 ccw->cda = (__u32) __pa(data); 106 memset(data, 0, sizeof (struct LO_fba_data)); 107 if (rw == WRITE) 108 data->operation.cmd = 0x5; 109 else if (rw == READ) 110 data->operation.cmd = 0x6; 111 else 112 data->operation.cmd = 0x8; 113 data->blk_nr = block_nr; 114 data->blk_ct = block_ct; 115 } 116 117 static int 118 dasd_fba_check_characteristics(struct dasd_device *device) 119 { 120 struct dasd_fba_private *private; 121 struct ccw_device *cdev = device->cdev; 122 void *rdc_data; 123 int rc; 124 125 private = (struct dasd_fba_private *) device->private; 126 if (private == NULL) { 127 private = kzalloc(sizeof(struct dasd_fba_private), GFP_KERNEL); 128 if (private == NULL) { 129 DEV_MESSAGE(KERN_WARNING, device, "%s", 130 "memory allocation failed for private " 131 "data"); 132 return -ENOMEM; 133 } 134 device->private = (void *) private; 135 } 136 /* Read Device Characteristics */ 137 rdc_data = (void *) &(private->rdc_data); 138 rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32); 139 if (rc) { 140 DEV_MESSAGE(KERN_WARNING, device, 141 "Read device characteristics returned error %d", 142 rc); 143 return rc; 144 } 145 146 DEV_MESSAGE(KERN_INFO, device, 147 "%04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)", 148 cdev->id.dev_type, 149 cdev->id.dev_model, 150 cdev->id.cu_type, 151 cdev->id.cu_model, 152 ((private->rdc_data.blk_bdsa * 153 (private->rdc_data.blk_size >> 9)) >> 11), 154 private->rdc_data.blk_size); 155 return 0; 156 } 157 158 static int 159 dasd_fba_do_analysis(struct dasd_device *device) 160 { 161 struct dasd_fba_private *private; 162 int sb, rc; 163 164 private = (struct dasd_fba_private *) device->private; 165 rc = dasd_check_blocksize(private->rdc_data.blk_size); 166 if (rc) { 167 DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d", 168 private->rdc_data.blk_size); 169 return rc; 170 } 171 device->blocks = private->rdc_data.blk_bdsa; 172 device->bp_block = private->rdc_data.blk_size; 173 device->s2b_shift = 0; /* bits to shift 512 to get a block */ 174 for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1) 175 device->s2b_shift++; 176 return 0; 177 } 178 179 static int 180 dasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo) 181 { 182 if (dasd_check_blocksize(device->bp_block) != 0) 183 return -EINVAL; 184 geo->cylinders = (device->blocks << device->s2b_shift) >> 10; 185 geo->heads = 16; 186 geo->sectors = 128 >> device->s2b_shift; 187 return 0; 188 } 189 190 static dasd_era_t 191 dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb) 192 { 193 struct dasd_device *device; 194 struct ccw_device *cdev; 195 196 device = (struct dasd_device *) cqr->device; 197 if (irb->scsw.cstat == 0x00 && 198 irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) 199 return dasd_era_none; 200 201 cdev = device->cdev; 202 switch (cdev->id.dev_type) { 203 case 0x3370: 204 return dasd_3370_erp_examine(cqr, irb); 205 case 0x9336: 206 return dasd_9336_erp_examine(cqr, irb); 207 default: 208 return dasd_era_recover; 209 } 210 } 211 212 static dasd_erp_fn_t 213 dasd_fba_erp_action(struct dasd_ccw_req * cqr) 214 { 215 return dasd_default_erp_action; 216 } 217 218 static dasd_erp_fn_t 219 dasd_fba_erp_postaction(struct dasd_ccw_req * cqr) 220 { 221 if (cqr->function == dasd_default_erp_action) 222 return dasd_default_erp_postaction; 223 224 DEV_MESSAGE(KERN_WARNING, cqr->device, "unknown ERP action %p", 225 cqr->function); 226 return NULL; 227 } 228 229 static struct dasd_ccw_req * 230 dasd_fba_build_cp(struct dasd_device * device, struct request *req) 231 { 232 struct dasd_fba_private *private; 233 unsigned long *idaws; 234 struct LO_fba_data *LO_data; 235 struct dasd_ccw_req *cqr; 236 struct ccw1 *ccw; 237 struct req_iterator iter; 238 struct bio_vec *bv; 239 char *dst; 240 int count, cidaw, cplength, datasize; 241 sector_t recid, first_rec, last_rec; 242 unsigned int blksize, off; 243 unsigned char cmd; 244 245 private = (struct dasd_fba_private *) device->private; 246 if (rq_data_dir(req) == READ) { 247 cmd = DASD_FBA_CCW_READ; 248 } else if (rq_data_dir(req) == WRITE) { 249 cmd = DASD_FBA_CCW_WRITE; 250 } else 251 return ERR_PTR(-EINVAL); 252 blksize = device->bp_block; 253 /* Calculate record id of first and last block. */ 254 first_rec = req->sector >> device->s2b_shift; 255 last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift; 256 /* Check struct bio and count the number of blocks for the request. */ 257 count = 0; 258 cidaw = 0; 259 rq_for_each_segment(bv, req, iter) { 260 if (bv->bv_len & (blksize - 1)) 261 /* Fba can only do full blocks. */ 262 return ERR_PTR(-EINVAL); 263 count += bv->bv_len >> (device->s2b_shift + 9); 264 #if defined(CONFIG_64BIT) 265 if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) 266 cidaw += bv->bv_len / blksize; 267 #endif 268 } 269 /* Paranoia. */ 270 if (count != last_rec - first_rec + 1) 271 return ERR_PTR(-EINVAL); 272 /* 1x define extent + 1x locate record + number of blocks */ 273 cplength = 2 + count; 274 /* 1x define extent + 1x locate record */ 275 datasize = sizeof(struct DE_fba_data) + sizeof(struct LO_fba_data) + 276 cidaw * sizeof(unsigned long); 277 /* 278 * Find out number of additional locate record ccws if the device 279 * can't do data chaining. 280 */ 281 if (private->rdc_data.mode.bits.data_chain == 0) { 282 cplength += count - 1; 283 datasize += (count - 1)*sizeof(struct LO_fba_data); 284 } 285 /* Allocate the ccw request. */ 286 cqr = dasd_smalloc_request(dasd_fba_discipline.name, 287 cplength, datasize, device); 288 if (IS_ERR(cqr)) 289 return cqr; 290 ccw = cqr->cpaddr; 291 /* First ccw is define extent. */ 292 define_extent(ccw++, cqr->data, rq_data_dir(req), 293 device->bp_block, req->sector, req->nr_sectors); 294 /* Build locate_record + read/write ccws. */ 295 idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data)); 296 LO_data = (struct LO_fba_data *) (idaws + cidaw); 297 /* Locate record for all blocks for smart devices. */ 298 if (private->rdc_data.mode.bits.data_chain != 0) { 299 ccw[-1].flags |= CCW_FLAG_CC; 300 locate_record(ccw++, LO_data++, rq_data_dir(req), 0, count); 301 } 302 recid = first_rec; 303 rq_for_each_segment(bv, req, iter) { 304 dst = page_address(bv->bv_page) + bv->bv_offset; 305 if (dasd_page_cache) { 306 char *copy = kmem_cache_alloc(dasd_page_cache, 307 GFP_DMA | __GFP_NOWARN); 308 if (copy && rq_data_dir(req) == WRITE) 309 memcpy(copy + bv->bv_offset, dst, bv->bv_len); 310 if (copy) 311 dst = copy + bv->bv_offset; 312 } 313 for (off = 0; off < bv->bv_len; off += blksize) { 314 /* Locate record for stupid devices. */ 315 if (private->rdc_data.mode.bits.data_chain == 0) { 316 ccw[-1].flags |= CCW_FLAG_CC; 317 locate_record(ccw, LO_data++, 318 rq_data_dir(req), 319 recid - first_rec, 1); 320 ccw->flags = CCW_FLAG_CC; 321 ccw++; 322 } else { 323 if (recid > first_rec) 324 ccw[-1].flags |= CCW_FLAG_DC; 325 else 326 ccw[-1].flags |= CCW_FLAG_CC; 327 } 328 ccw->cmd_code = cmd; 329 ccw->count = device->bp_block; 330 if (idal_is_needed(dst, blksize)) { 331 ccw->cda = (__u32)(addr_t) idaws; 332 ccw->flags = CCW_FLAG_IDA; 333 idaws = idal_create_words(idaws, dst, blksize); 334 } else { 335 ccw->cda = (__u32)(addr_t) dst; 336 ccw->flags = 0; 337 } 338 ccw++; 339 dst += blksize; 340 recid++; 341 } 342 } 343 if (req->cmd_flags & REQ_FAILFAST) 344 set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); 345 cqr->device = device; 346 cqr->expires = 5 * 60 * HZ; /* 5 minutes */ 347 cqr->retries = 32; 348 cqr->buildclk = get_clock(); 349 cqr->status = DASD_CQR_FILLED; 350 return cqr; 351 } 352 353 static int 354 dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) 355 { 356 struct dasd_fba_private *private; 357 struct ccw1 *ccw; 358 struct req_iterator iter; 359 struct bio_vec *bv; 360 char *dst, *cda; 361 unsigned int blksize, off; 362 int status; 363 364 if (!dasd_page_cache) 365 goto out; 366 private = (struct dasd_fba_private *) cqr->device->private; 367 blksize = cqr->device->bp_block; 368 ccw = cqr->cpaddr; 369 /* Skip over define extent & locate record. */ 370 ccw++; 371 if (private->rdc_data.mode.bits.data_chain != 0) 372 ccw++; 373 rq_for_each_segment(bv, req, iter) { 374 dst = page_address(bv->bv_page) + bv->bv_offset; 375 for (off = 0; off < bv->bv_len; off += blksize) { 376 /* Skip locate record. */ 377 if (private->rdc_data.mode.bits.data_chain == 0) 378 ccw++; 379 if (dst) { 380 if (ccw->flags & CCW_FLAG_IDA) 381 cda = *((char **)((addr_t) ccw->cda)); 382 else 383 cda = (char *)((addr_t) ccw->cda); 384 if (dst != cda) { 385 if (rq_data_dir(req) == READ) 386 memcpy(dst, cda, bv->bv_len); 387 kmem_cache_free(dasd_page_cache, 388 (void *)((addr_t)cda & PAGE_MASK)); 389 } 390 dst = NULL; 391 } 392 ccw++; 393 } 394 } 395 out: 396 status = cqr->status == DASD_CQR_DONE; 397 dasd_sfree_request(cqr, cqr->device); 398 return status; 399 } 400 401 static int 402 dasd_fba_fill_info(struct dasd_device * device, 403 struct dasd_information2_t * info) 404 { 405 info->label_block = 1; 406 info->FBA_layout = 1; 407 info->format = DASD_FORMAT_LDL; 408 info->characteristics_size = sizeof(struct dasd_fba_characteristics); 409 memcpy(info->characteristics, 410 &((struct dasd_fba_private *) device->private)->rdc_data, 411 sizeof (struct dasd_fba_characteristics)); 412 info->confdata_size = 0; 413 return 0; 414 } 415 416 static void 417 dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, 418 struct irb *irb) 419 { 420 char *page; 421 struct ccw1 *act, *end, *last; 422 int len, sl, sct, count; 423 424 page = (char *) get_zeroed_page(GFP_ATOMIC); 425 if (page == NULL) { 426 DEV_MESSAGE(KERN_ERR, device, " %s", 427 "No memory to dump sense data"); 428 return; 429 } 430 len = sprintf(page, KERN_ERR PRINTK_HEADER 431 " I/O status report for device %s:\n", 432 device->cdev->dev.bus_id); 433 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 434 " in req: %p CS: 0x%02X DS: 0x%02X\n", req, 435 irb->scsw.cstat, irb->scsw.dstat); 436 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 437 " device %s: Failing CCW: %p\n", 438 device->cdev->dev.bus_id, 439 (void *) (addr_t) irb->scsw.cpa); 440 if (irb->esw.esw0.erw.cons) { 441 for (sl = 0; sl < 4; sl++) { 442 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 443 " Sense(hex) %2d-%2d:", 444 (8 * sl), ((8 * sl) + 7)); 445 446 for (sct = 0; sct < 8; sct++) { 447 len += sprintf(page + len, " %02x", 448 irb->ecw[8 * sl + sct]); 449 } 450 len += sprintf(page + len, "\n"); 451 } 452 } else { 453 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 454 " SORRY - NO VALID SENSE AVAILABLE\n"); 455 } 456 MESSAGE_LOG(KERN_ERR, "%s", 457 page + sizeof(KERN_ERR PRINTK_HEADER)); 458 459 /* dump the Channel Program */ 460 /* print first CCWs (maximum 8) */ 461 act = req->cpaddr; 462 for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++); 463 end = min(act + 8, last); 464 len = sprintf(page, KERN_ERR PRINTK_HEADER 465 " Related CP in req: %p\n", req); 466 while (act <= end) { 467 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 468 " CCW %p: %08X %08X DAT:", 469 act, ((int *) act)[0], ((int *) act)[1]); 470 for (count = 0; count < 32 && count < act->count; 471 count += sizeof(int)) 472 len += sprintf(page + len, " %08X", 473 ((int *) (addr_t) act->cda) 474 [(count>>2)]); 475 len += sprintf(page + len, "\n"); 476 act++; 477 } 478 MESSAGE_LOG(KERN_ERR, "%s", 479 page + sizeof(KERN_ERR PRINTK_HEADER)); 480 481 482 /* print failing CCW area */ 483 len = 0; 484 if (act < ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) { 485 act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2; 486 len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); 487 } 488 end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last); 489 while (act <= end) { 490 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 491 " CCW %p: %08X %08X DAT:", 492 act, ((int *) act)[0], ((int *) act)[1]); 493 for (count = 0; count < 32 && count < act->count; 494 count += sizeof(int)) 495 len += sprintf(page + len, " %08X", 496 ((int *) (addr_t) act->cda) 497 [(count>>2)]); 498 len += sprintf(page + len, "\n"); 499 act++; 500 } 501 502 /* print last CCWs */ 503 if (act < last - 2) { 504 act = last - 2; 505 len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); 506 } 507 while (act <= last) { 508 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 509 " CCW %p: %08X %08X DAT:", 510 act, ((int *) act)[0], ((int *) act)[1]); 511 for (count = 0; count < 32 && count < act->count; 512 count += sizeof(int)) 513 len += sprintf(page + len, " %08X", 514 ((int *) (addr_t) act->cda) 515 [(count>>2)]); 516 len += sprintf(page + len, "\n"); 517 act++; 518 } 519 if (len > 0) 520 MESSAGE_LOG(KERN_ERR, "%s", 521 page + sizeof(KERN_ERR PRINTK_HEADER)); 522 free_page((unsigned long) page); 523 } 524 525 /* 526 * max_blocks is dependent on the amount of storage that is available 527 * in the static io buffer for each device. Currently each device has 528 * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has 529 * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use 530 * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In 531 * addition we have one define extent ccw + 16 bytes of data and a 532 * locate record ccw for each block (stupid devices!) + 16 bytes of data. 533 * That makes: 534 * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum. 535 * We want to fit two into the available memory so that we can immediately 536 * start the next request if one finishes off. That makes 100.1 blocks 537 * for one request. Give a little safety and the result is 96. 538 */ 539 static struct dasd_discipline dasd_fba_discipline = { 540 .owner = THIS_MODULE, 541 .name = "FBA ", 542 .ebcname = "FBA ", 543 .max_blocks = 96, 544 .check_device = dasd_fba_check_characteristics, 545 .do_analysis = dasd_fba_do_analysis, 546 .fill_geometry = dasd_fba_fill_geometry, 547 .start_IO = dasd_start_IO, 548 .term_IO = dasd_term_IO, 549 .examine_error = dasd_fba_examine_error, 550 .erp_action = dasd_fba_erp_action, 551 .erp_postaction = dasd_fba_erp_postaction, 552 .build_cp = dasd_fba_build_cp, 553 .free_cp = dasd_fba_free_cp, 554 .dump_sense = dasd_fba_dump_sense, 555 .fill_info = dasd_fba_fill_info, 556 }; 557 558 static int __init 559 dasd_fba_init(void) 560 { 561 ASCEBC(dasd_fba_discipline.ebcname, 4); 562 return ccw_driver_register(&dasd_fba_driver); 563 } 564 565 static void __exit 566 dasd_fba_cleanup(void) 567 { 568 ccw_driver_unregister(&dasd_fba_driver); 569 } 570 571 module_init(dasd_fba_init); 572 module_exit(dasd_fba_cleanup); 573