diff options
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 972 |
1 files changed, 889 insertions, 83 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 69f93e626fd3..1e4c89b8b304 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -27,9 +27,12 @@ | |||
27 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
28 | #include <asm/cio.h> | 28 | #include <asm/cio.h> |
29 | #include <asm/ccwdev.h> | 29 | #include <asm/ccwdev.h> |
30 | #include <asm/itcw.h> | ||
30 | 31 | ||
31 | #include "dasd_int.h" | 32 | #include "dasd_int.h" |
32 | #include "dasd_eckd.h" | 33 | #include "dasd_eckd.h" |
34 | #include "../cio/chsc.h" | ||
35 | |||
33 | 36 | ||
34 | #ifdef PRINTK_HEADER | 37 | #ifdef PRINTK_HEADER |
35 | #undef PRINTK_HEADER | 38 | #undef PRINTK_HEADER |
@@ -245,7 +248,8 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, | |||
245 | rc = check_XRC (ccw, data, device); | 248 | rc = check_XRC (ccw, data, device); |
246 | break; | 249 | break; |
247 | default: | 250 | default: |
248 | DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); | 251 | DBF_DEV_EVENT(DBF_ERR, device, |
252 | "PFX LRE unknown opcode 0x%x", cmd); | ||
249 | break; | 253 | break; |
250 | } | 254 | } |
251 | 255 | ||
@@ -289,30 +293,145 @@ static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, | |||
289 | return 0; | 293 | return 0; |
290 | 294 | ||
291 | /* switch on System Time Stamp - needed for XRC Support */ | 295 | /* switch on System Time Stamp - needed for XRC Support */ |
292 | pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid' */ | 296 | pfxdata->define_extent.ga_extended |= 0x08; /* 'Time Stamp Valid' */ |
293 | pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */ | 297 | pfxdata->define_extent.ga_extended |= 0x02; /* 'Extended Parameter' */ |
294 | pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */ | 298 | pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */ |
295 | 299 | ||
296 | rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time); | 300 | rc = get_sync_clock(&pfxdata->define_extent.ep_sys_time); |
297 | /* Ignore return code if sync clock is switched off. */ | 301 | /* Ignore return code if sync clock is switched off. */ |
298 | if (rc == -ENOSYS || rc == -EACCES) | 302 | if (rc == -ENOSYS || rc == -EACCES) |
299 | rc = 0; | 303 | rc = 0; |
300 | return rc; | 304 | return rc; |
301 | } | 305 | } |
302 | 306 | ||
303 | static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | 307 | static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk, |
304 | unsigned int trk, unsigned int totrk, int cmd, | 308 | unsigned int rec_on_trk, int count, int cmd, |
305 | struct dasd_device *basedev, struct dasd_device *startdev) | 309 | struct dasd_device *device, unsigned int reclen, |
310 | unsigned int tlf) | ||
311 | { | ||
312 | struct dasd_eckd_private *private; | ||
313 | int sector; | ||
314 | int dn, d; | ||
315 | |||
316 | private = (struct dasd_eckd_private *) device->private; | ||
317 | |||
318 | memset(data, 0, sizeof(*data)); | ||
319 | sector = 0; | ||
320 | if (rec_on_trk) { | ||
321 | switch (private->rdc_data.dev_type) { | ||
322 | case 0x3390: | ||
323 | dn = ceil_quot(reclen + 6, 232); | ||
324 | d = 9 + ceil_quot(reclen + 6 * (dn + 1), 34); | ||
325 | sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8; | ||
326 | break; | ||
327 | case 0x3380: | ||
328 | d = 7 + ceil_quot(reclen + 12, 32); | ||
329 | sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7; | ||
330 | break; | ||
331 | } | ||
332 | } | ||
333 | data->sector = sector; | ||
334 | /* note: meaning of count depends on the operation | ||
335 | * for record based I/O it's the number of records, but for | ||
336 | * track based I/O it's the number of tracks | ||
337 | */ | ||
338 | data->count = count; | ||
339 | switch (cmd) { | ||
340 | case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: | ||
341 | data->operation.orientation = 0x3; | ||
342 | data->operation.operation = 0x03; | ||
343 | break; | ||
344 | case DASD_ECKD_CCW_READ_HOME_ADDRESS: | ||
345 | data->operation.orientation = 0x3; | ||
346 | data->operation.operation = 0x16; | ||
347 | break; | ||
348 | case DASD_ECKD_CCW_WRITE_RECORD_ZERO: | ||
349 | data->operation.orientation = 0x1; | ||
350 | data->operation.operation = 0x03; | ||
351 | data->count++; | ||
352 | break; | ||
353 | case DASD_ECKD_CCW_READ_RECORD_ZERO: | ||
354 | data->operation.orientation = 0x3; | ||
355 | data->operation.operation = 0x16; | ||
356 | data->count++; | ||
357 | break; | ||
358 | case DASD_ECKD_CCW_WRITE: | ||
359 | case DASD_ECKD_CCW_WRITE_MT: | ||
360 | case DASD_ECKD_CCW_WRITE_KD: | ||
361 | case DASD_ECKD_CCW_WRITE_KD_MT: | ||
362 | data->auxiliary.length_valid = 0x1; | ||
363 | data->length = reclen; | ||
364 | data->operation.operation = 0x01; | ||
365 | break; | ||
366 | case DASD_ECKD_CCW_WRITE_CKD: | ||
367 | case DASD_ECKD_CCW_WRITE_CKD_MT: | ||
368 | data->auxiliary.length_valid = 0x1; | ||
369 | data->length = reclen; | ||
370 | data->operation.operation = 0x03; | ||
371 | break; | ||
372 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: | ||
373 | data->auxiliary.length_valid = 0x1; | ||
374 | data->length = reclen; /* not tlf, as one might think */ | ||
375 | data->operation.operation = 0x3F; | ||
376 | data->extended_operation = 0x23; | ||
377 | break; | ||
378 | case DASD_ECKD_CCW_READ: | ||
379 | case DASD_ECKD_CCW_READ_MT: | ||
380 | case DASD_ECKD_CCW_READ_KD: | ||
381 | case DASD_ECKD_CCW_READ_KD_MT: | ||
382 | data->auxiliary.length_valid = 0x1; | ||
383 | data->length = reclen; | ||
384 | data->operation.operation = 0x06; | ||
385 | break; | ||
386 | case DASD_ECKD_CCW_READ_CKD: | ||
387 | case DASD_ECKD_CCW_READ_CKD_MT: | ||
388 | data->auxiliary.length_valid = 0x1; | ||
389 | data->length = reclen; | ||
390 | data->operation.operation = 0x16; | ||
391 | break; | ||
392 | case DASD_ECKD_CCW_READ_COUNT: | ||
393 | data->operation.operation = 0x06; | ||
394 | break; | ||
395 | case DASD_ECKD_CCW_READ_TRACK_DATA: | ||
396 | data->auxiliary.length_valid = 0x1; | ||
397 | data->length = tlf; | ||
398 | data->operation.operation = 0x0C; | ||
399 | break; | ||
400 | case DASD_ECKD_CCW_ERASE: | ||
401 | data->length = reclen; | ||
402 | data->auxiliary.length_valid = 0x1; | ||
403 | data->operation.operation = 0x0b; | ||
404 | break; | ||
405 | default: | ||
406 | DBF_DEV_EVENT(DBF_ERR, device, | ||
407 | "fill LRE unknown opcode 0x%x", cmd); | ||
408 | BUG(); | ||
409 | } | ||
410 | set_ch_t(&data->seek_addr, | ||
411 | trk / private->rdc_data.trk_per_cyl, | ||
412 | trk % private->rdc_data.trk_per_cyl); | ||
413 | data->search_arg.cyl = data->seek_addr.cyl; | ||
414 | data->search_arg.head = data->seek_addr.head; | ||
415 | data->search_arg.record = rec_on_trk; | ||
416 | } | ||
417 | |||
418 | static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | ||
419 | unsigned int trk, unsigned int totrk, int cmd, | ||
420 | struct dasd_device *basedev, struct dasd_device *startdev, | ||
421 | unsigned char format, unsigned int rec_on_trk, int count, | ||
422 | unsigned int blksize, unsigned int tlf) | ||
306 | { | 423 | { |
307 | struct dasd_eckd_private *basepriv, *startpriv; | 424 | struct dasd_eckd_private *basepriv, *startpriv; |
308 | struct DE_eckd_data *data; | 425 | struct DE_eckd_data *dedata; |
426 | struct LRE_eckd_data *lredata; | ||
309 | u32 begcyl, endcyl; | 427 | u32 begcyl, endcyl; |
310 | u16 heads, beghead, endhead; | 428 | u16 heads, beghead, endhead; |
311 | int rc = 0; | 429 | int rc = 0; |
312 | 430 | ||
313 | basepriv = (struct dasd_eckd_private *) basedev->private; | 431 | basepriv = (struct dasd_eckd_private *) basedev->private; |
314 | startpriv = (struct dasd_eckd_private *) startdev->private; | 432 | startpriv = (struct dasd_eckd_private *) startdev->private; |
315 | data = &pfxdata->define_extend; | 433 | dedata = &pfxdata->define_extent; |
434 | lredata = &pfxdata->locate_record; | ||
316 | 435 | ||
317 | ccw->cmd_code = DASD_ECKD_CCW_PFX; | 436 | ccw->cmd_code = DASD_ECKD_CCW_PFX; |
318 | ccw->flags = 0; | 437 | ccw->flags = 0; |
@@ -321,10 +440,16 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
321 | 440 | ||
322 | memset(pfxdata, 0, sizeof(*pfxdata)); | 441 | memset(pfxdata, 0, sizeof(*pfxdata)); |
323 | /* prefix data */ | 442 | /* prefix data */ |
324 | pfxdata->format = 0; | 443 | if (format > 1) { |
444 | DBF_DEV_EVENT(DBF_ERR, basedev, | ||
445 | "PFX LRE unknown format 0x%x", format); | ||
446 | BUG(); | ||
447 | return -EINVAL; | ||
448 | } | ||
449 | pfxdata->format = format; | ||
325 | pfxdata->base_address = basepriv->ned->unit_addr; | 450 | pfxdata->base_address = basepriv->ned->unit_addr; |
326 | pfxdata->base_lss = basepriv->ned->ID; | 451 | pfxdata->base_lss = basepriv->ned->ID; |
327 | pfxdata->validity.define_extend = 1; | 452 | pfxdata->validity.define_extent = 1; |
328 | 453 | ||
329 | /* private uid is kept up to date, conf_data may be outdated */ | 454 | /* private uid is kept up to date, conf_data may be outdated */ |
330 | if (startpriv->uid.type != UA_BASE_DEVICE) { | 455 | if (startpriv->uid.type != UA_BASE_DEVICE) { |
@@ -344,42 +469,55 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
344 | case DASD_ECKD_CCW_READ_KD: | 469 | case DASD_ECKD_CCW_READ_KD: |
345 | case DASD_ECKD_CCW_READ_KD_MT: | 470 | case DASD_ECKD_CCW_READ_KD_MT: |
346 | case DASD_ECKD_CCW_READ_COUNT: | 471 | case DASD_ECKD_CCW_READ_COUNT: |
347 | data->mask.perm = 0x1; | 472 | dedata->mask.perm = 0x1; |
348 | data->attributes.operation = basepriv->attrib.operation; | 473 | dedata->attributes.operation = basepriv->attrib.operation; |
474 | break; | ||
475 | case DASD_ECKD_CCW_READ_TRACK_DATA: | ||
476 | dedata->mask.perm = 0x1; | ||
477 | dedata->attributes.operation = basepriv->attrib.operation; | ||
478 | dedata->blk_size = 0; | ||
349 | break; | 479 | break; |
350 | case DASD_ECKD_CCW_WRITE: | 480 | case DASD_ECKD_CCW_WRITE: |
351 | case DASD_ECKD_CCW_WRITE_MT: | 481 | case DASD_ECKD_CCW_WRITE_MT: |
352 | case DASD_ECKD_CCW_WRITE_KD: | 482 | case DASD_ECKD_CCW_WRITE_KD: |
353 | case DASD_ECKD_CCW_WRITE_KD_MT: | 483 | case DASD_ECKD_CCW_WRITE_KD_MT: |
354 | data->mask.perm = 0x02; | 484 | dedata->mask.perm = 0x02; |
355 | data->attributes.operation = basepriv->attrib.operation; | 485 | dedata->attributes.operation = basepriv->attrib.operation; |
356 | rc = check_XRC_on_prefix(pfxdata, basedev); | 486 | rc = check_XRC_on_prefix(pfxdata, basedev); |
357 | break; | 487 | break; |
358 | case DASD_ECKD_CCW_WRITE_CKD: | 488 | case DASD_ECKD_CCW_WRITE_CKD: |
359 | case DASD_ECKD_CCW_WRITE_CKD_MT: | 489 | case DASD_ECKD_CCW_WRITE_CKD_MT: |
360 | data->attributes.operation = DASD_BYPASS_CACHE; | 490 | dedata->attributes.operation = DASD_BYPASS_CACHE; |
361 | rc = check_XRC_on_prefix(pfxdata, basedev); | 491 | rc = check_XRC_on_prefix(pfxdata, basedev); |
362 | break; | 492 | break; |
363 | case DASD_ECKD_CCW_ERASE: | 493 | case DASD_ECKD_CCW_ERASE: |
364 | case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: | 494 | case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: |
365 | case DASD_ECKD_CCW_WRITE_RECORD_ZERO: | 495 | case DASD_ECKD_CCW_WRITE_RECORD_ZERO: |
366 | data->mask.perm = 0x3; | 496 | dedata->mask.perm = 0x3; |
367 | data->mask.auth = 0x1; | 497 | dedata->mask.auth = 0x1; |
368 | data->attributes.operation = DASD_BYPASS_CACHE; | 498 | dedata->attributes.operation = DASD_BYPASS_CACHE; |
369 | rc = check_XRC_on_prefix(pfxdata, basedev); | 499 | rc = check_XRC_on_prefix(pfxdata, basedev); |
370 | break; | 500 | break; |
371 | default: | 501 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: |
372 | DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd); | 502 | dedata->mask.perm = 0x02; |
503 | dedata->attributes.operation = basepriv->attrib.operation; | ||
504 | dedata->blk_size = blksize; | ||
505 | rc = check_XRC_on_prefix(pfxdata, basedev); | ||
373 | break; | 506 | break; |
507 | default: | ||
508 | DBF_DEV_EVENT(DBF_ERR, basedev, | ||
509 | "PFX LRE unknown opcode 0x%x", cmd); | ||
510 | BUG(); | ||
511 | return -EINVAL; | ||
374 | } | 512 | } |
375 | 513 | ||
376 | data->attributes.mode = 0x3; /* ECKD */ | 514 | dedata->attributes.mode = 0x3; /* ECKD */ |
377 | 515 | ||
378 | if ((basepriv->rdc_data.cu_type == 0x2105 || | 516 | if ((basepriv->rdc_data.cu_type == 0x2105 || |
379 | basepriv->rdc_data.cu_type == 0x2107 || | 517 | basepriv->rdc_data.cu_type == 0x2107 || |
380 | basepriv->rdc_data.cu_type == 0x1750) | 518 | basepriv->rdc_data.cu_type == 0x1750) |
381 | && !(basepriv->uses_cdl && trk < 2)) | 519 | && !(basepriv->uses_cdl && trk < 2)) |
382 | data->ga_extended |= 0x40; /* Regular Data Format Mode */ | 520 | dedata->ga_extended |= 0x40; /* Regular Data Format Mode */ |
383 | 521 | ||
384 | heads = basepriv->rdc_data.trk_per_cyl; | 522 | heads = basepriv->rdc_data.trk_per_cyl; |
385 | begcyl = trk / heads; | 523 | begcyl = trk / heads; |
@@ -388,8 +526,8 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
388 | endhead = totrk % heads; | 526 | endhead = totrk % heads; |
389 | 527 | ||
390 | /* check for sequential prestage - enhance cylinder range */ | 528 | /* check for sequential prestage - enhance cylinder range */ |
391 | if (data->attributes.operation == DASD_SEQ_PRESTAGE || | 529 | if (dedata->attributes.operation == DASD_SEQ_PRESTAGE || |
392 | data->attributes.operation == DASD_SEQ_ACCESS) { | 530 | dedata->attributes.operation == DASD_SEQ_ACCESS) { |
393 | 531 | ||
394 | if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl) | 532 | if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl) |
395 | endcyl += basepriv->attrib.nr_cyl; | 533 | endcyl += basepriv->attrib.nr_cyl; |
@@ -397,11 +535,25 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | |||
397 | endcyl = (basepriv->real_cyl - 1); | 535 | endcyl = (basepriv->real_cyl - 1); |
398 | } | 536 | } |
399 | 537 | ||
400 | set_ch_t(&data->beg_ext, begcyl, beghead); | 538 | set_ch_t(&dedata->beg_ext, begcyl, beghead); |
401 | set_ch_t(&data->end_ext, endcyl, endhead); | 539 | set_ch_t(&dedata->end_ext, endcyl, endhead); |
540 | |||
541 | if (format == 1) { | ||
542 | fill_LRE_data(lredata, trk, rec_on_trk, count, cmd, | ||
543 | basedev, blksize, tlf); | ||
544 | } | ||
545 | |||
402 | return rc; | 546 | return rc; |
403 | } | 547 | } |
404 | 548 | ||
549 | static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, | ||
550 | unsigned int trk, unsigned int totrk, int cmd, | ||
551 | struct dasd_device *basedev, struct dasd_device *startdev) | ||
552 | { | ||
553 | return prefix_LRE(ccw, pfxdata, trk, totrk, cmd, basedev, startdev, | ||
554 | 0, 0, 0, 0, 0); | ||
555 | } | ||
556 | |||
405 | static void | 557 | static void |
406 | locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk, | 558 | locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk, |
407 | unsigned int rec_on_trk, int no_rec, int cmd, | 559 | unsigned int rec_on_trk, int no_rec, int cmd, |
@@ -845,7 +997,8 @@ static int dasd_eckd_read_features(struct dasd_device *device) | |||
845 | /* | 997 | /* |
846 | * Build CP for Perform Subsystem Function - SSC. | 998 | * Build CP for Perform Subsystem Function - SSC. |
847 | */ | 999 | */ |
848 | static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device) | 1000 | static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, |
1001 | int enable_pav) | ||
849 | { | 1002 | { |
850 | struct dasd_ccw_req *cqr; | 1003 | struct dasd_ccw_req *cqr; |
851 | struct dasd_psf_ssc_data *psf_ssc_data; | 1004 | struct dasd_psf_ssc_data *psf_ssc_data; |
@@ -862,9 +1015,11 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device) | |||
862 | } | 1015 | } |
863 | psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data; | 1016 | psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data; |
864 | psf_ssc_data->order = PSF_ORDER_SSC; | 1017 | psf_ssc_data->order = PSF_ORDER_SSC; |
865 | psf_ssc_data->suborder = 0x88; | 1018 | psf_ssc_data->suborder = 0x40; |
866 | psf_ssc_data->reserved[0] = 0x88; | 1019 | if (enable_pav) { |
867 | 1020 | psf_ssc_data->suborder |= 0x88; | |
1021 | psf_ssc_data->reserved[0] = 0x88; | ||
1022 | } | ||
868 | ccw = cqr->cpaddr; | 1023 | ccw = cqr->cpaddr; |
869 | ccw->cmd_code = DASD_ECKD_CCW_PSF; | 1024 | ccw->cmd_code = DASD_ECKD_CCW_PSF; |
870 | ccw->cda = (__u32)(addr_t)psf_ssc_data; | 1025 | ccw->cda = (__u32)(addr_t)psf_ssc_data; |
@@ -885,12 +1040,12 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device) | |||
885 | * call might change behaviour of DASD devices. | 1040 | * call might change behaviour of DASD devices. |
886 | */ | 1041 | */ |
887 | static int | 1042 | static int |
888 | dasd_eckd_psf_ssc(struct dasd_device *device) | 1043 | dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) |
889 | { | 1044 | { |
890 | struct dasd_ccw_req *cqr; | 1045 | struct dasd_ccw_req *cqr; |
891 | int rc; | 1046 | int rc; |
892 | 1047 | ||
893 | cqr = dasd_eckd_build_psf_ssc(device); | 1048 | cqr = dasd_eckd_build_psf_ssc(device, enable_pav); |
894 | if (IS_ERR(cqr)) | 1049 | if (IS_ERR(cqr)) |
895 | return PTR_ERR(cqr); | 1050 | return PTR_ERR(cqr); |
896 | 1051 | ||
@@ -909,12 +1064,13 @@ static int dasd_eckd_validate_server(struct dasd_device *device) | |||
909 | { | 1064 | { |
910 | int rc; | 1065 | int rc; |
911 | struct dasd_eckd_private *private; | 1066 | struct dasd_eckd_private *private; |
1067 | int enable_pav; | ||
912 | 1068 | ||
913 | /* Currently PAV is the only reason to 'validate' server on LPAR */ | ||
914 | if (dasd_nopav || MACHINE_IS_VM) | 1069 | if (dasd_nopav || MACHINE_IS_VM) |
915 | return 0; | 1070 | enable_pav = 0; |
916 | 1071 | else | |
917 | rc = dasd_eckd_psf_ssc(device); | 1072 | enable_pav = 1; |
1073 | rc = dasd_eckd_psf_ssc(device, enable_pav); | ||
918 | /* may be requested feature is not available on server, | 1074 | /* may be requested feature is not available on server, |
919 | * therefore just report error and go ahead */ | 1075 | * therefore just report error and go ahead */ |
920 | private = (struct dasd_eckd_private *) device->private; | 1076 | private = (struct dasd_eckd_private *) device->private; |
@@ -1504,40 +1660,41 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, | |||
1504 | struct irb *irb) | 1660 | struct irb *irb) |
1505 | { | 1661 | { |
1506 | char mask; | 1662 | char mask; |
1663 | char *sense = NULL; | ||
1507 | 1664 | ||
1508 | /* first of all check for state change pending interrupt */ | 1665 | /* first of all check for state change pending interrupt */ |
1509 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; | 1666 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; |
1510 | if ((irb->scsw.cmd.dstat & mask) == mask) { | 1667 | if ((scsw_dstat(&irb->scsw) & mask) == mask) { |
1511 | dasd_generic_handle_state_change(device); | 1668 | dasd_generic_handle_state_change(device); |
1512 | return; | 1669 | return; |
1513 | } | 1670 | } |
1514 | 1671 | ||
1515 | /* summary unit check */ | 1672 | /* summary unit check */ |
1516 | if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && | 1673 | if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && |
1517 | (irb->ecw[7] == 0x0D)) { | 1674 | (irb->ecw[7] == 0x0D)) { |
1518 | dasd_alias_handle_summary_unit_check(device, irb); | 1675 | dasd_alias_handle_summary_unit_check(device, irb); |
1519 | return; | 1676 | return; |
1520 | } | 1677 | } |
1521 | 1678 | ||
1522 | 1679 | sense = dasd_get_sense(irb); | |
1523 | /* service information message SIM */ | 1680 | /* service information message SIM */ |
1524 | if (irb->esw.esw0.erw.cons && !(irb->ecw[27] & DASD_SENSE_BIT_0) && | 1681 | if (sense && !(sense[27] & DASD_SENSE_BIT_0) && |
1525 | ((irb->ecw[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { | 1682 | ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { |
1526 | dasd_3990_erp_handle_sim(device, irb->ecw); | 1683 | dasd_3990_erp_handle_sim(device, sense); |
1527 | dasd_schedule_device_bh(device); | 1684 | dasd_schedule_device_bh(device); |
1528 | return; | 1685 | return; |
1529 | } | 1686 | } |
1530 | 1687 | ||
1531 | if ((irb->scsw.cmd.cc == 1) && | 1688 | if ((scsw_cc(&irb->scsw) == 1) && |
1532 | (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && | 1689 | (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && |
1533 | (irb->scsw.cmd.actl & SCSW_ACTL_START_PEND) && | 1690 | (scsw_actl(&irb->scsw) & SCSW_ACTL_START_PEND) && |
1534 | (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND)) { | 1691 | (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) { |
1535 | /* fake irb do nothing, they are handled elsewhere */ | 1692 | /* fake irb do nothing, they are handled elsewhere */ |
1536 | dasd_schedule_device_bh(device); | 1693 | dasd_schedule_device_bh(device); |
1537 | return; | 1694 | return; |
1538 | } | 1695 | } |
1539 | 1696 | ||
1540 | if (!(irb->esw.esw0.erw.cons)) { | 1697 | if (!sense) { |
1541 | /* just report other unsolicited interrupts */ | 1698 | /* just report other unsolicited interrupts */ |
1542 | DEV_MESSAGE(KERN_ERR, device, "%s", | 1699 | DEV_MESSAGE(KERN_ERR, device, "%s", |
1543 | "unsolicited interrupt received"); | 1700 | "unsolicited interrupt received"); |
@@ -1552,9 +1709,19 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, | |||
1552 | return; | 1709 | return; |
1553 | }; | 1710 | }; |
1554 | 1711 | ||
1555 | static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | 1712 | |
1713 | static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( | ||
1714 | struct dasd_device *startdev, | ||
1556 | struct dasd_block *block, | 1715 | struct dasd_block *block, |
1557 | struct request *req) | 1716 | struct request *req, |
1717 | sector_t first_rec, | ||
1718 | sector_t last_rec, | ||
1719 | sector_t first_trk, | ||
1720 | sector_t last_trk, | ||
1721 | unsigned int first_offs, | ||
1722 | unsigned int last_offs, | ||
1723 | unsigned int blk_per_trk, | ||
1724 | unsigned int blksize) | ||
1558 | { | 1725 | { |
1559 | struct dasd_eckd_private *private; | 1726 | struct dasd_eckd_private *private; |
1560 | unsigned long *idaws; | 1727 | unsigned long *idaws; |
@@ -1564,11 +1731,9 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
1564 | struct req_iterator iter; | 1731 | struct req_iterator iter; |
1565 | struct bio_vec *bv; | 1732 | struct bio_vec *bv; |
1566 | char *dst; | 1733 | char *dst; |
1567 | unsigned int blksize, blk_per_trk, off; | 1734 | unsigned int off; |
1568 | int count, cidaw, cplength, datasize; | 1735 | int count, cidaw, cplength, datasize; |
1569 | sector_t recid, first_rec, last_rec; | 1736 | sector_t recid; |
1570 | sector_t first_trk, last_trk; | ||
1571 | unsigned int first_offs, last_offs; | ||
1572 | unsigned char cmd, rcmd; | 1737 | unsigned char cmd, rcmd; |
1573 | int use_prefix; | 1738 | int use_prefix; |
1574 | struct dasd_device *basedev; | 1739 | struct dasd_device *basedev; |
@@ -1581,15 +1746,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
1581 | cmd = DASD_ECKD_CCW_WRITE_MT; | 1746 | cmd = DASD_ECKD_CCW_WRITE_MT; |
1582 | else | 1747 | else |
1583 | return ERR_PTR(-EINVAL); | 1748 | return ERR_PTR(-EINVAL); |
1584 | /* Calculate number of blocks/records per track. */ | 1749 | |
1585 | blksize = block->bp_block; | ||
1586 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); | ||
1587 | /* Calculate record id of first and last block. */ | ||
1588 | first_rec = first_trk = req->sector >> block->s2b_shift; | ||
1589 | first_offs = sector_div(first_trk, blk_per_trk); | ||
1590 | last_rec = last_trk = | ||
1591 | (req->sector + req->nr_sectors - 1) >> block->s2b_shift; | ||
1592 | last_offs = sector_div(last_trk, blk_per_trk); | ||
1593 | /* Check struct bio and count the number of blocks for the request. */ | 1750 | /* Check struct bio and count the number of blocks for the request. */ |
1594 | count = 0; | 1751 | count = 0; |
1595 | cidaw = 0; | 1752 | cidaw = 0; |
@@ -1739,6 +1896,497 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | |||
1739 | return cqr; | 1896 | return cqr; |
1740 | } | 1897 | } |
1741 | 1898 | ||
1899 | static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | ||
1900 | struct dasd_device *startdev, | ||
1901 | struct dasd_block *block, | ||
1902 | struct request *req, | ||
1903 | sector_t first_rec, | ||
1904 | sector_t last_rec, | ||
1905 | sector_t first_trk, | ||
1906 | sector_t last_trk, | ||
1907 | unsigned int first_offs, | ||
1908 | unsigned int last_offs, | ||
1909 | unsigned int blk_per_trk, | ||
1910 | unsigned int blksize) | ||
1911 | { | ||
1912 | struct dasd_eckd_private *private; | ||
1913 | unsigned long *idaws; | ||
1914 | struct dasd_ccw_req *cqr; | ||
1915 | struct ccw1 *ccw; | ||
1916 | struct req_iterator iter; | ||
1917 | struct bio_vec *bv; | ||
1918 | char *dst, *idaw_dst; | ||
1919 | unsigned int cidaw, cplength, datasize; | ||
1920 | unsigned int tlf; | ||
1921 | sector_t recid; | ||
1922 | unsigned char cmd; | ||
1923 | struct dasd_device *basedev; | ||
1924 | unsigned int trkcount, count, count_to_trk_end; | ||
1925 | unsigned int idaw_len, seg_len, part_len, len_to_track_end; | ||
1926 | unsigned char new_track, end_idaw; | ||
1927 | sector_t trkid; | ||
1928 | unsigned int recoffs; | ||
1929 | |||
1930 | basedev = block->base; | ||
1931 | private = (struct dasd_eckd_private *) basedev->private; | ||
1932 | if (rq_data_dir(req) == READ) | ||
1933 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; | ||
1934 | else if (rq_data_dir(req) == WRITE) | ||
1935 | cmd = DASD_ECKD_CCW_WRITE_TRACK_DATA; | ||
1936 | else | ||
1937 | return ERR_PTR(-EINVAL); | ||
1938 | |||
1939 | /* Track based I/O needs IDAWs for each page, and not just for | ||
1940 | * 64 bit addresses. We need additional idals for pages | ||
1941 | * that get filled from two tracks, so we use the number | ||
1942 | * of records as upper limit. | ||
1943 | */ | ||
1944 | cidaw = last_rec - first_rec + 1; | ||
1945 | trkcount = last_trk - first_trk + 1; | ||
1946 | |||
1947 | /* 1x prefix + one read/write ccw per track */ | ||
1948 | cplength = 1 + trkcount; | ||
1949 | |||
1950 | /* on 31-bit we need space for two 32 bit addresses per page | ||
1951 | * on 64-bit one 64 bit address | ||
1952 | */ | ||
1953 | datasize = sizeof(struct PFX_eckd_data) + | ||
1954 | cidaw * sizeof(unsigned long long); | ||
1955 | |||
1956 | /* Allocate the ccw request. */ | ||
1957 | cqr = dasd_smalloc_request(dasd_eckd_discipline.name, | ||
1958 | cplength, datasize, startdev); | ||
1959 | if (IS_ERR(cqr)) | ||
1960 | return cqr; | ||
1961 | ccw = cqr->cpaddr; | ||
1962 | /* transfer length factor: how many bytes to read from the last track */ | ||
1963 | if (first_trk == last_trk) | ||
1964 | tlf = last_offs - first_offs + 1; | ||
1965 | else | ||
1966 | tlf = last_offs + 1; | ||
1967 | tlf *= blksize; | ||
1968 | |||
1969 | if (prefix_LRE(ccw++, cqr->data, first_trk, | ||
1970 | last_trk, cmd, basedev, startdev, | ||
1971 | 1 /* format */, first_offs + 1, | ||
1972 | trkcount, blksize, | ||
1973 | tlf) == -EAGAIN) { | ||
1974 | /* Clock not in sync and XRC is enabled. | ||
1975 | * Try again later. | ||
1976 | */ | ||
1977 | dasd_sfree_request(cqr, startdev); | ||
1978 | return ERR_PTR(-EAGAIN); | ||
1979 | } | ||
1980 | |||
1981 | /* | ||
1982 | * The translation of request into ccw programs must meet the | ||
1983 | * following conditions: | ||
1984 | * - all idaws but the first and the last must address full pages | ||
1985 | * (or 2K blocks on 31-bit) | ||
1986 | * - the scope of a ccw and it's idal ends with the track boundaries | ||
1987 | */ | ||
1988 | idaws = (unsigned long *) (cqr->data + sizeof(struct PFX_eckd_data)); | ||
1989 | recid = first_rec; | ||
1990 | new_track = 1; | ||
1991 | end_idaw = 0; | ||
1992 | len_to_track_end = 0; | ||
1993 | idaw_dst = 0; | ||
1994 | idaw_len = 0; | ||
1995 | rq_for_each_segment(bv, req, iter) { | ||
1996 | dst = page_address(bv->bv_page) + bv->bv_offset; | ||
1997 | seg_len = bv->bv_len; | ||
1998 | while (seg_len) { | ||
1999 | if (new_track) { | ||
2000 | trkid = recid; | ||
2001 | recoffs = sector_div(trkid, blk_per_trk); | ||
2002 | count_to_trk_end = blk_per_trk - recoffs; | ||
2003 | count = min((last_rec - recid + 1), | ||
2004 | (sector_t)count_to_trk_end); | ||
2005 | len_to_track_end = count * blksize; | ||
2006 | ccw[-1].flags |= CCW_FLAG_CC; | ||
2007 | ccw->cmd_code = cmd; | ||
2008 | ccw->count = len_to_track_end; | ||
2009 | ccw->cda = (__u32)(addr_t)idaws; | ||
2010 | ccw->flags = CCW_FLAG_IDA; | ||
2011 | ccw++; | ||
2012 | recid += count; | ||
2013 | new_track = 0; | ||
2014 | } | ||
2015 | /* If we start a new idaw, everything is fine and the | ||
2016 | * start of the new idaw is the start of this segment. | ||
2017 | * If we continue an idaw, we must make sure that the | ||
2018 | * current segment begins where the so far accumulated | ||
2019 | * idaw ends | ||
2020 | */ | ||
2021 | if (!idaw_dst) | ||
2022 | idaw_dst = dst; | ||
2023 | if ((idaw_dst + idaw_len) != dst) { | ||
2024 | dasd_sfree_request(cqr, startdev); | ||
2025 | return ERR_PTR(-ERANGE); | ||
2026 | } | ||
2027 | part_len = min(seg_len, len_to_track_end); | ||
2028 | seg_len -= part_len; | ||
2029 | dst += part_len; | ||
2030 | idaw_len += part_len; | ||
2031 | len_to_track_end -= part_len; | ||
2032 | /* collected memory area ends on an IDA_BLOCK border, | ||
2033 | * -> create an idaw | ||
2034 | * idal_create_words will handle cases where idaw_len | ||
2035 | * is larger then IDA_BLOCK_SIZE | ||
2036 | */ | ||
2037 | if (!(__pa(idaw_dst + idaw_len) & (IDA_BLOCK_SIZE-1))) | ||
2038 | end_idaw = 1; | ||
2039 | /* We also need to end the idaw at track end */ | ||
2040 | if (!len_to_track_end) { | ||
2041 | new_track = 1; | ||
2042 | end_idaw = 1; | ||
2043 | } | ||
2044 | if (end_idaw) { | ||
2045 | idaws = idal_create_words(idaws, idaw_dst, | ||
2046 | idaw_len); | ||
2047 | idaw_dst = 0; | ||
2048 | idaw_len = 0; | ||
2049 | end_idaw = 0; | ||
2050 | } | ||
2051 | } | ||
2052 | } | ||
2053 | |||
2054 | if (blk_noretry_request(req) || | ||
2055 | block->base->features & DASD_FEATURE_FAILFAST) | ||
2056 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | ||
2057 | cqr->startdev = startdev; | ||
2058 | cqr->memdev = startdev; | ||
2059 | cqr->block = block; | ||
2060 | cqr->expires = 5 * 60 * HZ; /* 5 minutes */ | ||
2061 | cqr->lpm = private->path_data.ppm; | ||
2062 | cqr->retries = 256; | ||
2063 | cqr->buildclk = get_clock(); | ||
2064 | cqr->status = DASD_CQR_FILLED; | ||
2065 | return cqr; | ||
2066 | } | ||
2067 | |||
2068 | static int prepare_itcw(struct itcw *itcw, | ||
2069 | unsigned int trk, unsigned int totrk, int cmd, | ||
2070 | struct dasd_device *basedev, | ||
2071 | struct dasd_device *startdev, | ||
2072 | unsigned int rec_on_trk, int count, | ||
2073 | unsigned int blksize, | ||
2074 | unsigned int total_data_size, | ||
2075 | unsigned int tlf, | ||
2076 | unsigned int blk_per_trk) | ||
2077 | { | ||
2078 | struct PFX_eckd_data pfxdata; | ||
2079 | struct dasd_eckd_private *basepriv, *startpriv; | ||
2080 | struct DE_eckd_data *dedata; | ||
2081 | struct LRE_eckd_data *lredata; | ||
2082 | struct dcw *dcw; | ||
2083 | |||
2084 | u32 begcyl, endcyl; | ||
2085 | u16 heads, beghead, endhead; | ||
2086 | u8 pfx_cmd; | ||
2087 | |||
2088 | int rc = 0; | ||
2089 | int sector = 0; | ||
2090 | int dn, d; | ||
2091 | |||
2092 | |||
2093 | /* setup prefix data */ | ||
2094 | basepriv = (struct dasd_eckd_private *) basedev->private; | ||
2095 | startpriv = (struct dasd_eckd_private *) startdev->private; | ||
2096 | dedata = &pfxdata.define_extent; | ||
2097 | lredata = &pfxdata.locate_record; | ||
2098 | |||
2099 | memset(&pfxdata, 0, sizeof(pfxdata)); | ||
2100 | pfxdata.format = 1; /* PFX with LRE */ | ||
2101 | pfxdata.base_address = basepriv->ned->unit_addr; | ||
2102 | pfxdata.base_lss = basepriv->ned->ID; | ||
2103 | pfxdata.validity.define_extent = 1; | ||
2104 | |||
2105 | /* private uid is kept up to date, conf_data may be outdated */ | ||
2106 | if (startpriv->uid.type != UA_BASE_DEVICE) { | ||
2107 | pfxdata.validity.verify_base = 1; | ||
2108 | if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) | ||
2109 | pfxdata.validity.hyper_pav = 1; | ||
2110 | } | ||
2111 | |||
2112 | switch (cmd) { | ||
2113 | case DASD_ECKD_CCW_READ_TRACK_DATA: | ||
2114 | dedata->mask.perm = 0x1; | ||
2115 | dedata->attributes.operation = basepriv->attrib.operation; | ||
2116 | dedata->blk_size = blksize; | ||
2117 | dedata->ga_extended |= 0x42; | ||
2118 | lredata->operation.orientation = 0x0; | ||
2119 | lredata->operation.operation = 0x0C; | ||
2120 | lredata->auxiliary.check_bytes = 0x01; | ||
2121 | pfx_cmd = DASD_ECKD_CCW_PFX_READ; | ||
2122 | break; | ||
2123 | case DASD_ECKD_CCW_WRITE_TRACK_DATA: | ||
2124 | dedata->mask.perm = 0x02; | ||
2125 | dedata->attributes.operation = basepriv->attrib.operation; | ||
2126 | dedata->blk_size = blksize; | ||
2127 | rc = check_XRC_on_prefix(&pfxdata, basedev); | ||
2128 | dedata->ga_extended |= 0x42; | ||
2129 | lredata->operation.orientation = 0x0; | ||
2130 | lredata->operation.operation = 0x3F; | ||
2131 | lredata->extended_operation = 0x23; | ||
2132 | lredata->auxiliary.check_bytes = 0x2; | ||
2133 | pfx_cmd = DASD_ECKD_CCW_PFX; | ||
2134 | break; | ||
2135 | default: | ||
2136 | DBF_DEV_EVENT(DBF_ERR, basedev, | ||
2137 | "prepare itcw, unknown opcode 0x%x", cmd); | ||
2138 | BUG(); | ||
2139 | break; | ||
2140 | } | ||
2141 | if (rc) | ||
2142 | return rc; | ||
2143 | |||
2144 | dedata->attributes.mode = 0x3; /* ECKD */ | ||
2145 | |||
2146 | heads = basepriv->rdc_data.trk_per_cyl; | ||
2147 | begcyl = trk / heads; | ||
2148 | beghead = trk % heads; | ||
2149 | endcyl = totrk / heads; | ||
2150 | endhead = totrk % heads; | ||
2151 | |||
2152 | /* check for sequential prestage - enhance cylinder range */ | ||
2153 | if (dedata->attributes.operation == DASD_SEQ_PRESTAGE || | ||
2154 | dedata->attributes.operation == DASD_SEQ_ACCESS) { | ||
2155 | |||
2156 | if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl) | ||
2157 | endcyl += basepriv->attrib.nr_cyl; | ||
2158 | else | ||
2159 | endcyl = (basepriv->real_cyl - 1); | ||
2160 | } | ||
2161 | |||
2162 | set_ch_t(&dedata->beg_ext, begcyl, beghead); | ||
2163 | set_ch_t(&dedata->end_ext, endcyl, endhead); | ||
2164 | |||
2165 | dedata->ep_format = 0x20; /* records per track is valid */ | ||
2166 | dedata->ep_rec_per_track = blk_per_trk; | ||
2167 | |||
2168 | if (rec_on_trk) { | ||
2169 | switch (basepriv->rdc_data.dev_type) { | ||
2170 | case 0x3390: | ||
2171 | dn = ceil_quot(blksize + 6, 232); | ||
2172 | d = 9 + ceil_quot(blksize + 6 * (dn + 1), 34); | ||
2173 | sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8; | ||
2174 | break; | ||
2175 | case 0x3380: | ||
2176 | d = 7 + ceil_quot(blksize + 12, 32); | ||
2177 | sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7; | ||
2178 | break; | ||
2179 | } | ||
2180 | } | ||
2181 | |||
2182 | lredata->auxiliary.length_valid = 1; | ||
2183 | lredata->auxiliary.length_scope = 1; | ||
2184 | lredata->auxiliary.imbedded_ccw_valid = 1; | ||
2185 | lredata->length = tlf; | ||
2186 | lredata->imbedded_ccw = cmd; | ||
2187 | lredata->count = count; | ||
2188 | lredata->sector = sector; | ||
2189 | set_ch_t(&lredata->seek_addr, begcyl, beghead); | ||
2190 | lredata->search_arg.cyl = lredata->seek_addr.cyl; | ||
2191 | lredata->search_arg.head = lredata->seek_addr.head; | ||
2192 | lredata->search_arg.record = rec_on_trk; | ||
2193 | |||
2194 | dcw = itcw_add_dcw(itcw, pfx_cmd, 0, | ||
2195 | &pfxdata, sizeof(pfxdata), total_data_size); | ||
2196 | |||
2197 | return rc; | ||
2198 | } | ||
2199 | |||
2200 | static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | ||
2201 | struct dasd_device *startdev, | ||
2202 | struct dasd_block *block, | ||
2203 | struct request *req, | ||
2204 | sector_t first_rec, | ||
2205 | sector_t last_rec, | ||
2206 | sector_t first_trk, | ||
2207 | sector_t last_trk, | ||
2208 | unsigned int first_offs, | ||
2209 | unsigned int last_offs, | ||
2210 | unsigned int blk_per_trk, | ||
2211 | unsigned int blksize) | ||
2212 | { | ||
2213 | struct dasd_eckd_private *private; | ||
2214 | struct dasd_ccw_req *cqr; | ||
2215 | struct req_iterator iter; | ||
2216 | struct bio_vec *bv; | ||
2217 | char *dst; | ||
2218 | unsigned int trkcount, ctidaw; | ||
2219 | unsigned char cmd; | ||
2220 | struct dasd_device *basedev; | ||
2221 | unsigned int tlf; | ||
2222 | struct itcw *itcw; | ||
2223 | struct tidaw *last_tidaw = NULL; | ||
2224 | int itcw_op; | ||
2225 | size_t itcw_size; | ||
2226 | |||
2227 | basedev = block->base; | ||
2228 | private = (struct dasd_eckd_private *) basedev->private; | ||
2229 | if (rq_data_dir(req) == READ) { | ||
2230 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; | ||
2231 | itcw_op = ITCW_OP_READ; | ||
2232 | } else if (rq_data_dir(req) == WRITE) { | ||
2233 | cmd = DASD_ECKD_CCW_WRITE_TRACK_DATA; | ||
2234 | itcw_op = ITCW_OP_WRITE; | ||
2235 | } else | ||
2236 | return ERR_PTR(-EINVAL); | ||
2237 | |||
2238 | /* trackbased I/O needs address all memory via TIDAWs, | ||
2239 | * not just for 64 bit addresses. This allows us to map | ||
2240 | * each segment directly to one tidaw. | ||
2241 | */ | ||
2242 | trkcount = last_trk - first_trk + 1; | ||
2243 | ctidaw = 0; | ||
2244 | rq_for_each_segment(bv, req, iter) { | ||
2245 | ++ctidaw; | ||
2246 | } | ||
2247 | |||
2248 | /* Allocate the ccw request. */ | ||
2249 | itcw_size = itcw_calc_size(0, ctidaw, 0); | ||
2250 | cqr = dasd_smalloc_request(dasd_eckd_discipline.name, | ||
2251 | 0, itcw_size, startdev); | ||
2252 | if (IS_ERR(cqr)) | ||
2253 | return cqr; | ||
2254 | |||
2255 | cqr->cpmode = 1; | ||
2256 | cqr->startdev = startdev; | ||
2257 | cqr->memdev = startdev; | ||
2258 | cqr->block = block; | ||
2259 | cqr->expires = 100*HZ; | ||
2260 | cqr->buildclk = get_clock(); | ||
2261 | cqr->status = DASD_CQR_FILLED; | ||
2262 | cqr->retries = 10; | ||
2263 | |||
2264 | /* transfer length factor: how many bytes to read from the last track */ | ||
2265 | if (first_trk == last_trk) | ||
2266 | tlf = last_offs - first_offs + 1; | ||
2267 | else | ||
2268 | tlf = last_offs + 1; | ||
2269 | tlf *= blksize; | ||
2270 | |||
2271 | itcw = itcw_init(cqr->data, itcw_size, itcw_op, 0, ctidaw, 0); | ||
2272 | cqr->cpaddr = itcw_get_tcw(itcw); | ||
2273 | |||
2274 | if (prepare_itcw(itcw, first_trk, last_trk, | ||
2275 | cmd, basedev, startdev, | ||
2276 | first_offs + 1, | ||
2277 | trkcount, blksize, | ||
2278 | (last_rec - first_rec + 1) * blksize, | ||
2279 | tlf, blk_per_trk) == -EAGAIN) { | ||
2280 | /* Clock not in sync and XRC is enabled. | ||
2281 | * Try again later. | ||
2282 | */ | ||
2283 | dasd_sfree_request(cqr, startdev); | ||
2284 | return ERR_PTR(-EAGAIN); | ||
2285 | } | ||
2286 | |||
2287 | /* | ||
2288 | * A tidaw can address 4k of memory, but must not cross page boundaries | ||
2289 | * We can let the block layer handle this by setting | ||
2290 | * blk_queue_segment_boundary to page boundaries and | ||
2291 | * blk_max_segment_size to page size when setting up the request queue. | ||
2292 | */ | ||
2293 | rq_for_each_segment(bv, req, iter) { | ||
2294 | dst = page_address(bv->bv_page) + bv->bv_offset; | ||
2295 | last_tidaw = itcw_add_tidaw(itcw, 0x00, dst, bv->bv_len); | ||
2296 | if (IS_ERR(last_tidaw)) | ||
2297 | return (struct dasd_ccw_req *)last_tidaw; | ||
2298 | } | ||
2299 | |||
2300 | last_tidaw->flags |= 0x80; | ||
2301 | itcw_finalize(itcw); | ||
2302 | |||
2303 | if (blk_noretry_request(req) || | ||
2304 | block->base->features & DASD_FEATURE_FAILFAST) | ||
2305 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | ||
2306 | cqr->startdev = startdev; | ||
2307 | cqr->memdev = startdev; | ||
2308 | cqr->block = block; | ||
2309 | cqr->expires = 5 * 60 * HZ; /* 5 minutes */ | ||
2310 | cqr->lpm = private->path_data.ppm; | ||
2311 | cqr->retries = 256; | ||
2312 | cqr->buildclk = get_clock(); | ||
2313 | cqr->status = DASD_CQR_FILLED; | ||
2314 | return cqr; | ||
2315 | } | ||
2316 | |||
2317 | static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | ||
2318 | struct dasd_block *block, | ||
2319 | struct request *req) | ||
2320 | { | ||
2321 | int tpm, cmdrtd, cmdwtd; | ||
2322 | int use_prefix; | ||
2323 | |||
2324 | struct dasd_eckd_private *private; | ||
2325 | int fcx_in_css, fcx_in_gneq, fcx_in_features; | ||
2326 | struct dasd_device *basedev; | ||
2327 | sector_t first_rec, last_rec; | ||
2328 | sector_t first_trk, last_trk; | ||
2329 | unsigned int first_offs, last_offs; | ||
2330 | unsigned int blk_per_trk, blksize; | ||
2331 | int cdlspecial; | ||
2332 | struct dasd_ccw_req *cqr; | ||
2333 | |||
2334 | basedev = block->base; | ||
2335 | private = (struct dasd_eckd_private *) basedev->private; | ||
2336 | |||
2337 | /* Calculate number of blocks/records per track. */ | ||
2338 | blksize = block->bp_block; | ||
2339 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); | ||
2340 | /* Calculate record id of first and last block. */ | ||
2341 | first_rec = first_trk = req->sector >> block->s2b_shift; | ||
2342 | first_offs = sector_div(first_trk, blk_per_trk); | ||
2343 | last_rec = last_trk = | ||
2344 | (req->sector + req->nr_sectors - 1) >> block->s2b_shift; | ||
2345 | last_offs = sector_div(last_trk, blk_per_trk); | ||
2346 | cdlspecial = (private->uses_cdl && first_rec < 2*blk_per_trk); | ||
2347 | |||
2348 | /* is transport mode supported ? */ | ||
2349 | fcx_in_css = css_general_characteristics.fcx; | ||
2350 | fcx_in_gneq = private->gneq->reserved2[7] & 0x04; | ||
2351 | fcx_in_features = private->features.feature[40] & 0x80; | ||
2352 | tpm = fcx_in_css && fcx_in_gneq && fcx_in_features; | ||
2353 | |||
2354 | /* is read track data and write track data in command mode supported? */ | ||
2355 | cmdrtd = private->features.feature[9] & 0x20; | ||
2356 | cmdwtd = private->features.feature[12] & 0x40; | ||
2357 | use_prefix = private->features.feature[8] & 0x01; | ||
2358 | |||
2359 | cqr = NULL; | ||
2360 | if (cdlspecial || dasd_page_cache) { | ||
2361 | /* do nothing, just fall through to the cmd mode single case */ | ||
2362 | } else if (!dasd_nofcx && tpm && (first_trk == last_trk)) { | ||
2363 | cqr = dasd_eckd_build_cp_tpm_track(startdev, block, req, | ||
2364 | first_rec, last_rec, | ||
2365 | first_trk, last_trk, | ||
2366 | first_offs, last_offs, | ||
2367 | blk_per_trk, blksize); | ||
2368 | if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) | ||
2369 | cqr = NULL; | ||
2370 | } else if (use_prefix && | ||
2371 | (((rq_data_dir(req) == READ) && cmdrtd) || | ||
2372 | ((rq_data_dir(req) == WRITE) && cmdwtd))) { | ||
2373 | cqr = dasd_eckd_build_cp_cmd_track(startdev, block, req, | ||
2374 | first_rec, last_rec, | ||
2375 | first_trk, last_trk, | ||
2376 | first_offs, last_offs, | ||
2377 | blk_per_trk, blksize); | ||
2378 | if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN) | ||
2379 | cqr = NULL; | ||
2380 | } | ||
2381 | if (!cqr) | ||
2382 | cqr = dasd_eckd_build_cp_cmd_single(startdev, block, req, | ||
2383 | first_rec, last_rec, | ||
2384 | first_trk, last_trk, | ||
2385 | first_offs, last_offs, | ||
2386 | blk_per_trk, blksize); | ||
2387 | return cqr; | ||
2388 | } | ||
2389 | |||
1742 | static int | 2390 | static int |
1743 | dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) | 2391 | dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) |
1744 | { | 2392 | { |
@@ -1792,7 +2440,7 @@ out: | |||
1792 | } | 2440 | } |
1793 | 2441 | ||
1794 | /* | 2442 | /* |
1795 | * Modify ccw chain in cqr so it can be started on a base device. | 2443 | * Modify ccw/tcw in cqr so it can be started on a base device. |
1796 | * | 2444 | * |
1797 | * Note that this is not enough to restart the cqr! | 2445 | * Note that this is not enough to restart the cqr! |
1798 | * Either reset cqr->startdev as well (summary unit check handling) | 2446 | * Either reset cqr->startdev as well (summary unit check handling) |
@@ -1802,13 +2450,24 @@ void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr) | |||
1802 | { | 2450 | { |
1803 | struct ccw1 *ccw; | 2451 | struct ccw1 *ccw; |
1804 | struct PFX_eckd_data *pfxdata; | 2452 | struct PFX_eckd_data *pfxdata; |
1805 | 2453 | struct tcw *tcw; | |
1806 | ccw = cqr->cpaddr; | 2454 | struct tccb *tccb; |
1807 | pfxdata = cqr->data; | 2455 | struct dcw *dcw; |
1808 | 2456 | ||
1809 | if (ccw->cmd_code == DASD_ECKD_CCW_PFX) { | 2457 | if (cqr->cpmode == 1) { |
2458 | tcw = cqr->cpaddr; | ||
2459 | tccb = tcw_get_tccb(tcw); | ||
2460 | dcw = (struct dcw *)&tccb->tca[0]; | ||
2461 | pfxdata = (struct PFX_eckd_data *)&dcw->cd[0]; | ||
1810 | pfxdata->validity.verify_base = 0; | 2462 | pfxdata->validity.verify_base = 0; |
1811 | pfxdata->validity.hyper_pav = 0; | 2463 | pfxdata->validity.hyper_pav = 0; |
2464 | } else { | ||
2465 | ccw = cqr->cpaddr; | ||
2466 | pfxdata = cqr->data; | ||
2467 | if (ccw->cmd_code == DASD_ECKD_CCW_PFX) { | ||
2468 | pfxdata->validity.verify_base = 0; | ||
2469 | pfxdata->validity.hyper_pav = 0; | ||
2470 | } | ||
1812 | } | 2471 | } |
1813 | } | 2472 | } |
1814 | 2473 | ||
@@ -1886,6 +2545,7 @@ dasd_eckd_release(struct dasd_device *device) | |||
1886 | { | 2545 | { |
1887 | struct dasd_ccw_req *cqr; | 2546 | struct dasd_ccw_req *cqr; |
1888 | int rc; | 2547 | int rc; |
2548 | struct ccw1 *ccw; | ||
1889 | 2549 | ||
1890 | if (!capable(CAP_SYS_ADMIN)) | 2550 | if (!capable(CAP_SYS_ADMIN)) |
1891 | return -EACCES; | 2551 | return -EACCES; |
@@ -1897,10 +2557,11 @@ dasd_eckd_release(struct dasd_device *device) | |||
1897 | "Could not allocate initialization request"); | 2557 | "Could not allocate initialization request"); |
1898 | return PTR_ERR(cqr); | 2558 | return PTR_ERR(cqr); |
1899 | } | 2559 | } |
1900 | cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE; | 2560 | ccw = cqr->cpaddr; |
1901 | cqr->cpaddr->flags |= CCW_FLAG_SLI; | 2561 | ccw->cmd_code = DASD_ECKD_CCW_RELEASE; |
1902 | cqr->cpaddr->count = 32; | 2562 | ccw->flags |= CCW_FLAG_SLI; |
1903 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; | 2563 | ccw->count = 32; |
2564 | ccw->cda = (__u32)(addr_t) cqr->data; | ||
1904 | cqr->startdev = device; | 2565 | cqr->startdev = device; |
1905 | cqr->memdev = device; | 2566 | cqr->memdev = device; |
1906 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 2567 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
@@ -1927,6 +2588,7 @@ dasd_eckd_reserve(struct dasd_device *device) | |||
1927 | { | 2588 | { |
1928 | struct dasd_ccw_req *cqr; | 2589 | struct dasd_ccw_req *cqr; |
1929 | int rc; | 2590 | int rc; |
2591 | struct ccw1 *ccw; | ||
1930 | 2592 | ||
1931 | if (!capable(CAP_SYS_ADMIN)) | 2593 | if (!capable(CAP_SYS_ADMIN)) |
1932 | return -EACCES; | 2594 | return -EACCES; |
@@ -1938,10 +2600,11 @@ dasd_eckd_reserve(struct dasd_device *device) | |||
1938 | "Could not allocate initialization request"); | 2600 | "Could not allocate initialization request"); |
1939 | return PTR_ERR(cqr); | 2601 | return PTR_ERR(cqr); |
1940 | } | 2602 | } |
1941 | cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE; | 2603 | ccw = cqr->cpaddr; |
1942 | cqr->cpaddr->flags |= CCW_FLAG_SLI; | 2604 | ccw->cmd_code = DASD_ECKD_CCW_RESERVE; |
1943 | cqr->cpaddr->count = 32; | 2605 | ccw->flags |= CCW_FLAG_SLI; |
1944 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; | 2606 | ccw->count = 32; |
2607 | ccw->cda = (__u32)(addr_t) cqr->data; | ||
1945 | cqr->startdev = device; | 2608 | cqr->startdev = device; |
1946 | cqr->memdev = device; | 2609 | cqr->memdev = device; |
1947 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 2610 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
@@ -1967,6 +2630,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) | |||
1967 | { | 2630 | { |
1968 | struct dasd_ccw_req *cqr; | 2631 | struct dasd_ccw_req *cqr; |
1969 | int rc; | 2632 | int rc; |
2633 | struct ccw1 *ccw; | ||
1970 | 2634 | ||
1971 | if (!capable(CAP_SYS_ADMIN)) | 2635 | if (!capable(CAP_SYS_ADMIN)) |
1972 | return -EACCES; | 2636 | return -EACCES; |
@@ -1978,10 +2642,11 @@ dasd_eckd_steal_lock(struct dasd_device *device) | |||
1978 | "Could not allocate initialization request"); | 2642 | "Could not allocate initialization request"); |
1979 | return PTR_ERR(cqr); | 2643 | return PTR_ERR(cqr); |
1980 | } | 2644 | } |
1981 | cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK; | 2645 | ccw = cqr->cpaddr; |
1982 | cqr->cpaddr->flags |= CCW_FLAG_SLI; | 2646 | ccw->cmd_code = DASD_ECKD_CCW_SLCK; |
1983 | cqr->cpaddr->count = 32; | 2647 | ccw->flags |= CCW_FLAG_SLI; |
1984 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; | 2648 | ccw->count = 32; |
2649 | ccw->cda = (__u32)(addr_t) cqr->data; | ||
1985 | cqr->startdev = device; | 2650 | cqr->startdev = device; |
1986 | cqr->memdev = device; | 2651 | cqr->memdev = device; |
1987 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 2652 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
@@ -2271,7 +2936,7 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) | |||
2271 | * Print sense data and related channel program. | 2936 | * Print sense data and related channel program. |
2272 | * Parts are printed because printk buffer is only 1024 bytes. | 2937 | * Parts are printed because printk buffer is only 1024 bytes. |
2273 | */ | 2938 | */ |
2274 | static void dasd_eckd_dump_sense(struct dasd_device *device, | 2939 | static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, |
2275 | struct dasd_ccw_req *req, struct irb *irb) | 2940 | struct dasd_ccw_req *req, struct irb *irb) |
2276 | { | 2941 | { |
2277 | char *page; | 2942 | char *page; |
@@ -2290,7 +2955,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, | |||
2290 | dev_name(&device->cdev->dev)); | 2955 | dev_name(&device->cdev->dev)); |
2291 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 2956 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
2292 | " in req: %p CS: 0x%02X DS: 0x%02X\n", req, | 2957 | " in req: %p CS: 0x%02X DS: 0x%02X\n", req, |
2293 | irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); | 2958 | scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw)); |
2294 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | 2959 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER |
2295 | " device %s: Failing CCW: %p\n", | 2960 | " device %s: Failing CCW: %p\n", |
2296 | dev_name(&device->cdev->dev), | 2961 | dev_name(&device->cdev->dev), |
@@ -2366,6 +3031,147 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, | |||
2366 | free_page((unsigned long) page); | 3031 | free_page((unsigned long) page); |
2367 | } | 3032 | } |
2368 | 3033 | ||
3034 | |||
3035 | /* | ||
3036 | * Print sense data from a tcw. | ||
3037 | */ | ||
3038 | static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, | ||
3039 | struct dasd_ccw_req *req, struct irb *irb) | ||
3040 | { | ||
3041 | char *page; | ||
3042 | int len, sl, sct, residual; | ||
3043 | |||
3044 | struct tsb *tsb; | ||
3045 | u8 *sense; | ||
3046 | |||
3047 | |||
3048 | page = (char *) get_zeroed_page(GFP_ATOMIC); | ||
3049 | if (page == NULL) { | ||
3050 | DEV_MESSAGE(KERN_ERR, device, " %s", | ||
3051 | "No memory to dump sense data"); | ||
3052 | return; | ||
3053 | } | ||
3054 | /* dump the sense data */ | ||
3055 | len = sprintf(page, KERN_ERR PRINTK_HEADER | ||
3056 | " I/O status report for device %s:\n", | ||
3057 | dev_name(&device->cdev->dev)); | ||
3058 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3059 | " in req: %p CS: 0x%02X DS: 0x%02X " | ||
3060 | "fcxs: 0x%02X schxs: 0x%02X\n", req, | ||
3061 | scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), | ||
3062 | irb->scsw.tm.fcxs, irb->scsw.tm.schxs); | ||
3063 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3064 | " device %s: Failing TCW: %p\n", | ||
3065 | dev_name(&device->cdev->dev), | ||
3066 | (void *) (addr_t) irb->scsw.tm.tcw); | ||
3067 | |||
3068 | tsb = NULL; | ||
3069 | sense = NULL; | ||
3070 | if (irb->scsw.tm.tcw) | ||
3071 | tsb = tcw_get_tsb( | ||
3072 | (struct tcw *)(unsigned long)irb->scsw.tm.tcw); | ||
3073 | |||
3074 | if (tsb && (irb->scsw.tm.fcxs == 0x01)) { | ||
3075 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3076 | " tsb->length %d\n", tsb->length); | ||
3077 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3078 | " tsb->flags %x\n", tsb->flags); | ||
3079 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3080 | " tsb->dcw_offset %d\n", tsb->dcw_offset); | ||
3081 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3082 | " tsb->count %d\n", tsb->count); | ||
3083 | residual = tsb->count - 28; | ||
3084 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3085 | " residual %d\n", residual); | ||
3086 | |||
3087 | switch (tsb->flags & 0x07) { | ||
3088 | case 1: /* tsa_iostat */ | ||
3089 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3090 | " tsb->tsa.iostat.dev_time %d\n", | ||
3091 | tsb->tsa.iostat.dev_time); | ||
3092 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3093 | " tsb->tsa.iostat.def_time %d\n", | ||
3094 | tsb->tsa.iostat.def_time); | ||
3095 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3096 | " tsb->tsa.iostat.queue_time %d\n", | ||
3097 | tsb->tsa.iostat.queue_time); | ||
3098 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3099 | " tsb->tsa.iostat.dev_busy_time %d\n", | ||
3100 | tsb->tsa.iostat.dev_busy_time); | ||
3101 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3102 | " tsb->tsa.iostat.dev_act_time %d\n", | ||
3103 | tsb->tsa.iostat.dev_act_time); | ||
3104 | sense = tsb->tsa.iostat.sense; | ||
3105 | break; | ||
3106 | case 2: /* ts_ddpc */ | ||
3107 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3108 | " tsb->tsa.ddpc.rc %d\n", tsb->tsa.ddpc.rc); | ||
3109 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3110 | " tsb->tsa.ddpc.rcq: "); | ||
3111 | for (sl = 0; sl < 16; sl++) { | ||
3112 | for (sct = 0; sct < 8; sct++) { | ||
3113 | len += sprintf(page + len, " %02x", | ||
3114 | tsb->tsa.ddpc.rcq[sl]); | ||
3115 | } | ||
3116 | len += sprintf(page + len, "\n"); | ||
3117 | } | ||
3118 | sense = tsb->tsa.ddpc.sense; | ||
3119 | break; | ||
3120 | case 3: /* tsa_intrg */ | ||
3121 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3122 | " tsb->tsa.intrg.: not supportet yet \n"); | ||
3123 | break; | ||
3124 | } | ||
3125 | |||
3126 | if (sense) { | ||
3127 | for (sl = 0; sl < 4; sl++) { | ||
3128 | len += sprintf(page + len, | ||
3129 | KERN_ERR PRINTK_HEADER | ||
3130 | " Sense(hex) %2d-%2d:", | ||
3131 | (8 * sl), ((8 * sl) + 7)); | ||
3132 | for (sct = 0; sct < 8; sct++) { | ||
3133 | len += sprintf(page + len, " %02x", | ||
3134 | sense[8 * sl + sct]); | ||
3135 | } | ||
3136 | len += sprintf(page + len, "\n"); | ||
3137 | } | ||
3138 | |||
3139 | if (sense[27] & DASD_SENSE_BIT_0) { | ||
3140 | /* 24 Byte Sense Data */ | ||
3141 | sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3142 | " 24 Byte: %x MSG %x, " | ||
3143 | "%s MSGb to SYSOP\n", | ||
3144 | sense[7] >> 4, sense[7] & 0x0f, | ||
3145 | sense[1] & 0x10 ? "" : "no"); | ||
3146 | } else { | ||
3147 | /* 32 Byte Sense Data */ | ||
3148 | sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3149 | " 32 Byte: Format: %x " | ||
3150 | "Exception class %x\n", | ||
3151 | sense[6] & 0x0f, sense[22] >> 4); | ||
3152 | } | ||
3153 | } else { | ||
3154 | sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3155 | " SORRY - NO VALID SENSE AVAILABLE\n"); | ||
3156 | } | ||
3157 | } else { | ||
3158 | sprintf(page + len, KERN_ERR PRINTK_HEADER | ||
3159 | " SORRY - NO TSB DATA AVAILABLE\n"); | ||
3160 | } | ||
3161 | printk("%s", page); | ||
3162 | free_page((unsigned long) page); | ||
3163 | } | ||
3164 | |||
3165 | static void dasd_eckd_dump_sense(struct dasd_device *device, | ||
3166 | struct dasd_ccw_req *req, struct irb *irb) | ||
3167 | { | ||
3168 | if (req && scsw_is_tm(&req->irb.scsw)) | ||
3169 | dasd_eckd_dump_sense_tcw(device, req, irb); | ||
3170 | else | ||
3171 | dasd_eckd_dump_sense_ccw(device, req, irb); | ||
3172 | } | ||
3173 | |||
3174 | |||
2369 | /* | 3175 | /* |
2370 | * max_blocks is dependent on the amount of storage that is available | 3176 | * max_blocks is dependent on the amount of storage that is available |
2371 | * in the static io buffer for each device. Currently each device has | 3177 | * in the static io buffer for each device. Currently each device has |