0001
0002
0003
0004
0005
0006
0007
0008 #define KMSG_COMPONENT "dasd-fba"
0009
0010 #include <linux/stddef.h>
0011 #include <linux/kernel.h>
0012 #include <asm/debug.h>
0013
0014 #include <linux/slab.h>
0015 #include <linux/hdreg.h> /* HDIO_GETGEO */
0016 #include <linux/bio.h>
0017 #include <linux/module.h>
0018 #include <linux/init.h>
0019
0020 #include <asm/idals.h>
0021 #include <asm/ebcdic.h>
0022 #include <asm/io.h>
0023 #include <asm/ccwdev.h>
0024
0025 #include "dasd_int.h"
0026 #include "dasd_fba.h"
0027
0028 #ifdef PRINTK_HEADER
0029 #undef PRINTK_HEADER
0030 #endif
0031 #define PRINTK_HEADER "dasd(fba):"
0032
0033 #define FBA_DEFAULT_RETRIES 32
0034
0035 #define DASD_FBA_CCW_WRITE 0x41
0036 #define DASD_FBA_CCW_READ 0x42
0037 #define DASD_FBA_CCW_LOCATE 0x43
0038 #define DASD_FBA_CCW_DEFINE_EXTENT 0x63
0039
0040 MODULE_LICENSE("GPL");
0041
0042 static struct dasd_discipline dasd_fba_discipline;
0043 static void *dasd_fba_zero_page;
0044
0045 struct dasd_fba_private {
0046 struct dasd_fba_characteristics rdc_data;
0047 };
0048
0049 static struct ccw_device_id dasd_fba_ids[] = {
0050 { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), .driver_info = 0x1},
0051 { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), .driver_info = 0x2},
0052 { },
0053 };
0054
0055 MODULE_DEVICE_TABLE(ccw, dasd_fba_ids);
0056
0057 static int
0058 dasd_fba_set_online(struct ccw_device *cdev)
0059 {
0060 return dasd_generic_set_online(cdev, &dasd_fba_discipline);
0061 }
0062
0063 static struct ccw_driver dasd_fba_driver = {
0064 .driver = {
0065 .name = "dasd-fba",
0066 .owner = THIS_MODULE,
0067 .dev_groups = dasd_dev_groups,
0068 },
0069 .ids = dasd_fba_ids,
0070 .probe = dasd_generic_probe,
0071 .remove = dasd_generic_remove,
0072 .set_offline = dasd_generic_set_offline,
0073 .set_online = dasd_fba_set_online,
0074 .notify = dasd_generic_notify,
0075 .path_event = dasd_generic_path_event,
0076 .int_class = IRQIO_DAS,
0077 };
0078
0079 static void
0080 define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
0081 int blksize, int beg, int nr)
0082 {
0083 ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
0084 ccw->flags = 0;
0085 ccw->count = 16;
0086 ccw->cda = (__u32) __pa(data);
0087 memset(data, 0, sizeof (struct DE_fba_data));
0088 if (rw == WRITE)
0089 (data->mask).perm = 0x0;
0090 else if (rw == READ)
0091 (data->mask).perm = 0x1;
0092 else
0093 data->mask.perm = 0x2;
0094 data->blk_size = blksize;
0095 data->ext_loc = beg;
0096 data->ext_end = nr - 1;
0097 }
0098
0099 static void
0100 locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
0101 int block_nr, int block_ct)
0102 {
0103 ccw->cmd_code = DASD_FBA_CCW_LOCATE;
0104 ccw->flags = 0;
0105 ccw->count = 8;
0106 ccw->cda = (__u32) __pa(data);
0107 memset(data, 0, sizeof (struct LO_fba_data));
0108 if (rw == WRITE)
0109 data->operation.cmd = 0x5;
0110 else if (rw == READ)
0111 data->operation.cmd = 0x6;
0112 else
0113 data->operation.cmd = 0x8;
0114 data->blk_nr = block_nr;
0115 data->blk_ct = block_ct;
0116 }
0117
0118 static int
0119 dasd_fba_check_characteristics(struct dasd_device *device)
0120 {
0121 struct dasd_fba_private *private = device->private;
0122 struct ccw_device *cdev = device->cdev;
0123 struct dasd_block *block;
0124 int readonly, rc;
0125
0126 if (!private) {
0127 private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
0128 if (!private) {
0129 dev_warn(&device->cdev->dev,
0130 "Allocating memory for private DASD "
0131 "data failed\n");
0132 return -ENOMEM;
0133 }
0134 device->private = private;
0135 } else {
0136 memset(private, 0, sizeof(*private));
0137 }
0138 block = dasd_alloc_block();
0139 if (IS_ERR(block)) {
0140 DBF_EVENT_DEVID(DBF_WARNING, cdev, "%s", "could not allocate "
0141 "dasd block structure");
0142 device->private = NULL;
0143 kfree(private);
0144 return PTR_ERR(block);
0145 }
0146 device->block = block;
0147 block->base = device;
0148
0149
0150 rc = dasd_generic_read_dev_chars(device, DASD_FBA_MAGIC,
0151 &private->rdc_data, 32);
0152 if (rc) {
0153 DBF_EVENT_DEVID(DBF_WARNING, cdev, "Read device "
0154 "characteristics returned error %d", rc);
0155 device->block = NULL;
0156 dasd_free_block(block);
0157 device->private = NULL;
0158 kfree(private);
0159 return rc;
0160 }
0161
0162 device->default_expires = DASD_EXPIRES;
0163 device->default_retries = FBA_DEFAULT_RETRIES;
0164 dasd_path_set_opm(device, LPM_ANYPATH);
0165
0166 readonly = dasd_device_is_ro(device);
0167 if (readonly)
0168 set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
0169
0170
0171 dasd_set_feature(cdev, DASD_FEATURE_DISCARD, 1);
0172
0173 dev_info(&device->cdev->dev,
0174 "New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB "
0175 "and %d B/blk%s\n",
0176 cdev->id.dev_type,
0177 cdev->id.dev_model,
0178 cdev->id.cu_type,
0179 cdev->id.cu_model,
0180 ((private->rdc_data.blk_bdsa *
0181 (private->rdc_data.blk_size >> 9)) >> 11),
0182 private->rdc_data.blk_size,
0183 readonly ? ", read-only device" : "");
0184 return 0;
0185 }
0186
0187 static int dasd_fba_do_analysis(struct dasd_block *block)
0188 {
0189 struct dasd_fba_private *private = block->base->private;
0190 int sb, rc;
0191
0192 rc = dasd_check_blocksize(private->rdc_data.blk_size);
0193 if (rc) {
0194 DBF_DEV_EVENT(DBF_WARNING, block->base, "unknown blocksize %d",
0195 private->rdc_data.blk_size);
0196 return rc;
0197 }
0198 block->blocks = private->rdc_data.blk_bdsa;
0199 block->bp_block = private->rdc_data.blk_size;
0200 block->s2b_shift = 0;
0201 for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1)
0202 block->s2b_shift++;
0203 return 0;
0204 }
0205
0206 static int dasd_fba_fill_geometry(struct dasd_block *block,
0207 struct hd_geometry *geo)
0208 {
0209 if (dasd_check_blocksize(block->bp_block) != 0)
0210 return -EINVAL;
0211 geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
0212 geo->heads = 16;
0213 geo->sectors = 128 >> block->s2b_shift;
0214 return 0;
0215 }
0216
0217 static dasd_erp_fn_t
0218 dasd_fba_erp_action(struct dasd_ccw_req * cqr)
0219 {
0220 return dasd_default_erp_action;
0221 }
0222
0223 static dasd_erp_fn_t
0224 dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)
0225 {
0226 if (cqr->function == dasd_default_erp_action)
0227 return dasd_default_erp_postaction;
0228
0229 DBF_DEV_EVENT(DBF_WARNING, cqr->startdev, "unknown ERP action %p",
0230 cqr->function);
0231 return NULL;
0232 }
0233
0234 static void dasd_fba_check_for_device_change(struct dasd_device *device,
0235 struct dasd_ccw_req *cqr,
0236 struct irb *irb)
0237 {
0238 char mask;
0239
0240
0241 mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
0242 if ((irb->scsw.cmd.dstat & mask) == mask)
0243 dasd_generic_handle_state_change(device);
0244 };
0245
0246
0247
0248
0249
0250 static void ccw_write_no_data(struct ccw1 *ccw)
0251 {
0252 ccw->cmd_code = DASD_FBA_CCW_WRITE;
0253 ccw->flags |= CCW_FLAG_SLI;
0254 ccw->count = 0;
0255 }
0256
0257
0258
0259
0260 static void ccw_write_zero(struct ccw1 *ccw, int count)
0261 {
0262 ccw->cmd_code = DASD_FBA_CCW_WRITE;
0263 ccw->flags |= CCW_FLAG_SLI;
0264 ccw->count = count;
0265 ccw->cda = (__u32) (addr_t) dasd_fba_zero_page;
0266 }
0267
0268
0269
0270
0271
0272 static int count_ccws(sector_t first_rec, sector_t last_rec,
0273 unsigned int blocks_per_page)
0274 {
0275 sector_t wz_stop = 0, d_stop = 0;
0276 int cur_pos = 0;
0277 int count = 0;
0278
0279 if (first_rec % blocks_per_page != 0) {
0280 wz_stop = first_rec + blocks_per_page -
0281 (first_rec % blocks_per_page) - 1;
0282 if (wz_stop > last_rec)
0283 wz_stop = last_rec;
0284 cur_pos = wz_stop - first_rec + 1;
0285 count++;
0286 }
0287
0288 if (last_rec - (first_rec + cur_pos) + 1 >= blocks_per_page) {
0289 if ((last_rec - blocks_per_page + 1) % blocks_per_page != 0)
0290 d_stop = last_rec - ((last_rec - blocks_per_page + 1) %
0291 blocks_per_page);
0292 else
0293 d_stop = last_rec;
0294
0295 cur_pos += d_stop - (first_rec + cur_pos) + 1;
0296 count++;
0297 }
0298
0299 if (cur_pos == 0 || first_rec + cur_pos - 1 < last_rec)
0300 count++;
0301
0302 return count;
0303 }
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316 static struct dasd_ccw_req *dasd_fba_build_cp_discard(
0317 struct dasd_device *memdev,
0318 struct dasd_block *block,
0319 struct request *req)
0320 {
0321 struct LO_fba_data *LO_data;
0322 struct dasd_ccw_req *cqr;
0323 struct ccw1 *ccw;
0324
0325 sector_t wz_stop = 0, d_stop = 0;
0326 sector_t first_rec, last_rec;
0327
0328 unsigned int blksize = block->bp_block;
0329 unsigned int blocks_per_page;
0330 int wz_count = 0;
0331 int d_count = 0;
0332 int cur_pos = 0;
0333 int count = 0;
0334 int cplength;
0335 int datasize;
0336 int nr_ccws;
0337
0338 first_rec = blk_rq_pos(req) >> block->s2b_shift;
0339 last_rec =
0340 (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
0341 count = last_rec - first_rec + 1;
0342
0343 blocks_per_page = BLOCKS_PER_PAGE(blksize);
0344 nr_ccws = count_ccws(first_rec, last_rec, blocks_per_page);
0345
0346
0347 cplength = 1 + 2 * nr_ccws;
0348 datasize = sizeof(struct DE_fba_data) +
0349 nr_ccws * (sizeof(struct LO_fba_data) + sizeof(struct ccw1));
0350
0351 cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev,
0352 blk_mq_rq_to_pdu(req));
0353 if (IS_ERR(cqr))
0354 return cqr;
0355
0356 ccw = cqr->cpaddr;
0357
0358 define_extent(ccw++, cqr->data, WRITE, blksize, first_rec, count);
0359 LO_data = cqr->data + sizeof(struct DE_fba_data);
0360
0361
0362 if (first_rec % blocks_per_page != 0) {
0363 wz_stop = first_rec + blocks_per_page -
0364 (first_rec % blocks_per_page) - 1;
0365 if (wz_stop > last_rec)
0366 wz_stop = last_rec;
0367 wz_count = wz_stop - first_rec + 1;
0368
0369 ccw[-1].flags |= CCW_FLAG_CC;
0370 locate_record(ccw++, LO_data++, WRITE, cur_pos, wz_count);
0371
0372 ccw[-1].flags |= CCW_FLAG_CC;
0373 ccw_write_zero(ccw++, wz_count * blksize);
0374
0375 cur_pos = wz_count;
0376 }
0377
0378
0379 if (last_rec - (first_rec + cur_pos) + 1 >= blocks_per_page) {
0380
0381 if ((last_rec - blocks_per_page + 1) % blocks_per_page != 0)
0382 d_stop = last_rec - ((last_rec - blocks_per_page + 1) %
0383 blocks_per_page);
0384 else
0385 d_stop = last_rec;
0386
0387 d_count = d_stop - (first_rec + cur_pos) + 1;
0388
0389 ccw[-1].flags |= CCW_FLAG_CC;
0390 locate_record(ccw++, LO_data++, WRITE, cur_pos, d_count);
0391
0392 ccw[-1].flags |= CCW_FLAG_CC;
0393 ccw_write_no_data(ccw++);
0394
0395 cur_pos += d_count;
0396 }
0397
0398
0399 if (cur_pos == 0 || first_rec + cur_pos - 1 < last_rec) {
0400 if (d_stop != 0)
0401 wz_count = last_rec - d_stop;
0402 else if (wz_stop != 0)
0403 wz_count = last_rec - wz_stop;
0404 else
0405 wz_count = count;
0406
0407 ccw[-1].flags |= CCW_FLAG_CC;
0408 locate_record(ccw++, LO_data++, WRITE, cur_pos, wz_count);
0409
0410 ccw[-1].flags |= CCW_FLAG_CC;
0411 ccw_write_zero(ccw++, wz_count * blksize);
0412 }
0413
0414 if (blk_noretry_request(req) ||
0415 block->base->features & DASD_FEATURE_FAILFAST)
0416 set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
0417
0418 cqr->startdev = memdev;
0419 cqr->memdev = memdev;
0420 cqr->block = block;
0421 cqr->expires = memdev->default_expires * HZ;
0422 cqr->retries = memdev->default_retries;
0423 cqr->buildclk = get_tod_clock();
0424 cqr->status = DASD_CQR_FILLED;
0425
0426 return cqr;
0427 }
0428
0429 static struct dasd_ccw_req *dasd_fba_build_cp_regular(
0430 struct dasd_device *memdev,
0431 struct dasd_block *block,
0432 struct request *req)
0433 {
0434 struct dasd_fba_private *private = block->base->private;
0435 unsigned long *idaws;
0436 struct LO_fba_data *LO_data;
0437 struct dasd_ccw_req *cqr;
0438 struct ccw1 *ccw;
0439 struct req_iterator iter;
0440 struct bio_vec bv;
0441 char *dst;
0442 int count, cidaw, cplength, datasize;
0443 sector_t recid, first_rec, last_rec;
0444 unsigned int blksize, off;
0445 unsigned char cmd;
0446
0447 if (rq_data_dir(req) == READ) {
0448 cmd = DASD_FBA_CCW_READ;
0449 } else if (rq_data_dir(req) == WRITE) {
0450 cmd = DASD_FBA_CCW_WRITE;
0451 } else
0452 return ERR_PTR(-EINVAL);
0453 blksize = block->bp_block;
0454
0455 first_rec = blk_rq_pos(req) >> block->s2b_shift;
0456 last_rec =
0457 (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
0458
0459 count = 0;
0460 cidaw = 0;
0461 rq_for_each_segment(bv, req, iter) {
0462 if (bv.bv_len & (blksize - 1))
0463
0464 return ERR_PTR(-EINVAL);
0465 count += bv.bv_len >> (block->s2b_shift + 9);
0466 if (idal_is_needed (page_address(bv.bv_page), bv.bv_len))
0467 cidaw += bv.bv_len / blksize;
0468 }
0469
0470 if (count != last_rec - first_rec + 1)
0471 return ERR_PTR(-EINVAL);
0472
0473 cplength = 2 + count;
0474
0475 datasize = sizeof(struct DE_fba_data) + sizeof(struct LO_fba_data) +
0476 cidaw * sizeof(unsigned long);
0477
0478
0479
0480
0481 if (private->rdc_data.mode.bits.data_chain == 0) {
0482 cplength += count - 1;
0483 datasize += (count - 1)*sizeof(struct LO_fba_data);
0484 }
0485
0486 cqr = dasd_smalloc_request(DASD_FBA_MAGIC, cplength, datasize, memdev,
0487 blk_mq_rq_to_pdu(req));
0488 if (IS_ERR(cqr))
0489 return cqr;
0490 ccw = cqr->cpaddr;
0491
0492 define_extent(ccw++, cqr->data, rq_data_dir(req),
0493 block->bp_block, blk_rq_pos(req), blk_rq_sectors(req));
0494
0495 idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
0496 LO_data = (struct LO_fba_data *) (idaws + cidaw);
0497
0498 if (private->rdc_data.mode.bits.data_chain != 0) {
0499 ccw[-1].flags |= CCW_FLAG_CC;
0500 locate_record(ccw++, LO_data++, rq_data_dir(req), 0, count);
0501 }
0502 recid = first_rec;
0503 rq_for_each_segment(bv, req, iter) {
0504 dst = bvec_virt(&bv);
0505 if (dasd_page_cache) {
0506 char *copy = kmem_cache_alloc(dasd_page_cache,
0507 GFP_DMA | __GFP_NOWARN);
0508 if (copy && rq_data_dir(req) == WRITE)
0509 memcpy(copy + bv.bv_offset, dst, bv.bv_len);
0510 if (copy)
0511 dst = copy + bv.bv_offset;
0512 }
0513 for (off = 0; off < bv.bv_len; off += blksize) {
0514
0515 if (private->rdc_data.mode.bits.data_chain == 0) {
0516 ccw[-1].flags |= CCW_FLAG_CC;
0517 locate_record(ccw, LO_data++,
0518 rq_data_dir(req),
0519 recid - first_rec, 1);
0520 ccw->flags = CCW_FLAG_CC;
0521 ccw++;
0522 } else {
0523 if (recid > first_rec)
0524 ccw[-1].flags |= CCW_FLAG_DC;
0525 else
0526 ccw[-1].flags |= CCW_FLAG_CC;
0527 }
0528 ccw->cmd_code = cmd;
0529 ccw->count = block->bp_block;
0530 if (idal_is_needed(dst, blksize)) {
0531 ccw->cda = (__u32)(addr_t) idaws;
0532 ccw->flags = CCW_FLAG_IDA;
0533 idaws = idal_create_words(idaws, dst, blksize);
0534 } else {
0535 ccw->cda = (__u32)(addr_t) dst;
0536 ccw->flags = 0;
0537 }
0538 ccw++;
0539 dst += blksize;
0540 recid++;
0541 }
0542 }
0543 if (blk_noretry_request(req) ||
0544 block->base->features & DASD_FEATURE_FAILFAST)
0545 set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
0546 cqr->startdev = memdev;
0547 cqr->memdev = memdev;
0548 cqr->block = block;
0549 cqr->expires = memdev->default_expires * HZ;
0550 cqr->retries = memdev->default_retries;
0551 cqr->buildclk = get_tod_clock();
0552 cqr->status = DASD_CQR_FILLED;
0553 return cqr;
0554 }
0555
0556 static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device *memdev,
0557 struct dasd_block *block,
0558 struct request *req)
0559 {
0560 if (req_op(req) == REQ_OP_DISCARD || req_op(req) == REQ_OP_WRITE_ZEROES)
0561 return dasd_fba_build_cp_discard(memdev, block, req);
0562 else
0563 return dasd_fba_build_cp_regular(memdev, block, req);
0564 }
0565
0566 static int
0567 dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
0568 {
0569 struct dasd_fba_private *private = cqr->block->base->private;
0570 struct ccw1 *ccw;
0571 struct req_iterator iter;
0572 struct bio_vec bv;
0573 char *dst, *cda;
0574 unsigned int blksize, off;
0575 int status;
0576
0577 if (!dasd_page_cache)
0578 goto out;
0579 blksize = cqr->block->bp_block;
0580 ccw = cqr->cpaddr;
0581
0582 ccw++;
0583 if (private->rdc_data.mode.bits.data_chain != 0)
0584 ccw++;
0585 rq_for_each_segment(bv, req, iter) {
0586 dst = bvec_virt(&bv);
0587 for (off = 0; off < bv.bv_len; off += blksize) {
0588
0589 if (private->rdc_data.mode.bits.data_chain == 0)
0590 ccw++;
0591 if (dst) {
0592 if (ccw->flags & CCW_FLAG_IDA)
0593 cda = *((char **)((addr_t) ccw->cda));
0594 else
0595 cda = (char *)((addr_t) ccw->cda);
0596 if (dst != cda) {
0597 if (rq_data_dir(req) == READ)
0598 memcpy(dst, cda, bv.bv_len);
0599 kmem_cache_free(dasd_page_cache,
0600 (void *)((addr_t)cda & PAGE_MASK));
0601 }
0602 dst = NULL;
0603 }
0604 ccw++;
0605 }
0606 }
0607 out:
0608 status = cqr->status == DASD_CQR_DONE;
0609 dasd_sfree_request(cqr, cqr->memdev);
0610 return status;
0611 }
0612
0613 static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
0614 {
0615 if (cqr->retries < 0)
0616 cqr->status = DASD_CQR_FAILED;
0617 else
0618 cqr->status = DASD_CQR_FILLED;
0619 };
0620
0621 static int
0622 dasd_fba_fill_info(struct dasd_device * device,
0623 struct dasd_information2_t * info)
0624 {
0625 struct dasd_fba_private *private = device->private;
0626
0627 info->label_block = 1;
0628 info->FBA_layout = 1;
0629 info->format = DASD_FORMAT_LDL;
0630 info->characteristics_size = sizeof(private->rdc_data);
0631 memcpy(info->characteristics, &private->rdc_data,
0632 sizeof(private->rdc_data));
0633 info->confdata_size = 0;
0634 return 0;
0635 }
0636
0637 static void
0638 dasd_fba_dump_sense_dbf(struct dasd_device *device, struct irb *irb,
0639 char *reason)
0640 {
0641 u64 *sense;
0642
0643 sense = (u64 *) dasd_get_sense(irb);
0644 if (sense) {
0645 DBF_DEV_EVENT(DBF_EMERG, device,
0646 "%s: %s %02x%02x%02x %016llx %016llx %016llx "
0647 "%016llx", reason,
0648 scsw_is_tm(&irb->scsw) ? "t" : "c",
0649 scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw),
0650 scsw_dstat(&irb->scsw), sense[0], sense[1],
0651 sense[2], sense[3]);
0652 } else {
0653 DBF_DEV_EVENT(DBF_EMERG, device, "%s",
0654 "SORRY - NO VALID SENSE AVAILABLE\n");
0655 }
0656 }
0657
0658
0659 static void
0660 dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
0661 struct irb *irb)
0662 {
0663 char *page;
0664 struct ccw1 *act, *end, *last;
0665 int len, sl, sct, count;
0666
0667 page = (char *) get_zeroed_page(GFP_ATOMIC);
0668 if (page == NULL) {
0669 DBF_DEV_EVENT(DBF_WARNING, device, "%s",
0670 "No memory to dump sense data");
0671 return;
0672 }
0673 len = sprintf(page, PRINTK_HEADER
0674 " I/O status report for device %s:\n",
0675 dev_name(&device->cdev->dev));
0676 len += sprintf(page + len, PRINTK_HEADER
0677 " in req: %p CS: 0x%02X DS: 0x%02X\n", req,
0678 irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
0679 len += sprintf(page + len, PRINTK_HEADER
0680 " device %s: Failing CCW: %p\n",
0681 dev_name(&device->cdev->dev),
0682 (void *) (addr_t) irb->scsw.cmd.cpa);
0683 if (irb->esw.esw0.erw.cons) {
0684 for (sl = 0; sl < 4; sl++) {
0685 len += sprintf(page + len, PRINTK_HEADER
0686 " Sense(hex) %2d-%2d:",
0687 (8 * sl), ((8 * sl) + 7));
0688
0689 for (sct = 0; sct < 8; sct++) {
0690 len += sprintf(page + len, " %02x",
0691 irb->ecw[8 * sl + sct]);
0692 }
0693 len += sprintf(page + len, "\n");
0694 }
0695 } else {
0696 len += sprintf(page + len, PRINTK_HEADER
0697 " SORRY - NO VALID SENSE AVAILABLE\n");
0698 }
0699 printk(KERN_ERR "%s", page);
0700
0701
0702
0703 act = req->cpaddr;
0704 for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
0705 end = min(act + 8, last);
0706 len = sprintf(page, PRINTK_HEADER " Related CP in req: %p\n", req);
0707 while (act <= end) {
0708 len += sprintf(page + len, PRINTK_HEADER
0709 " CCW %p: %08X %08X DAT:",
0710 act, ((int *) act)[0], ((int *) act)[1]);
0711 for (count = 0; count < 32 && count < act->count;
0712 count += sizeof(int))
0713 len += sprintf(page + len, " %08X",
0714 ((int *) (addr_t) act->cda)
0715 [(count>>2)]);
0716 len += sprintf(page + len, "\n");
0717 act++;
0718 }
0719 printk(KERN_ERR "%s", page);
0720
0721
0722
0723 len = 0;
0724 if (act < ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2) {
0725 act = ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2;
0726 len += sprintf(page + len, PRINTK_HEADER "......\n");
0727 }
0728 end = min((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa + 2, last);
0729 while (act <= end) {
0730 len += sprintf(page + len, PRINTK_HEADER
0731 " CCW %p: %08X %08X DAT:",
0732 act, ((int *) act)[0], ((int *) act)[1]);
0733 for (count = 0; count < 32 && count < act->count;
0734 count += sizeof(int))
0735 len += sprintf(page + len, " %08X",
0736 ((int *) (addr_t) act->cda)
0737 [(count>>2)]);
0738 len += sprintf(page + len, "\n");
0739 act++;
0740 }
0741
0742
0743 if (act < last - 2) {
0744 act = last - 2;
0745 len += sprintf(page + len, PRINTK_HEADER "......\n");
0746 }
0747 while (act <= last) {
0748 len += sprintf(page + len, PRINTK_HEADER
0749 " CCW %p: %08X %08X DAT:",
0750 act, ((int *) act)[0], ((int *) act)[1]);
0751 for (count = 0; count < 32 && count < act->count;
0752 count += sizeof(int))
0753 len += sprintf(page + len, " %08X",
0754 ((int *) (addr_t) act->cda)
0755 [(count>>2)]);
0756 len += sprintf(page + len, "\n");
0757 act++;
0758 }
0759 if (len > 0)
0760 printk(KERN_ERR "%s", page);
0761 free_page((unsigned long) page);
0762 }
0763
0764
0765
0766
0767 static void dasd_fba_setup_blk_queue(struct dasd_block *block)
0768 {
0769 unsigned int logical_block_size = block->bp_block;
0770 struct request_queue *q = block->request_queue;
0771 unsigned int max_bytes, max_discard_sectors;
0772 int max;
0773
0774 max = DASD_FBA_MAX_BLOCKS << block->s2b_shift;
0775 blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
0776 q->limits.max_dev_sectors = max;
0777 blk_queue_logical_block_size(q, logical_block_size);
0778 blk_queue_max_hw_sectors(q, max);
0779 blk_queue_max_segments(q, USHRT_MAX);
0780
0781 blk_queue_max_segment_size(q, PAGE_SIZE);
0782 blk_queue_segment_boundary(q, PAGE_SIZE - 1);
0783
0784 q->limits.discard_granularity = logical_block_size;
0785
0786
0787 max_bytes = USHRT_MAX * logical_block_size;
0788 max_bytes = ALIGN_DOWN(max_bytes, PAGE_SIZE);
0789 max_discard_sectors = max_bytes / logical_block_size;
0790
0791 blk_queue_max_discard_sectors(q, max_discard_sectors);
0792 blk_queue_max_write_zeroes_sectors(q, max_discard_sectors);
0793 }
0794
0795 static int dasd_fba_pe_handler(struct dasd_device *device,
0796 __u8 tbvpm, __u8 fcsecpm)
0797 {
0798 return dasd_generic_verify_path(device, tbvpm);
0799 }
0800
0801 static struct dasd_discipline dasd_fba_discipline = {
0802 .owner = THIS_MODULE,
0803 .name = "FBA ",
0804 .ebcname = "FBA ",
0805 .check_device = dasd_fba_check_characteristics,
0806 .do_analysis = dasd_fba_do_analysis,
0807 .pe_handler = dasd_fba_pe_handler,
0808 .setup_blk_queue = dasd_fba_setup_blk_queue,
0809 .fill_geometry = dasd_fba_fill_geometry,
0810 .start_IO = dasd_start_IO,
0811 .term_IO = dasd_term_IO,
0812 .handle_terminated_request = dasd_fba_handle_terminated_request,
0813 .erp_action = dasd_fba_erp_action,
0814 .erp_postaction = dasd_fba_erp_postaction,
0815 .check_for_device_change = dasd_fba_check_for_device_change,
0816 .build_cp = dasd_fba_build_cp,
0817 .free_cp = dasd_fba_free_cp,
0818 .dump_sense = dasd_fba_dump_sense,
0819 .dump_sense_dbf = dasd_fba_dump_sense_dbf,
0820 .fill_info = dasd_fba_fill_info,
0821 };
0822
0823 static int __init
0824 dasd_fba_init(void)
0825 {
0826 int ret;
0827
0828 ASCEBC(dasd_fba_discipline.ebcname, 4);
0829
0830 dasd_fba_zero_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
0831 if (!dasd_fba_zero_page)
0832 return -ENOMEM;
0833
0834 ret = ccw_driver_register(&dasd_fba_driver);
0835 if (!ret)
0836 wait_for_device_probe();
0837
0838 return ret;
0839 }
0840
0841 static void __exit
0842 dasd_fba_cleanup(void)
0843 {
0844 ccw_driver_unregister(&dasd_fba_driver);
0845 free_page((unsigned long)dasd_fba_zero_page);
0846 }
0847
0848 module_init(dasd_fba_init);
0849 module_exit(dasd_fba_cleanup);