aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block')
-rw-r--r--drivers/s390/block/dasd.c4
-rw-r--r--drivers/s390/block/dasd_eckd.c158
-rw-r--r--drivers/s390/block/dasd_eckd.h6
3 files changed, 122 insertions, 46 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index faa7d425cb9c..605f96f154a5 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -745,10 +745,6 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength,
745 char *data; 745 char *data;
746 int size; 746 int size;
747 747
748 /* Sanity checks */
749 BUG_ON(datasize > PAGE_SIZE ||
750 (cplength*sizeof(struct ccw1)) > PAGE_SIZE);
751
752 size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; 748 size = (sizeof(struct dasd_ccw_req) + 7L) & -8L;
753 if (cplength > 0) 749 if (cplength > 0)
754 size += cplength * sizeof(struct ccw1); 750 size += cplength * sizeof(struct ccw1);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index bf61274af3bb..549443af121c 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1105,6 +1105,37 @@ static void dasd_eckd_validate_server(struct dasd_device *device)
1105 "returned rc=%d", private->uid.ssid, rc); 1105 "returned rc=%d", private->uid.ssid, rc);
1106} 1106}
1107 1107
1108static u32 get_fcx_max_data(struct dasd_device *device)
1109{
1110#if defined(CONFIG_64BIT)
1111 int tpm, mdc;
1112 int fcx_in_css, fcx_in_gneq, fcx_in_features;
1113 struct dasd_eckd_private *private;
1114
1115 if (dasd_nofcx)
1116 return 0;
1117 /* is transport mode supported? */
1118 private = (struct dasd_eckd_private *) device->private;
1119 fcx_in_css = css_general_characteristics.fcx;
1120 fcx_in_gneq = private->gneq->reserved2[7] & 0x04;
1121 fcx_in_features = private->features.feature[40] & 0x80;
1122 tpm = fcx_in_css && fcx_in_gneq && fcx_in_features;
1123
1124 if (!tpm)
1125 return 0;
1126
1127 mdc = ccw_device_get_mdc(device->cdev, 0);
1128 if (mdc < 0) {
1129 dev_warn(&device->cdev->dev, "Detecting the maximum supported"
1130 " data size for zHPF requests failed\n");
1131 return 0;
1132 } else
1133 return mdc * FCX_MAX_DATA_FACTOR;
1134#else
1135 return 0;
1136#endif
1137}
1138
1108/* 1139/*
1109 * Check device characteristics. 1140 * Check device characteristics.
1110 * If the device is accessible using ECKD discipline, the device is enabled. 1141 * If the device is accessible using ECKD discipline, the device is enabled.
@@ -1223,6 +1254,8 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
1223 else 1254 else
1224 private->real_cyl = private->rdc_data.no_cyl; 1255 private->real_cyl = private->rdc_data.no_cyl;
1225 1256
1257 private->fcx_max_data = get_fcx_max_data(device);
1258
1226 readonly = dasd_device_is_ro(device); 1259 readonly = dasd_device_is_ro(device);
1227 if (readonly) 1260 if (readonly)
1228 set_bit(DASD_FLAG_DEVICE_RO, &device->flags); 1261 set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
@@ -2326,6 +2359,12 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
2326 struct tidaw *last_tidaw = NULL; 2359 struct tidaw *last_tidaw = NULL;
2327 int itcw_op; 2360 int itcw_op;
2328 size_t itcw_size; 2361 size_t itcw_size;
2362 u8 tidaw_flags;
2363 unsigned int seg_len, part_len, len_to_track_end;
2364 unsigned char new_track;
2365 sector_t recid, trkid;
2366 unsigned int offs;
2367 unsigned int count, count_to_trk_end;
2329 2368
2330 basedev = block->base; 2369 basedev = block->base;
2331 private = (struct dasd_eckd_private *) basedev->private; 2370 private = (struct dasd_eckd_private *) basedev->private;
@@ -2341,12 +2380,16 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
2341 /* trackbased I/O needs address all memory via TIDAWs, 2380 /* trackbased I/O needs address all memory via TIDAWs,
2342 * not just for 64 bit addresses. This allows us to map 2381 * not just for 64 bit addresses. This allows us to map
2343 * each segment directly to one tidaw. 2382 * each segment directly to one tidaw.
2383 * In the case of write requests, additional tidaws may
2384 * be needed when a segment crosses a track boundary.
2344 */ 2385 */
2345 trkcount = last_trk - first_trk + 1; 2386 trkcount = last_trk - first_trk + 1;
2346 ctidaw = 0; 2387 ctidaw = 0;
2347 rq_for_each_segment(bv, req, iter) { 2388 rq_for_each_segment(bv, req, iter) {
2348 ++ctidaw; 2389 ++ctidaw;
2349 } 2390 }
2391 if (rq_data_dir(req) == WRITE)
2392 ctidaw += (last_trk - first_trk);
2350 2393
2351 /* Allocate the ccw request. */ 2394 /* Allocate the ccw request. */
2352 itcw_size = itcw_calc_size(0, ctidaw, 0); 2395 itcw_size = itcw_calc_size(0, ctidaw, 0);
@@ -2354,15 +2397,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
2354 if (IS_ERR(cqr)) 2397 if (IS_ERR(cqr))
2355 return cqr; 2398 return cqr;
2356 2399
2357 cqr->cpmode = 1;
2358 cqr->startdev = startdev;
2359 cqr->memdev = startdev;
2360 cqr->block = block;
2361 cqr->expires = 100*HZ;
2362 cqr->buildclk = get_clock();
2363 cqr->status = DASD_CQR_FILLED;
2364 cqr->retries = 10;
2365
2366 /* transfer length factor: how many bytes to read from the last track */ 2400 /* transfer length factor: how many bytes to read from the last track */
2367 if (first_trk == last_trk) 2401 if (first_trk == last_trk)
2368 tlf = last_offs - first_offs + 1; 2402 tlf = last_offs - first_offs + 1;
@@ -2371,8 +2405,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
2371 tlf *= blksize; 2405 tlf *= blksize;
2372 2406
2373 itcw = itcw_init(cqr->data, itcw_size, itcw_op, 0, ctidaw, 0); 2407 itcw = itcw_init(cqr->data, itcw_size, itcw_op, 0, ctidaw, 0);
2408 if (IS_ERR(itcw)) {
2409 dasd_sfree_request(cqr, startdev);
2410 return ERR_PTR(-EINVAL);
2411 }
2374 cqr->cpaddr = itcw_get_tcw(itcw); 2412 cqr->cpaddr = itcw_get_tcw(itcw);
2375
2376 if (prepare_itcw(itcw, first_trk, last_trk, 2413 if (prepare_itcw(itcw, first_trk, last_trk,
2377 cmd, basedev, startdev, 2414 cmd, basedev, startdev,
2378 first_offs + 1, 2415 first_offs + 1,
@@ -2385,26 +2422,64 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
2385 dasd_sfree_request(cqr, startdev); 2422 dasd_sfree_request(cqr, startdev);
2386 return ERR_PTR(-EAGAIN); 2423 return ERR_PTR(-EAGAIN);
2387 } 2424 }
2388
2389 /* 2425 /*
2390 * A tidaw can address 4k of memory, but must not cross page boundaries 2426 * A tidaw can address 4k of memory, but must not cross page boundaries
2391 * We can let the block layer handle this by setting 2427 * We can let the block layer handle this by setting
2392 * blk_queue_segment_boundary to page boundaries and 2428 * blk_queue_segment_boundary to page boundaries and
2393 * blk_max_segment_size to page size when setting up the request queue. 2429 * blk_max_segment_size to page size when setting up the request queue.
2430 * For write requests, a TIDAW must not cross track boundaries, because
2431 * we have to set the CBC flag on the last tidaw for each track.
2394 */ 2432 */
2395 rq_for_each_segment(bv, req, iter) { 2433 if (rq_data_dir(req) == WRITE) {
2396 dst = page_address(bv->bv_page) + bv->bv_offset; 2434 new_track = 1;
2397 last_tidaw = itcw_add_tidaw(itcw, 0x00, dst, bv->bv_len); 2435 recid = first_rec;
2398 if (IS_ERR(last_tidaw)) 2436 rq_for_each_segment(bv, req, iter) {
2399 return (struct dasd_ccw_req *)last_tidaw; 2437 dst = page_address(bv->bv_page) + bv->bv_offset;
2438 seg_len = bv->bv_len;
2439 while (seg_len) {
2440 if (new_track) {
2441 trkid = recid;
2442 offs = sector_div(trkid, blk_per_trk);
2443 count_to_trk_end = blk_per_trk - offs;
2444 count = min((last_rec - recid + 1),
2445 (sector_t)count_to_trk_end);
2446 len_to_track_end = count * blksize;
2447 recid += count;
2448 new_track = 0;
2449 }
2450 part_len = min(seg_len, len_to_track_end);
2451 seg_len -= part_len;
2452 len_to_track_end -= part_len;
2453 /* We need to end the tidaw at track end */
2454 if (!len_to_track_end) {
2455 new_track = 1;
2456 tidaw_flags = TIDAW_FLAGS_INSERT_CBC;
2457 } else
2458 tidaw_flags = 0;
2459 last_tidaw = itcw_add_tidaw(itcw, tidaw_flags,
2460 dst, part_len);
2461 if (IS_ERR(last_tidaw))
2462 return ERR_PTR(-EINVAL);
2463 dst += part_len;
2464 }
2465 }
2466 } else {
2467 rq_for_each_segment(bv, req, iter) {
2468 dst = page_address(bv->bv_page) + bv->bv_offset;
2469 last_tidaw = itcw_add_tidaw(itcw, 0x00,
2470 dst, bv->bv_len);
2471 if (IS_ERR(last_tidaw))
2472 return ERR_PTR(-EINVAL);
2473 }
2400 } 2474 }
2401 2475 last_tidaw->flags |= TIDAW_FLAGS_LAST;
2402 last_tidaw->flags |= 0x80; 2476 last_tidaw->flags &= ~TIDAW_FLAGS_INSERT_CBC;
2403 itcw_finalize(itcw); 2477 itcw_finalize(itcw);
2404 2478
2405 if (blk_noretry_request(req) || 2479 if (blk_noretry_request(req) ||
2406 block->base->features & DASD_FEATURE_FAILFAST) 2480 block->base->features & DASD_FEATURE_FAILFAST)
2407 set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); 2481 set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
2482 cqr->cpmode = 1;
2408 cqr->startdev = startdev; 2483 cqr->startdev = startdev;
2409 cqr->memdev = startdev; 2484 cqr->memdev = startdev;
2410 cqr->block = block; 2485 cqr->block = block;
@@ -2420,11 +2495,9 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
2420 struct dasd_block *block, 2495 struct dasd_block *block,
2421 struct request *req) 2496 struct request *req)
2422{ 2497{
2423 int tpm, cmdrtd, cmdwtd; 2498 int cmdrtd, cmdwtd;
2424 int use_prefix; 2499 int use_prefix;
2425#if defined(CONFIG_64BIT) 2500 int fcx_multitrack;
2426 int fcx_in_css, fcx_in_gneq, fcx_in_features;
2427#endif
2428 struct dasd_eckd_private *private; 2501 struct dasd_eckd_private *private;
2429 struct dasd_device *basedev; 2502 struct dasd_device *basedev;
2430 sector_t first_rec, last_rec; 2503 sector_t first_rec, last_rec;
@@ -2432,6 +2505,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
2432 unsigned int first_offs, last_offs; 2505 unsigned int first_offs, last_offs;
2433 unsigned int blk_per_trk, blksize; 2506 unsigned int blk_per_trk, blksize;
2434 int cdlspecial; 2507 int cdlspecial;
2508 unsigned int data_size;
2435 struct dasd_ccw_req *cqr; 2509 struct dasd_ccw_req *cqr;
2436 2510
2437 basedev = block->base; 2511 basedev = block->base;
@@ -2450,15 +2524,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
2450 last_offs = sector_div(last_trk, blk_per_trk); 2524 last_offs = sector_div(last_trk, blk_per_trk);
2451 cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); 2525 cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk);
2452 2526
2453 /* is transport mode supported? */ 2527 fcx_multitrack = private->features.feature[40] & 0x20;
2454#if defined(CONFIG_64BIT) 2528 data_size = blk_rq_bytes(req);
2455 fcx_in_css = css_general_characteristics.fcx; 2529 /* tpm write request add CBC data on each track boundary */
2456 fcx_in_gneq = private->gneq->reserved2[7] & 0x04; 2530 if (rq_data_dir(req) == WRITE)
2457 fcx_in_features = private->features.feature[40] & 0x80; 2531 data_size += (last_trk - first_trk) * 4;
2458 tpm = fcx_in_css && fcx_in_gneq && fcx_in_features;
2459#else
2460 tpm = 0;
2461#endif
2462 2532
2463 /* is read track data and write track data in command mode supported? */ 2533 /* is read track data and write track data in command mode supported? */
2464 cmdrtd = private->features.feature[9] & 0x20; 2534 cmdrtd = private->features.feature[9] & 0x20;
@@ -2468,13 +2538,15 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
2468 cqr = NULL; 2538 cqr = NULL;
2469 if (cdlspecial || dasd_page_cache) { 2539 if (cdlspecial || dasd_page_cache) {
2470 /* do nothing, just fall through to the cmd mode single case */ 2540 /* do nothing, just fall through to the cmd mode single case */
2471 } else if (!dasd_nofcx && tpm && (first_trk == last_trk)) { 2541 } else if ((data_size <= private->fcx_max_data)
2542 && (fcx_multitrack || (first_trk == last_trk))) {
2472 cqr = dasd_eckd_build_cp_tpm_track(startdev, block, req, 2543 cqr = dasd_eckd_build_cp_tpm_track(startdev, block, req,
2473 first_rec, last_rec, 2544 first_rec, last_rec,
2474 first_trk, last_trk, 2545 first_trk, last_trk,
2475 first_offs, last_offs, 2546 first_offs, last_offs,
2476 blk_per_trk, blksize); 2547 blk_per_trk, blksize);
2477 if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) 2548 if (IS_ERR(cqr) && (PTR_ERR(cqr) != -EAGAIN) &&
2549 (PTR_ERR(cqr) != -ENOMEM))
2478 cqr = NULL; 2550 cqr = NULL;
2479 } else if (use_prefix && 2551 } else if (use_prefix &&
2480 (((rq_data_dir(req) == READ) && cmdrtd) || 2552 (((rq_data_dir(req) == READ) && cmdrtd) ||
@@ -2484,7 +2556,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
2484 first_trk, last_trk, 2556 first_trk, last_trk,
2485 first_offs, last_offs, 2557 first_offs, last_offs,
2486 blk_per_trk, blksize); 2558 blk_per_trk, blksize);
2487 if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) 2559 if (IS_ERR(cqr) && (PTR_ERR(cqr) != -EAGAIN) &&
2560 (PTR_ERR(cqr) != -ENOMEM))
2488 cqr = NULL; 2561 cqr = NULL;
2489 } 2562 }
2490 if (!cqr) 2563 if (!cqr)
@@ -3279,10 +3352,8 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
3279{ 3352{
3280 char *page; 3353 char *page;
3281 int len, sl, sct, residual; 3354 int len, sl, sct, residual;
3282
3283 struct tsb *tsb; 3355 struct tsb *tsb;
3284 u8 *sense; 3356 u8 *sense, *rcq;
3285
3286 3357
3287 page = (char *) get_zeroed_page(GFP_ATOMIC); 3358 page = (char *) get_zeroed_page(GFP_ATOMIC);
3288 if (page == NULL) { 3359 if (page == NULL) {
@@ -3348,12 +3419,15 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
3348 case 2: /* ts_ddpc */ 3419 case 2: /* ts_ddpc */
3349 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 3420 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
3350 " tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc); 3421 " tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc);
3351 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 3422 for (sl = 0; sl < 2; sl++) {
3352 " tsb->tsa.ddpc.rcq: "); 3423 len += sprintf(page + len,
3353 for (sl = 0; sl < 16; sl++) { 3424 KERN_ERR PRINTK_HEADER
3425 " tsb->tsa.ddpc.rcq %2d-%2d: ",
3426 (8 * sl), ((8 * sl) + 7));
3427 rcq = tsb->tsa.ddpc.rcq;
3354 for (sct = 0; sct < 8; sct++) { 3428 for (sct = 0; sct < 8; sct++) {
3355 len += sprintf(page + len, " %02x", 3429 len += sprintf(page + len, " %02x",
3356 tsb->tsa.ddpc.rcq[sl]); 3430 rcq[8 * sl + sct]);
3357 } 3431 }
3358 len += sprintf(page + len, "\n"); 3432 len += sprintf(page + len, "\n");
3359 } 3433 }
@@ -3573,7 +3647,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
3573 .owner = THIS_MODULE, 3647 .owner = THIS_MODULE,
3574 .name = "ECKD", 3648 .name = "ECKD",
3575 .ebcname = "ECKD", 3649 .ebcname = "ECKD",
3576 .max_blocks = 240, 3650 .max_blocks = 190,
3577 .check_device = dasd_eckd_check_characteristics, 3651 .check_device = dasd_eckd_check_characteristics,
3578 .uncheck_device = dasd_eckd_uncheck_device, 3652 .uncheck_device = dasd_eckd_uncheck_device,
3579 .do_analysis = dasd_eckd_do_analysis, 3653 .do_analysis = dasd_eckd_do_analysis,
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 12097c24f2f5..2150aed541be 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -57,6 +57,10 @@
57 */ 57 */
58#define LV_COMPAT_CYL 0xFFFE 58#define LV_COMPAT_CYL 0xFFFE
59 59
60
61#define FCX_MAX_DATA_FACTOR 65536
62
63
60/***************************************************************************** 64/*****************************************************************************
61 * SECTION: Type Definitions 65 * SECTION: Type Definitions
62 ****************************************************************************/ 66 ****************************************************************************/
@@ -455,6 +459,8 @@ struct dasd_eckd_private {
455 struct alias_pav_group *pavgroup; 459 struct alias_pav_group *pavgroup;
456 struct alias_lcu *lcu; 460 struct alias_lcu *lcu;
457 int count; 461 int count;
462
463 u32 fcx_max_data;
458}; 464};
459 465
460 466