diff options
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 787 |
1 files changed, 575 insertions, 212 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 6038d9195e27..61f16937c1e0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -52,16 +52,6 @@ MODULE_LICENSE("GPL"); | |||
52 | 52 | ||
53 | static struct dasd_discipline dasd_eckd_discipline; | 53 | static struct dasd_discipline dasd_eckd_discipline; |
54 | 54 | ||
55 | struct dasd_eckd_private { | ||
56 | struct dasd_eckd_characteristics rdc_data; | ||
57 | struct dasd_eckd_confdata conf_data; | ||
58 | struct dasd_eckd_path path_data; | ||
59 | struct eckd_count count_area[5]; | ||
60 | int init_cqr_status; | ||
61 | int uses_cdl; | ||
62 | struct attrib_data_t attrib; /* e.g. cache operations */ | ||
63 | }; | ||
64 | |||
65 | /* The ccw bus type uses this table to find devices that it sends to | 55 | /* The ccw bus type uses this table to find devices that it sends to |
66 | * dasd_eckd_probe */ | 56 | * dasd_eckd_probe */ |
67 | static struct ccw_device_id dasd_eckd_ids[] = { | 57 | static struct ccw_device_id dasd_eckd_ids[] = { |
@@ -188,7 +178,7 @@ check_XRC (struct ccw1 *de_ccw, | |||
188 | if (rc == -ENOSYS || rc == -EACCES) | 178 | if (rc == -ENOSYS || rc == -EACCES) |
189 | rc = 0; | 179 | rc = 0; |
190 | 180 | ||
191 | de_ccw->count = sizeof (struct DE_eckd_data); | 181 | de_ccw->count = sizeof(struct DE_eckd_data); |
192 | de_ccw->flags |= CCW_FLAG_SLI; | 182 | de_ccw->flags |= CCW_FLAG_SLI; |
193 | return rc; | 183 | return rc; |
194 | } | 184 | } |
@@ -208,7 +198,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, | |||
208 | ccw->count = 16; | 198 | ccw->count = 16; |
209 | ccw->cda = (__u32) __pa(data); | 199 | ccw->cda = (__u32) __pa(data); |
210 | 200 | ||
211 | memset(data, 0, sizeof (struct DE_eckd_data)); | 201 | memset(data, 0, sizeof(struct DE_eckd_data)); |
212 | switch (cmd) { | 202 | switch (cmd) { |
213 | case DASD_ECKD_CCW_READ_HOME_ADDRESS: | 203 | case DASD_ECKD_CCW_READ_HOME_ADDRESS: |
214 | case DASD_ECKD_CCW_READ_RECORD_ZERO: | 204 | case DASD_ECKD_CCW_READ_RECORD_ZERO: |
@@ -280,6 +270,132 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, | |||
280 | return rc; | 270 | return rc; |
281 | } | 271 | } |
282 | 272 | ||
273 | static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, | ||
274 | struct dasd_device *device) | ||
275 | { | ||
276 | struct dasd_eckd_private *private; | ||
277 | int rc; | ||
278 | |||
279 | private = (struct dasd_eckd_private *) device->private; | ||
280 | if (!private->rdc_data.facilities.XRC_supported) | ||
281 | return 0; | ||
282 | |||
283 | /* switch on System Time Stamp - needed for XRC Support */ | ||
284 | pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid' */ | ||
285 | pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */ | ||
286 | pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */ | ||
287 | |||
288 | rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time); | ||
289 | /* Ignore return code if sync clock is switched off. */ | ||
290 | if (rc == -ENOSYS || rc == -EACCES) | ||
291 | rc = 0; | ||
292 | return rc; | ||
293 | } | ||
294 | |||
295 | static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk, | ||
296 | int totrk, int cmd, struct dasd_device *basedev, | ||
297 | struct dasd_device *startdev) | ||
298 | { | ||
299 | struct dasd_eckd_private *basepriv, *startpriv; | ||
300 | struct DE_eckd_data *data; | ||
301 | struct ch_t geo, beg, end; | ||
302 | int rc = 0; | ||
303 | |||
304 | basepriv = (struct dasd_eckd_private *) basedev->private; | ||
305 | startpriv = (struct dasd_eckd_private *) startdev->private; | ||
306 | data = &pfxdata->define_extend; | ||
307 | |||
308 | ccw->cmd_code = DASD_ECKD_CCW_PFX; | ||
309 | ccw->flags = 0; | ||
310 | ccw->count = sizeof(*pfxdata); | ||
311 | ccw->cda = (__u32) __pa(pfxdata); | ||
312 | |||
313 | memset(pfxdata, 0, sizeof(*pfxdata)); | ||
314 | /* prefix data */ | ||
315 | pfxdata->format = 0; | ||
316 | pfxdata->base_address = basepriv->conf_data.ned1.unit_addr; | ||
317 | pfxdata->base_lss = basepriv->conf_data.ned1.ID; | ||
318 | pfxdata->validity.define_extend = 1; | ||
319 | |||
320 | /* private uid is kept up to date, conf_data may be outdated */ | ||
321 | if (startpriv->uid.type != UA_BASE_DEVICE) { | ||
322 | pfxdata->validity.verify_base = 1; | ||
323 | if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) | ||
324 | pfxdata->validity.hyper_pav = 1; | ||
325 | } | ||
326 | |||
327 | /* define extend data (mostly)*/ | ||
328 | switch (cmd) { | ||
329 | case DASD_ECKD_CCW_READ_HOME_ADDRESS: | ||
330 | case DASD_ECKD_CCW_READ_RECORD_ZERO: | ||
331 | case DASD_ECKD_CCW_READ: | ||
332 | case DASD_ECKD_CCW_READ_MT: | ||
333 | case DASD_ECKD_CCW_READ_CKD: | ||
334 | case DASD_ECKD_CCW_READ_CKD_MT: | ||
335 | case DASD_ECKD_CCW_READ_KD: | ||
336 | case DASD_ECKD_CCW_READ_KD_MT: | ||
337 | case DASD_ECKD_CCW_READ_COUNT: | ||
338 | data->mask.perm = 0x1; | ||
339 | data->attributes.operation = basepriv->attrib.operation; | ||
340 | break; | ||
341 | case DASD_ECKD_CCW_WRITE: | ||
342 | case DASD_ECKD_CCW_WRITE_MT: | ||
343 | case DASD_ECKD_CCW_WRITE_KD: | ||
344 | case DASD_ECKD_CCW_WRITE_KD_MT: | ||
345 | data->mask.perm = 0x02; | ||
346 | data->attributes.operation = basepriv->attrib.operation; | ||
347 | rc = check_XRC_on_prefix(pfxdata, basedev); | ||
348 | break; | ||
349 | case DASD_ECKD_CCW_WRITE_CKD: | ||
350 | case DASD_ECKD_CCW_WRITE_CKD_MT: | ||
351 | data->attributes.operation = DASD_BYPASS_CACHE; | ||
352 | rc = check_XRC_on_prefix(pfxdata, basedev); | ||
353 | break; | ||
354 | case DASD_ECKD_CCW_ERASE: | ||
355 | case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: | ||
356 | case DASD_ECKD_CCW_WRITE_RECORD_ZERO: | ||
357 | data->mask.perm = 0x3; | ||
358 | data->mask.auth = 0x1; | ||
359 | data->attributes.operation = DASD_BYPASS_CACHE; | ||
360 | rc = check_XRC_on_prefix(pfxdata, basedev); | ||
361 | break; | ||
362 | default: | ||
363 | DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd); | ||
364 | break; | ||
365 | } | ||
366 | |||
367 | data->attributes.mode = 0x3; /* ECKD */ | ||
368 | |||
369 | if ((basepriv->rdc_data.cu_type == 0x2105 || | ||
370 | basepriv->rdc_data.cu_type == 0x2107 || | ||
371 | basepriv->rdc_data.cu_type == 0x1750) | ||
372 | && !(basepriv->uses_cdl && trk < 2)) | ||
373 | data->ga_extended |= 0x40; /* Regular Data Format Mode */ | ||
374 | |||
375 | geo.cyl = basepriv->rdc_data.no_cyl; | ||
376 | geo.head = basepriv->rdc_data.trk_per_cyl; | ||
377 | beg.cyl = trk / geo.head; | ||
378 | beg.head = trk % geo.head; | ||
379 | end.cyl = totrk / geo.head; | ||
380 | end.head = totrk % geo.head; | ||
381 | |||
382 | /* check for sequential prestage - enhance cylinder range */ | ||
383 | if (data->attributes.operation == DASD_SEQ_PRESTAGE || | ||
384 | data->attributes.operation == DASD_SEQ_ACCESS) { | ||
385 | |||
386 | if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl) | ||
387 | end.cyl += basepriv->attrib.nr_cyl; | ||
388 | else | ||
389 | end.cyl = (geo.cyl - 1); | ||
390 | } | ||
391 | |||
392 | data->beg_ext.cyl = beg.cyl; | ||
393 | data->beg_ext.head = beg.head; | ||
394 | data->end_ext.cyl = end.cyl; | ||
395 | data->end_ext.head = end.head; | ||
396 | return rc; | ||
397 | } | ||
398 | |||
283 | static void | 399 | static void |
284 | locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, | 400 | locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, |
285 | int rec_on_trk, int no_rec, int cmd, | 401 | int rec_on_trk, int no_rec, int cmd, |
@@ -300,7 +416,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, | |||
300 | ccw->count = 16; | 416 | ccw->count = 16; |
301 | ccw->cda = (__u32) __pa(data); | 417 | ccw->cda = (__u32) __pa(data); |
302 | 418 | ||
303 | memset(data, 0, sizeof (struct LO_eckd_data)); | 419 | memset(data, 0, sizeof(struct LO_eckd_data)); |
304 | sector = 0; | 420 | sector = 0; |
305 | if (rec_on_trk) { | 421 | if (rec_on_trk) { |
306 | switch (private->rdc_data.dev_type) { | 422 | switch (private->rdc_data.dev_type) { |
@@ -441,12 +557,15 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) | |||
441 | sizeof(uid->serial) - 1); | 557 | sizeof(uid->serial) - 1); |
442 | EBCASC(uid->serial, sizeof(uid->serial) - 1); | 558 | EBCASC(uid->serial, sizeof(uid->serial) - 1); |
443 | uid->ssid = confdata->neq.subsystemID; | 559 | uid->ssid = confdata->neq.subsystemID; |
444 | if (confdata->ned2.sneq.flags == 0x40) { | 560 | uid->real_unit_addr = confdata->ned1.unit_addr; |
445 | uid->alias = 1; | 561 | if (confdata->ned2.sneq.flags == 0x40 && |
446 | uid->unit_addr = confdata->ned2.sneq.base_unit_addr; | 562 | confdata->ned2.sneq.format == 0x0001) { |
447 | } else | 563 | uid->type = confdata->ned2.sneq.sua_flags; |
448 | uid->unit_addr = confdata->ned1.unit_addr; | 564 | if (uid->type == UA_BASE_PAV_ALIAS) |
449 | 565 | uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr; | |
566 | } else { | ||
567 | uid->type = UA_BASE_DEVICE; | ||
568 | } | ||
450 | return 0; | 569 | return 0; |
451 | } | 570 | } |
452 | 571 | ||
@@ -470,7 +589,9 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, | |||
470 | ccw->cda = (__u32)(addr_t)rcd_buffer; | 589 | ccw->cda = (__u32)(addr_t)rcd_buffer; |
471 | ccw->count = ciw->count; | 590 | ccw->count = ciw->count; |
472 | 591 | ||
473 | cqr->device = device; | 592 | cqr->startdev = device; |
593 | cqr->memdev = device; | ||
594 | cqr->block = NULL; | ||
474 | cqr->expires = 10*HZ; | 595 | cqr->expires = 10*HZ; |
475 | cqr->lpm = lpm; | 596 | cqr->lpm = lpm; |
476 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 597 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
@@ -511,7 +632,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, | |||
511 | /* | 632 | /* |
512 | * on success we update the user input parms | 633 | * on success we update the user input parms |
513 | */ | 634 | */ |
514 | dasd_sfree_request(cqr, cqr->device); | 635 | dasd_sfree_request(cqr, cqr->memdev); |
515 | if (ret) | 636 | if (ret) |
516 | goto out_error; | 637 | goto out_error; |
517 | 638 | ||
@@ -557,19 +678,19 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
557 | "data retrieved"); | 678 | "data retrieved"); |
558 | continue; /* no error */ | 679 | continue; /* no error */ |
559 | } | 680 | } |
560 | if (conf_len != sizeof (struct dasd_eckd_confdata)) { | 681 | if (conf_len != sizeof(struct dasd_eckd_confdata)) { |
561 | MESSAGE(KERN_WARNING, | 682 | MESSAGE(KERN_WARNING, |
562 | "sizes of configuration data mismatch" | 683 | "sizes of configuration data mismatch" |
563 | "%d (read) vs %ld (expected)", | 684 | "%d (read) vs %ld (expected)", |
564 | conf_len, | 685 | conf_len, |
565 | sizeof (struct dasd_eckd_confdata)); | 686 | sizeof(struct dasd_eckd_confdata)); |
566 | kfree(conf_data); | 687 | kfree(conf_data); |
567 | continue; /* no error */ | 688 | continue; /* no error */ |
568 | } | 689 | } |
569 | /* save first valid configuration data */ | 690 | /* save first valid configuration data */ |
570 | if (!conf_data_saved){ | 691 | if (!conf_data_saved){ |
571 | memcpy(&private->conf_data, conf_data, | 692 | memcpy(&private->conf_data, conf_data, |
572 | sizeof (struct dasd_eckd_confdata)); | 693 | sizeof(struct dasd_eckd_confdata)); |
573 | conf_data_saved++; | 694 | conf_data_saved++; |
574 | } | 695 | } |
575 | switch (((char *)conf_data)[242] & 0x07){ | 696 | switch (((char *)conf_data)[242] & 0x07){ |
@@ -586,39 +707,104 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
586 | return 0; | 707 | return 0; |
587 | } | 708 | } |
588 | 709 | ||
710 | static int dasd_eckd_read_features(struct dasd_device *device) | ||
711 | { | ||
712 | struct dasd_psf_prssd_data *prssdp; | ||
713 | struct dasd_rssd_features *features; | ||
714 | struct dasd_ccw_req *cqr; | ||
715 | struct ccw1 *ccw; | ||
716 | int rc; | ||
717 | struct dasd_eckd_private *private; | ||
718 | |||
719 | private = (struct dasd_eckd_private *) device->private; | ||
720 | cqr = dasd_smalloc_request(dasd_eckd_discipline.name, | ||
721 | 1 /* PSF */ + 1 /* RSSD */ , | ||
722 | (sizeof(struct dasd_psf_prssd_data) + | ||
723 | sizeof(struct dasd_rssd_features)), | ||
724 | device); | ||
725 | if (IS_ERR(cqr)) { | ||
726 | DEV_MESSAGE(KERN_WARNING, device, "%s", | ||
727 | "Could not allocate initialization request"); | ||
728 | return PTR_ERR(cqr); | ||
729 | } | ||
730 | cqr->startdev = device; | ||
731 | cqr->memdev = device; | ||
732 | cqr->block = NULL; | ||
733 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | ||
734 | cqr->retries = 5; | ||
735 | cqr->expires = 10 * HZ; | ||
736 | |||
737 | /* Prepare for Read Subsystem Data */ | ||
738 | prssdp = (struct dasd_psf_prssd_data *) cqr->data; | ||
739 | memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data)); | ||
740 | prssdp->order = PSF_ORDER_PRSSD; | ||
741 | prssdp->suborder = 0x41; /* Read Feature Codes */ | ||
742 | /* all other bytes of prssdp must be zero */ | ||
743 | |||
744 | ccw = cqr->cpaddr; | ||
745 | ccw->cmd_code = DASD_ECKD_CCW_PSF; | ||
746 | ccw->count = sizeof(struct dasd_psf_prssd_data); | ||
747 | ccw->flags |= CCW_FLAG_CC; | ||
748 | ccw->cda = (__u32)(addr_t) prssdp; | ||
749 | |||
750 | /* Read Subsystem Data - feature codes */ | ||
751 | features = (struct dasd_rssd_features *) (prssdp + 1); | ||
752 | memset(features, 0, sizeof(struct dasd_rssd_features)); | ||
753 | |||
754 | ccw++; | ||
755 | ccw->cmd_code = DASD_ECKD_CCW_RSSD; | ||
756 | ccw->count = sizeof(struct dasd_rssd_features); | ||
757 | ccw->cda = (__u32)(addr_t) features; | ||
758 | |||
759 | cqr->buildclk = get_clock(); | ||
760 | cqr->status = DASD_CQR_FILLED; | ||
761 | rc = dasd_sleep_on(cqr); | ||
762 | if (rc == 0) { | ||
763 | prssdp = (struct dasd_psf_prssd_data *) cqr->data; | ||
764 | features = (struct dasd_rssd_features *) (prssdp + 1); | ||
765 | memcpy(&private->features, features, | ||
766 | sizeof(struct dasd_rssd_features)); | ||
767 | } | ||
768 | dasd_sfree_request(cqr, cqr->memdev); | ||
769 | return rc; | ||
770 | } | ||
771 | |||
772 | |||
589 | /* | 773 | /* |
590 | * Build CP for Perform Subsystem Function - SSC. | 774 | * Build CP for Perform Subsystem Function - SSC. |
591 | */ | 775 | */ |
592 | static struct dasd_ccw_req * | 776 | static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device) |
593 | dasd_eckd_build_psf_ssc(struct dasd_device *device) | ||
594 | { | 777 | { |
595 | struct dasd_ccw_req *cqr; | 778 | struct dasd_ccw_req *cqr; |
596 | struct dasd_psf_ssc_data *psf_ssc_data; | 779 | struct dasd_psf_ssc_data *psf_ssc_data; |
597 | struct ccw1 *ccw; | 780 | struct ccw1 *ccw; |
598 | 781 | ||
599 | cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ , | 782 | cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ , |
600 | sizeof(struct dasd_psf_ssc_data), | 783 | sizeof(struct dasd_psf_ssc_data), |
601 | device); | 784 | device); |
602 | 785 | ||
603 | if (IS_ERR(cqr)) { | 786 | if (IS_ERR(cqr)) { |
604 | DEV_MESSAGE(KERN_WARNING, device, "%s", | 787 | DEV_MESSAGE(KERN_WARNING, device, "%s", |
605 | "Could not allocate PSF-SSC request"); | 788 | "Could not allocate PSF-SSC request"); |
606 | return cqr; | 789 | return cqr; |
607 | } | 790 | } |
608 | psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data; | 791 | psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data; |
609 | psf_ssc_data->order = PSF_ORDER_SSC; | 792 | psf_ssc_data->order = PSF_ORDER_SSC; |
610 | psf_ssc_data->suborder = 0x08; | 793 | psf_ssc_data->suborder = 0x88; |
611 | 794 | psf_ssc_data->reserved[0] = 0x88; | |
612 | ccw = cqr->cpaddr; | 795 | |
613 | ccw->cmd_code = DASD_ECKD_CCW_PSF; | 796 | ccw = cqr->cpaddr; |
614 | ccw->cda = (__u32)(addr_t)psf_ssc_data; | 797 | ccw->cmd_code = DASD_ECKD_CCW_PSF; |
615 | ccw->count = 66; | 798 | ccw->cda = (__u32)(addr_t)psf_ssc_data; |
616 | 799 | ccw->count = 66; | |
617 | cqr->device = device; | 800 | |
618 | cqr->expires = 10*HZ; | 801 | cqr->startdev = device; |
619 | cqr->buildclk = get_clock(); | 802 | cqr->memdev = device; |
620 | cqr->status = DASD_CQR_FILLED; | 803 | cqr->block = NULL; |
621 | return cqr; | 804 | cqr->expires = 10*HZ; |
805 | cqr->buildclk = get_clock(); | ||
806 | cqr->status = DASD_CQR_FILLED; | ||
807 | return cqr; | ||
622 | } | 808 | } |
623 | 809 | ||
624 | /* | 810 | /* |
@@ -629,28 +815,28 @@ dasd_eckd_build_psf_ssc(struct dasd_device *device) | |||
629 | static int | 815 | static int |
630 | dasd_eckd_psf_ssc(struct dasd_device *device) | 816 | dasd_eckd_psf_ssc(struct dasd_device *device) |
631 | { | 817 | { |
632 | struct dasd_ccw_req *cqr; | 818 | struct dasd_ccw_req *cqr; |
633 | int rc; | 819 | int rc; |
634 | 820 | ||
635 | cqr = dasd_eckd_build_psf_ssc(device); | 821 | cqr = dasd_eckd_build_psf_ssc(device); |
636 | if (IS_ERR(cqr)) | 822 | if (IS_ERR(cqr)) |
637 | return PTR_ERR(cqr); | 823 | return PTR_ERR(cqr); |
638 | 824 | ||
639 | rc = dasd_sleep_on(cqr); | 825 | rc = dasd_sleep_on(cqr); |
640 | if (!rc) | 826 | if (!rc) |
641 | /* trigger CIO to reprobe devices */ | 827 | /* trigger CIO to reprobe devices */ |
642 | css_schedule_reprobe(); | 828 | css_schedule_reprobe(); |
643 | dasd_sfree_request(cqr, cqr->device); | 829 | dasd_sfree_request(cqr, cqr->memdev); |
644 | return rc; | 830 | return rc; |
645 | } | 831 | } |
646 | 832 | ||
647 | /* | 833 | /* |
648 | * Valide storage server of current device. | 834 | * Valide storage server of current device. |
649 | */ | 835 | */ |
650 | static int | 836 | static int dasd_eckd_validate_server(struct dasd_device *device) |
651 | dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid) | ||
652 | { | 837 | { |
653 | int rc; | 838 | int rc; |
839 | struct dasd_eckd_private *private; | ||
654 | 840 | ||
655 | /* Currently PAV is the only reason to 'validate' server on LPAR */ | 841 | /* Currently PAV is the only reason to 'validate' server on LPAR */ |
656 | if (dasd_nopav || MACHINE_IS_VM) | 842 | if (dasd_nopav || MACHINE_IS_VM) |
@@ -659,9 +845,11 @@ dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid) | |||
659 | rc = dasd_eckd_psf_ssc(device); | 845 | rc = dasd_eckd_psf_ssc(device); |
660 | /* may be requested feature is not available on server, | 846 | /* may be requested feature is not available on server, |
661 | * therefore just report error and go ahead */ | 847 | * therefore just report error and go ahead */ |
848 | private = (struct dasd_eckd_private *) device->private; | ||
662 | DEV_MESSAGE(KERN_INFO, device, | 849 | DEV_MESSAGE(KERN_INFO, device, |
663 | "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d", | 850 | "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d", |
664 | uid->vendor, uid->serial, uid->ssid, rc); | 851 | private->uid.vendor, private->uid.serial, |
852 | private->uid.ssid, rc); | ||
665 | /* RE-Read Configuration Data */ | 853 | /* RE-Read Configuration Data */ |
666 | return dasd_eckd_read_conf(device); | 854 | return dasd_eckd_read_conf(device); |
667 | } | 855 | } |
@@ -674,9 +862,9 @@ static int | |||
674 | dasd_eckd_check_characteristics(struct dasd_device *device) | 862 | dasd_eckd_check_characteristics(struct dasd_device *device) |
675 | { | 863 | { |
676 | struct dasd_eckd_private *private; | 864 | struct dasd_eckd_private *private; |
677 | struct dasd_uid uid; | 865 | struct dasd_block *block; |
678 | void *rdc_data; | 866 | void *rdc_data; |
679 | int rc; | 867 | int is_known, rc; |
680 | 868 | ||
681 | private = (struct dasd_eckd_private *) device->private; | 869 | private = (struct dasd_eckd_private *) device->private; |
682 | if (private == NULL) { | 870 | if (private == NULL) { |
@@ -699,27 +887,54 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
699 | /* Read Configuration Data */ | 887 | /* Read Configuration Data */ |
700 | rc = dasd_eckd_read_conf(device); | 888 | rc = dasd_eckd_read_conf(device); |
701 | if (rc) | 889 | if (rc) |
702 | return rc; | 890 | goto out_err1; |
703 | 891 | ||
704 | /* Generate device unique id and register in devmap */ | 892 | /* Generate device unique id and register in devmap */ |
705 | rc = dasd_eckd_generate_uid(device, &uid); | 893 | rc = dasd_eckd_generate_uid(device, &private->uid); |
706 | if (rc) | 894 | if (rc) |
707 | return rc; | 895 | goto out_err1; |
708 | rc = dasd_set_uid(device->cdev, &uid); | 896 | dasd_set_uid(device->cdev, &private->uid); |
709 | if (rc == 1) /* new server found */ | 897 | |
710 | rc = dasd_eckd_validate_server(device, &uid); | 898 | if (private->uid.type == UA_BASE_DEVICE) { |
899 | block = dasd_alloc_block(); | ||
900 | if (IS_ERR(block)) { | ||
901 | DEV_MESSAGE(KERN_WARNING, device, "%s", | ||
902 | "could not allocate dasd block structure"); | ||
903 | rc = PTR_ERR(block); | ||
904 | goto out_err1; | ||
905 | } | ||
906 | device->block = block; | ||
907 | block->base = device; | ||
908 | } | ||
909 | |||
910 | /* register lcu with alias handling, enable PAV if this is a new lcu */ | ||
911 | is_known = dasd_alias_make_device_known_to_lcu(device); | ||
912 | if (is_known < 0) { | ||
913 | rc = is_known; | ||
914 | goto out_err2; | ||
915 | } | ||
916 | if (!is_known) { | ||
917 | /* new lcu found */ | ||
918 | rc = dasd_eckd_validate_server(device); /* will switch pav on */ | ||
919 | if (rc) | ||
920 | goto out_err3; | ||
921 | } | ||
922 | |||
923 | /* Read Feature Codes */ | ||
924 | rc = dasd_eckd_read_features(device); | ||
711 | if (rc) | 925 | if (rc) |
712 | return rc; | 926 | goto out_err3; |
713 | 927 | ||
714 | /* Read Device Characteristics */ | 928 | /* Read Device Characteristics */ |
715 | rdc_data = (void *) &(private->rdc_data); | 929 | rdc_data = (void *) &(private->rdc_data); |
716 | memset(rdc_data, 0, sizeof(rdc_data)); | 930 | memset(rdc_data, 0, sizeof(rdc_data)); |
717 | rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64); | 931 | rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64); |
718 | if (rc) | 932 | if (rc) { |
719 | DEV_MESSAGE(KERN_WARNING, device, | 933 | DEV_MESSAGE(KERN_WARNING, device, |
720 | "Read device characteristics returned " | 934 | "Read device characteristics returned " |
721 | "rc=%d", rc); | 935 | "rc=%d", rc); |
722 | 936 | goto out_err3; | |
937 | } | ||
723 | DEV_MESSAGE(KERN_INFO, device, | 938 | DEV_MESSAGE(KERN_INFO, device, |
724 | "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", | 939 | "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", |
725 | private->rdc_data.dev_type, | 940 | private->rdc_data.dev_type, |
@@ -729,9 +944,24 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
729 | private->rdc_data.no_cyl, | 944 | private->rdc_data.no_cyl, |
730 | private->rdc_data.trk_per_cyl, | 945 | private->rdc_data.trk_per_cyl, |
731 | private->rdc_data.sec_per_trk); | 946 | private->rdc_data.sec_per_trk); |
947 | return 0; | ||
948 | |||
949 | out_err3: | ||
950 | dasd_alias_disconnect_device_from_lcu(device); | ||
951 | out_err2: | ||
952 | dasd_free_block(device->block); | ||
953 | device->block = NULL; | ||
954 | out_err1: | ||
955 | kfree(device->private); | ||
956 | device->private = NULL; | ||
732 | return rc; | 957 | return rc; |
733 | } | 958 | } |
734 | 959 | ||
960 | static void dasd_eckd_uncheck_device(struct dasd_device *device) | ||
961 | { | ||
962 | dasd_alias_disconnect_device_from_lcu(device); | ||
963 | } | ||
964 | |||
735 | static struct dasd_ccw_req * | 965 | static struct dasd_ccw_req * |
736 | dasd_eckd_analysis_ccw(struct dasd_device *device) | 966 | dasd_eckd_analysis_ccw(struct dasd_device *device) |
737 | { | 967 | { |
@@ -755,7 +985,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) | |||
755 | /* Define extent for the first 3 tracks. */ | 985 | /* Define extent for the first 3 tracks. */ |
756 | define_extent(ccw++, cqr->data, 0, 2, | 986 | define_extent(ccw++, cqr->data, 0, 2, |
757 | DASD_ECKD_CCW_READ_COUNT, device); | 987 | DASD_ECKD_CCW_READ_COUNT, device); |
758 | LO_data = cqr->data + sizeof (struct DE_eckd_data); | 988 | LO_data = cqr->data + sizeof(struct DE_eckd_data); |
759 | /* Locate record for the first 4 records on track 0. */ | 989 | /* Locate record for the first 4 records on track 0. */ |
760 | ccw[-1].flags |= CCW_FLAG_CC; | 990 | ccw[-1].flags |= CCW_FLAG_CC; |
761 | locate_record(ccw++, LO_data++, 0, 0, 4, | 991 | locate_record(ccw++, LO_data++, 0, 0, 4, |
@@ -783,7 +1013,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) | |||
783 | ccw->count = 8; | 1013 | ccw->count = 8; |
784 | ccw->cda = (__u32)(addr_t) count_data; | 1014 | ccw->cda = (__u32)(addr_t) count_data; |
785 | 1015 | ||
786 | cqr->device = device; | 1016 | cqr->block = NULL; |
1017 | cqr->startdev = device; | ||
1018 | cqr->memdev = device; | ||
787 | cqr->retries = 0; | 1019 | cqr->retries = 0; |
788 | cqr->buildclk = get_clock(); | 1020 | cqr->buildclk = get_clock(); |
789 | cqr->status = DASD_CQR_FILLED; | 1021 | cqr->status = DASD_CQR_FILLED; |
@@ -803,7 +1035,7 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data) | |||
803 | struct dasd_eckd_private *private; | 1035 | struct dasd_eckd_private *private; |
804 | struct dasd_device *device; | 1036 | struct dasd_device *device; |
805 | 1037 | ||
806 | device = init_cqr->device; | 1038 | device = init_cqr->startdev; |
807 | private = (struct dasd_eckd_private *) device->private; | 1039 | private = (struct dasd_eckd_private *) device->private; |
808 | private->init_cqr_status = init_cqr->status; | 1040 | private->init_cqr_status = init_cqr->status; |
809 | dasd_sfree_request(init_cqr, device); | 1041 | dasd_sfree_request(init_cqr, device); |
@@ -811,13 +1043,13 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data) | |||
811 | } | 1043 | } |
812 | 1044 | ||
813 | static int | 1045 | static int |
814 | dasd_eckd_start_analysis(struct dasd_device *device) | 1046 | dasd_eckd_start_analysis(struct dasd_block *block) |
815 | { | 1047 | { |
816 | struct dasd_eckd_private *private; | 1048 | struct dasd_eckd_private *private; |
817 | struct dasd_ccw_req *init_cqr; | 1049 | struct dasd_ccw_req *init_cqr; |
818 | 1050 | ||
819 | private = (struct dasd_eckd_private *) device->private; | 1051 | private = (struct dasd_eckd_private *) block->base->private; |
820 | init_cqr = dasd_eckd_analysis_ccw(device); | 1052 | init_cqr = dasd_eckd_analysis_ccw(block->base); |
821 | if (IS_ERR(init_cqr)) | 1053 | if (IS_ERR(init_cqr)) |
822 | return PTR_ERR(init_cqr); | 1054 | return PTR_ERR(init_cqr); |
823 | init_cqr->callback = dasd_eckd_analysis_callback; | 1055 | init_cqr->callback = dasd_eckd_analysis_callback; |
@@ -828,13 +1060,15 @@ dasd_eckd_start_analysis(struct dasd_device *device) | |||
828 | } | 1060 | } |
829 | 1061 | ||
830 | static int | 1062 | static int |
831 | dasd_eckd_end_analysis(struct dasd_device *device) | 1063 | dasd_eckd_end_analysis(struct dasd_block *block) |
832 | { | 1064 | { |
1065 | struct dasd_device *device; | ||
833 | struct dasd_eckd_private *private; | 1066 | struct dasd_eckd_private *private; |
834 | struct eckd_count *count_area; | 1067 | struct eckd_count *count_area; |
835 | unsigned int sb, blk_per_trk; | 1068 | unsigned int sb, blk_per_trk; |
836 | int status, i; | 1069 | int status, i; |
837 | 1070 | ||
1071 | device = block->base; | ||
838 | private = (struct dasd_eckd_private *) device->private; | 1072 | private = (struct dasd_eckd_private *) device->private; |
839 | status = private->init_cqr_status; | 1073 | status = private->init_cqr_status; |
840 | private->init_cqr_status = -1; | 1074 | private->init_cqr_status = -1; |
@@ -846,7 +1080,7 @@ dasd_eckd_end_analysis(struct dasd_device *device) | |||
846 | 1080 | ||
847 | private->uses_cdl = 1; | 1081 | private->uses_cdl = 1; |
848 | /* Calculate number of blocks/records per track. */ | 1082 | /* Calculate number of blocks/records per track. */ |
849 | blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block); | 1083 | blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); |
850 | /* Check Track 0 for Compatible Disk Layout */ | 1084 | /* Check Track 0 for Compatible Disk Layout */ |
851 | count_area = NULL; | 1085 | count_area = NULL; |
852 | for (i = 0; i < 3; i++) { | 1086 | for (i = 0; i < 3; i++) { |
@@ -876,56 +1110,65 @@ dasd_eckd_end_analysis(struct dasd_device *device) | |||
876 | if (count_area != NULL && count_area->kl == 0) { | 1110 | if (count_area != NULL && count_area->kl == 0) { |
877 | /* we found notthing violating our disk layout */ | 1111 | /* we found notthing violating our disk layout */ |
878 | if (dasd_check_blocksize(count_area->dl) == 0) | 1112 | if (dasd_check_blocksize(count_area->dl) == 0) |
879 | device->bp_block = count_area->dl; | 1113 | block->bp_block = count_area->dl; |
880 | } | 1114 | } |
881 | if (device->bp_block == 0) { | 1115 | if (block->bp_block == 0) { |
882 | DEV_MESSAGE(KERN_WARNING, device, "%s", | 1116 | DEV_MESSAGE(KERN_WARNING, device, "%s", |
883 | "Volume has incompatible disk layout"); | 1117 | "Volume has incompatible disk layout"); |
884 | return -EMEDIUMTYPE; | 1118 | return -EMEDIUMTYPE; |
885 | } | 1119 | } |
886 | device->s2b_shift = 0; /* bits to shift 512 to get a block */ | 1120 | block->s2b_shift = 0; /* bits to shift 512 to get a block */ |
887 | for (sb = 512; sb < device->bp_block; sb = sb << 1) | 1121 | for (sb = 512; sb < block->bp_block; sb = sb << 1) |
888 | device->s2b_shift++; | 1122 | block->s2b_shift++; |
889 | 1123 | ||
890 | blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block); | 1124 | blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); |
891 | device->blocks = (private->rdc_data.no_cyl * | 1125 | block->blocks = (private->rdc_data.no_cyl * |
892 | private->rdc_data.trk_per_cyl * | 1126 | private->rdc_data.trk_per_cyl * |
893 | blk_per_trk); | 1127 | blk_per_trk); |
894 | 1128 | ||
895 | DEV_MESSAGE(KERN_INFO, device, | 1129 | DEV_MESSAGE(KERN_INFO, device, |
896 | "(%dkB blks): %dkB at %dkB/trk %s", | 1130 | "(%dkB blks): %dkB at %dkB/trk %s", |
897 | (device->bp_block >> 10), | 1131 | (block->bp_block >> 10), |
898 | ((private->rdc_data.no_cyl * | 1132 | ((private->rdc_data.no_cyl * |
899 | private->rdc_data.trk_per_cyl * | 1133 | private->rdc_data.trk_per_cyl * |
900 | blk_per_trk * (device->bp_block >> 9)) >> 1), | 1134 | blk_per_trk * (block->bp_block >> 9)) >> 1), |
901 | ((blk_per_trk * device->bp_block) >> 10), | 1135 | ((blk_per_trk * block->bp_block) >> 10), |
902 | private->uses_cdl ? | 1136 | private->uses_cdl ? |
903 | "compatible disk layout" : "linux disk layout"); | 1137 | "compatible disk layout" : "linux disk layout"); |
904 | 1138 | ||
905 | return 0; | 1139 | return 0; |
906 | } | 1140 | } |
907 | 1141 | ||
908 | static int | 1142 | static int dasd_eckd_do_analysis(struct dasd_block *block) |
909 | dasd_eckd_do_analysis(struct dasd_device *device) | ||
910 | { | 1143 | { |
911 | struct dasd_eckd_private *private; | 1144 | struct dasd_eckd_private *private; |
912 | 1145 | ||
913 | private = (struct dasd_eckd_private *) device->private; | 1146 | private = (struct dasd_eckd_private *) block->base->private; |
914 | if (private->init_cqr_status < 0) | 1147 | if (private->init_cqr_status < 0) |
915 | return dasd_eckd_start_analysis(device); | 1148 | return dasd_eckd_start_analysis(block); |
916 | else | 1149 | else |
917 | return dasd_eckd_end_analysis(device); | 1150 | return dasd_eckd_end_analysis(block); |
918 | } | 1151 | } |
919 | 1152 | ||
1153 | static int dasd_eckd_ready_to_online(struct dasd_device *device) | ||
1154 | { | ||
1155 | return dasd_alias_add_device(device); | ||
1156 | }; | ||
1157 | |||
1158 | static int dasd_eckd_online_to_ready(struct dasd_device *device) | ||
1159 | { | ||
1160 | return dasd_alias_remove_device(device); | ||
1161 | }; | ||
1162 | |||
920 | static int | 1163 | static int |
921 | dasd_eckd_fill_geometry(struct dasd_device *device, struct hd_geometry *geo) | 1164 | dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo) |
922 | { | 1165 | { |
923 | struct dasd_eckd_private *private; | 1166 | struct dasd_eckd_private *private; |
924 | 1167 | ||
925 | private = (struct dasd_eckd_private *) device->private; | 1168 | private = (struct dasd_eckd_private *) block->base->private; |
926 | if (dasd_check_blocksize(device->bp_block) == 0) { | 1169 | if (dasd_check_blocksize(block->bp_block) == 0) { |
927 | geo->sectors = recs_per_track(&private->rdc_data, | 1170 | geo->sectors = recs_per_track(&private->rdc_data, |
928 | 0, device->bp_block); | 1171 | 0, block->bp_block); |
929 | } | 1172 | } |
930 | geo->cylinders = private->rdc_data.no_cyl; | 1173 | geo->cylinders = private->rdc_data.no_cyl; |
931 | geo->heads = private->rdc_data.trk_per_cyl; | 1174 | geo->heads = private->rdc_data.trk_per_cyl; |
@@ -1037,7 +1280,7 @@ dasd_eckd_format_device(struct dasd_device * device, | |||
1037 | locate_record(ccw++, (struct LO_eckd_data *) data, | 1280 | locate_record(ccw++, (struct LO_eckd_data *) data, |
1038 | fdata->start_unit, 0, rpt + 1, | 1281 | fdata->start_unit, 0, rpt + 1, |
1039 | DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, | 1282 | DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, |
1040 | device->bp_block); | 1283 | device->block->bp_block); |
1041 | data += sizeof(struct LO_eckd_data); | 1284 | data += sizeof(struct LO_eckd_data); |
1042 | break; | 1285 | break; |
1043 | case 0x04: /* Invalidate track. */ | 1286 | case 0x04: /* Invalidate track. */ |
@@ -1110,43 +1353,28 @@ dasd_eckd_format_device(struct dasd_device * device, | |||
1110 | ccw++; | 1353 | ccw++; |
1111 | } | 1354 | } |
1112 | } | 1355 | } |
1113 | fcp->device = device; | 1356 | fcp->startdev = device; |
1114 | fcp->retries = 2; /* set retry counter to enable ERP */ | 1357 | fcp->memdev = device; |
1358 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags); | ||
1359 | fcp->retries = 5; /* set retry counter to enable default ERP */ | ||
1115 | fcp->buildclk = get_clock(); | 1360 | fcp->buildclk = get_clock(); |
1116 | fcp->status = DASD_CQR_FILLED; | 1361 | fcp->status = DASD_CQR_FILLED; |
1117 | return fcp; | 1362 | return fcp; |
1118 | } | 1363 | } |
1119 | 1364 | ||
1120 | static dasd_era_t | 1365 | static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) |
1121 | dasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb) | ||
1122 | { | 1366 | { |
1123 | struct dasd_device *device = (struct dasd_device *) cqr->device; | 1367 | cqr->status = DASD_CQR_FILLED; |
1124 | struct ccw_device *cdev = device->cdev; | 1368 | if (cqr->block && (cqr->startdev != cqr->block->base)) { |
1125 | 1369 | dasd_eckd_reset_ccw_to_base_io(cqr); | |
1126 | if (irb->scsw.cstat == 0x00 && | 1370 | cqr->startdev = cqr->block->base; |
1127 | irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) | ||
1128 | return dasd_era_none; | ||
1129 | |||
1130 | switch (cdev->id.cu_type) { | ||
1131 | case 0x3990: | ||
1132 | case 0x2105: | ||
1133 | case 0x2107: | ||
1134 | case 0x1750: | ||
1135 | return dasd_3990_erp_examine(cqr, irb); | ||
1136 | case 0x9343: | ||
1137 | return dasd_9343_erp_examine(cqr, irb); | ||
1138 | case 0x3880: | ||
1139 | default: | ||
1140 | DEV_MESSAGE(KERN_WARNING, device, "%s", | ||
1141 | "default (unknown CU type) - RECOVERABLE return"); | ||
1142 | return dasd_era_recover; | ||
1143 | } | 1371 | } |
1144 | } | 1372 | }; |
1145 | 1373 | ||
1146 | static dasd_erp_fn_t | 1374 | static dasd_erp_fn_t |
1147 | dasd_eckd_erp_action(struct dasd_ccw_req * cqr) | 1375 | dasd_eckd_erp_action(struct dasd_ccw_req * cqr) |
1148 | { | 1376 | { |
1149 | struct dasd_device *device = (struct dasd_device *) cqr->device; | 1377 | struct dasd_device *device = (struct dasd_device *) cqr->startdev; |
1150 | struct ccw_device *cdev = device->cdev; | 1378 | struct ccw_device *cdev = device->cdev; |
1151 | 1379 | ||
1152 | switch (cdev->id.cu_type) { | 1380 | switch (cdev->id.cu_type) { |
@@ -1168,8 +1396,37 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr) | |||
1168 | return dasd_default_erp_postaction; | 1396 | return dasd_default_erp_postaction; |
1169 | } | 1397 | } |
1170 | 1398 | ||
1171 | static struct dasd_ccw_req * | 1399 | |
1172 | dasd_eckd_build_cp(struct dasd_device * device, struct request *req) | 1400 | static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, |
1401 | struct irb *irb) | ||
1402 | { | ||
1403 | char mask; | ||
1404 | |||
1405 | /* first of all check for state change pending interrupt */ | ||
1406 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; | ||
1407 | if ((irb->scsw.dstat & mask) == mask) { | ||
1408 | dasd_generic_handle_state_change(device); | ||
1409 | return; | ||
1410 | } | ||
1411 | |||
1412 | /* summary unit check */ | ||
1413 | if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) { | ||
1414 | dasd_alias_handle_summary_unit_check(device, irb); | ||
1415 | return; | ||
1416 | } | ||
1417 | |||
1418 | /* just report other unsolicited interrupts */ | ||
1419 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | ||
1420 | "unsolicited interrupt received"); | ||
1421 | device->discipline->dump_sense(device, NULL, irb); | ||
1422 | dasd_schedule_device_bh(device); | ||
1423 | |||
1424 | return; | ||
1425 | }; | ||
1426 | |||
1427 | static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, | ||
1428 | struct dasd_block *block, | ||
1429 | struct request *req) | ||
1173 | { | 1430 | { |
1174 | struct dasd_eckd_private *private; | 1431 | struct dasd_eckd_private *private; |
1175 | unsigned long *idaws; | 1432 | unsigned long *idaws; |
@@ -1185,8 +1442,11 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) | |||
1185 | sector_t first_trk, last_trk; | 1442 | sector_t first_trk, last_trk; |
1186 | unsigned int first_offs, last_offs; | 1443 | unsigned int first_offs, last_offs; |
1187 | unsigned char cmd, rcmd; | 1444 | unsigned char cmd, rcmd; |
1445 | int use_prefix; | ||
1446 | struct dasd_device *basedev; | ||
1188 | 1447 | ||
1189 | private = (struct dasd_eckd_private *) device->private; | 1448 | basedev = block->base; |
1449 | private = (struct dasd_eckd_private *) basedev->private; | ||
1190 | if (rq_data_dir(req) == READ) | 1450 | if (rq_data_dir(req) == READ) |
1191 | cmd = DASD_ECKD_CCW_READ_MT; | 1451 | cmd = DASD_ECKD_CCW_READ_MT; |
1192 | else if (rq_data_dir(req) == WRITE) | 1452 | else if (rq_data_dir(req) == WRITE) |
@@ -1194,13 +1454,13 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) | |||
1194 | else | 1454 | else |
1195 | return ERR_PTR(-EINVAL); | 1455 | return ERR_PTR(-EINVAL); |
1196 | /* Calculate number of blocks/records per track. */ | 1456 | /* Calculate number of blocks/records per track. */ |
1197 | blksize = device->bp_block; | 1457 | blksize = block->bp_block; |
1198 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); | 1458 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); |
1199 | /* Calculate record id of first and last block. */ | 1459 | /* Calculate record id of first and last block. */ |
1200 | first_rec = first_trk = req->sector >> device->s2b_shift; | 1460 | first_rec = first_trk = req->sector >> block->s2b_shift; |
1201 | first_offs = sector_div(first_trk, blk_per_trk); | 1461 | first_offs = sector_div(first_trk, blk_per_trk); |
1202 | last_rec = last_trk = | 1462 | last_rec = last_trk = |
1203 | (req->sector + req->nr_sectors - 1) >> device->s2b_shift; | 1463 | (req->sector + req->nr_sectors - 1) >> block->s2b_shift; |
1204 | last_offs = sector_div(last_trk, blk_per_trk); | 1464 | last_offs = sector_div(last_trk, blk_per_trk); |
1205 | /* Check struct bio and count the number of blocks for the request. */ | 1465 | /* Check struct bio and count the number of blocks for the request. */ |
1206 | count = 0; | 1466 | count = 0; |
@@ -1209,20 +1469,33 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) | |||
1209 | if (bv->bv_len & (blksize - 1)) | 1469 | if (bv->bv_len & (blksize - 1)) |
1210 | /* Eckd can only do full blocks. */ | 1470 | /* Eckd can only do full blocks. */ |
1211 | return ERR_PTR(-EINVAL); | 1471 | return ERR_PTR(-EINVAL); |
1212 | count += bv->bv_len >> (device->s2b_shift + 9); | 1472 | count += bv->bv_len >> (block->s2b_shift + 9); |
1213 | #if defined(CONFIG_64BIT) | 1473 | #if defined(CONFIG_64BIT) |
1214 | if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) | 1474 | if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) |
1215 | cidaw += bv->bv_len >> (device->s2b_shift + 9); | 1475 | cidaw += bv->bv_len >> (block->s2b_shift + 9); |
1216 | #endif | 1476 | #endif |
1217 | } | 1477 | } |
1218 | /* Paranoia. */ | 1478 | /* Paranoia. */ |
1219 | if (count != last_rec - first_rec + 1) | 1479 | if (count != last_rec - first_rec + 1) |
1220 | return ERR_PTR(-EINVAL); | 1480 | return ERR_PTR(-EINVAL); |
1221 | /* 1x define extent + 1x locate record + number of blocks */ | 1481 | |
1222 | cplength = 2 + count; | 1482 | /* use the prefix command if available */ |
1223 | /* 1x define extent + 1x locate record + cidaws*sizeof(long) */ | 1483 | use_prefix = private->features.feature[8] & 0x01; |
1224 | datasize = sizeof(struct DE_eckd_data) + sizeof(struct LO_eckd_data) + | 1484 | if (use_prefix) { |
1225 | cidaw * sizeof(unsigned long); | 1485 | /* 1x prefix + number of blocks */ |
1486 | cplength = 2 + count; | ||
1487 | /* 1x prefix + cidaws*sizeof(long) */ | ||
1488 | datasize = sizeof(struct PFX_eckd_data) + | ||
1489 | sizeof(struct LO_eckd_data) + | ||
1490 | cidaw * sizeof(unsigned long); | ||
1491 | } else { | ||
1492 | /* 1x define extent + 1x locate record + number of blocks */ | ||
1493 | cplength = 2 + count; | ||
1494 | /* 1x define extent + 1x locate record + cidaws*sizeof(long) */ | ||
1495 | datasize = sizeof(struct DE_eckd_data) + | ||
1496 | sizeof(struct LO_eckd_data) + | ||
1497 | cidaw * sizeof(unsigned long); | ||
1498 | } | ||
1226 | /* Find out the number of additional locate record ccws for cdl. */ | 1499 | /* Find out the number of additional locate record ccws for cdl. */ |
1227 | if (private->uses_cdl && first_rec < 2*blk_per_trk) { | 1500 | if (private->uses_cdl && first_rec < 2*blk_per_trk) { |
1228 | if (last_rec >= 2*blk_per_trk) | 1501 | if (last_rec >= 2*blk_per_trk) |
@@ -1232,26 +1505,42 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) | |||
1232 | } | 1505 | } |
1233 | /* Allocate the ccw request. */ | 1506 | /* Allocate the ccw request. */ |
1234 | cqr = dasd_smalloc_request(dasd_eckd_discipline.name, | 1507 | cqr = dasd_smalloc_request(dasd_eckd_discipline.name, |
1235 | cplength, datasize, device); | 1508 | cplength, datasize, startdev); |
1236 | if (IS_ERR(cqr)) | 1509 | if (IS_ERR(cqr)) |
1237 | return cqr; | 1510 | return cqr; |
1238 | ccw = cqr->cpaddr; | 1511 | ccw = cqr->cpaddr; |
1239 | /* First ccw is define extent. */ | 1512 | /* First ccw is define extent or prefix. */ |
1240 | if (define_extent(ccw++, cqr->data, first_trk, | 1513 | if (use_prefix) { |
1241 | last_trk, cmd, device) == -EAGAIN) { | 1514 | if (prefix(ccw++, cqr->data, first_trk, |
1242 | /* Clock not in sync and XRC is enabled. Try again later. */ | 1515 | last_trk, cmd, basedev, startdev) == -EAGAIN) { |
1243 | dasd_sfree_request(cqr, device); | 1516 | /* Clock not in sync and XRC is enabled. |
1244 | return ERR_PTR(-EAGAIN); | 1517 | * Try again later. |
1518 | */ | ||
1519 | dasd_sfree_request(cqr, startdev); | ||
1520 | return ERR_PTR(-EAGAIN); | ||
1521 | } | ||
1522 | idaws = (unsigned long *) (cqr->data + | ||
1523 | sizeof(struct PFX_eckd_data)); | ||
1524 | } else { | ||
1525 | if (define_extent(ccw++, cqr->data, first_trk, | ||
1526 | last_trk, cmd, startdev) == -EAGAIN) { | ||
1527 | /* Clock not in sync and XRC is enabled. | ||
1528 | * Try again later. | ||
1529 | */ | ||
1530 | dasd_sfree_request(cqr, startdev); | ||
1531 | return ERR_PTR(-EAGAIN); | ||
1532 | } | ||
1533 | idaws = (unsigned long *) (cqr->data + | ||
1534 | sizeof(struct DE_eckd_data)); | ||
1245 | } | 1535 | } |
1246 | /* Build locate_record+read/write/ccws. */ | 1536 | /* Build locate_record+read/write/ccws. */ |
1247 | idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data)); | ||
1248 | LO_data = (struct LO_eckd_data *) (idaws + cidaw); | 1537 | LO_data = (struct LO_eckd_data *) (idaws + cidaw); |
1249 | recid = first_rec; | 1538 | recid = first_rec; |
1250 | if (private->uses_cdl == 0 || recid > 2*blk_per_trk) { | 1539 | if (private->uses_cdl == 0 || recid > 2*blk_per_trk) { |
1251 | /* Only standard blocks so there is just one locate record. */ | 1540 | /* Only standard blocks so there is just one locate record. */ |
1252 | ccw[-1].flags |= CCW_FLAG_CC; | 1541 | ccw[-1].flags |= CCW_FLAG_CC; |
1253 | locate_record(ccw++, LO_data++, first_trk, first_offs + 1, | 1542 | locate_record(ccw++, LO_data++, first_trk, first_offs + 1, |
1254 | last_rec - recid + 1, cmd, device, blksize); | 1543 | last_rec - recid + 1, cmd, basedev, blksize); |
1255 | } | 1544 | } |
1256 | rq_for_each_segment(bv, req, iter) { | 1545 | rq_for_each_segment(bv, req, iter) { |
1257 | dst = page_address(bv->bv_page) + bv->bv_offset; | 1546 | dst = page_address(bv->bv_page) + bv->bv_offset; |
@@ -1281,7 +1570,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) | |||
1281 | ccw[-1].flags |= CCW_FLAG_CC; | 1570 | ccw[-1].flags |= CCW_FLAG_CC; |
1282 | locate_record(ccw++, LO_data++, | 1571 | locate_record(ccw++, LO_data++, |
1283 | trkid, recoffs + 1, | 1572 | trkid, recoffs + 1, |
1284 | 1, rcmd, device, count); | 1573 | 1, rcmd, basedev, count); |
1285 | } | 1574 | } |
1286 | /* Locate record for standard blocks ? */ | 1575 | /* Locate record for standard blocks ? */ |
1287 | if (private->uses_cdl && recid == 2*blk_per_trk) { | 1576 | if (private->uses_cdl && recid == 2*blk_per_trk) { |
@@ -1289,7 +1578,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) | |||
1289 | locate_record(ccw++, LO_data++, | 1578 | locate_record(ccw++, LO_data++, |
1290 | trkid, recoffs + 1, | 1579 | trkid, recoffs + 1, |
1291 | last_rec - recid + 1, | 1580 | last_rec - recid + 1, |
1292 | cmd, device, count); | 1581 | cmd, basedev, count); |
1293 | } | 1582 | } |
1294 | /* Read/write ccw. */ | 1583 | /* Read/write ccw. */ |
1295 | ccw[-1].flags |= CCW_FLAG_CC; | 1584 | ccw[-1].flags |= CCW_FLAG_CC; |
@@ -1310,7 +1599,9 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) | |||
1310 | } | 1599 | } |
1311 | if (req->cmd_flags & REQ_FAILFAST) | 1600 | if (req->cmd_flags & REQ_FAILFAST) |
1312 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | 1601 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); |
1313 | cqr->device = device; | 1602 | cqr->startdev = startdev; |
1603 | cqr->memdev = startdev; | ||
1604 | cqr->block = block; | ||
1314 | cqr->expires = 5 * 60 * HZ; /* 5 minutes */ | 1605 | cqr->expires = 5 * 60 * HZ; /* 5 minutes */ |
1315 | cqr->lpm = private->path_data.ppm; | 1606 | cqr->lpm = private->path_data.ppm; |
1316 | cqr->retries = 256; | 1607 | cqr->retries = 256; |
@@ -1333,10 +1624,10 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) | |||
1333 | 1624 | ||
1334 | if (!dasd_page_cache) | 1625 | if (!dasd_page_cache) |
1335 | goto out; | 1626 | goto out; |
1336 | private = (struct dasd_eckd_private *) cqr->device->private; | 1627 | private = (struct dasd_eckd_private *) cqr->block->base->private; |
1337 | blksize = cqr->device->bp_block; | 1628 | blksize = cqr->block->bp_block; |
1338 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); | 1629 | blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); |
1339 | recid = req->sector >> cqr->device->s2b_shift; | 1630 | recid = req->sector >> cqr->block->s2b_shift; |
1340 | ccw = cqr->cpaddr; | 1631 | ccw = cqr->cpaddr; |
1341 | /* Skip over define extent & locate record. */ | 1632 | /* Skip over define extent & locate record. */ |
1342 | ccw++; | 1633 | ccw++; |
@@ -1367,10 +1658,71 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) | |||
1367 | } | 1658 | } |
1368 | out: | 1659 | out: |
1369 | status = cqr->status == DASD_CQR_DONE; | 1660 | status = cqr->status == DASD_CQR_DONE; |
1370 | dasd_sfree_request(cqr, cqr->device); | 1661 | dasd_sfree_request(cqr, cqr->memdev); |
1371 | return status; | 1662 | return status; |
1372 | } | 1663 | } |
1373 | 1664 | ||
1665 | /* | ||
1666 | * Modify ccw chain in cqr so it can be started on a base device. | ||
1667 | * | ||
1668 | * Note that this is not enough to restart the cqr! | ||
1669 | * Either reset cqr->startdev as well (summary unit check handling) | ||
1670 | * or restart via separate cqr (as in ERP handling). | ||
1671 | */ | ||
1672 | void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr) | ||
1673 | { | ||
1674 | struct ccw1 *ccw; | ||
1675 | struct PFX_eckd_data *pfxdata; | ||
1676 | |||
1677 | ccw = cqr->cpaddr; | ||
1678 | pfxdata = cqr->data; | ||
1679 | |||
1680 | if (ccw->cmd_code == DASD_ECKD_CCW_PFX) { | ||
1681 | pfxdata->validity.verify_base = 0; | ||
1682 | pfxdata->validity.hyper_pav = 0; | ||
1683 | } | ||
1684 | } | ||
1685 | |||
1686 | #define DASD_ECKD_CHANQ_MAX_SIZE 4 | ||
1687 | |||
1688 | static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base, | ||
1689 | struct dasd_block *block, | ||
1690 | struct request *req) | ||
1691 | { | ||
1692 | struct dasd_eckd_private *private; | ||
1693 | struct dasd_device *startdev; | ||
1694 | unsigned long flags; | ||
1695 | struct dasd_ccw_req *cqr; | ||
1696 | |||
1697 | startdev = dasd_alias_get_start_dev(base); | ||
1698 | if (!startdev) | ||
1699 | startdev = base; | ||
1700 | private = (struct dasd_eckd_private *) startdev->private; | ||
1701 | if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE) | ||
1702 | return ERR_PTR(-EBUSY); | ||
1703 | |||
1704 | spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags); | ||
1705 | private->count++; | ||
1706 | cqr = dasd_eckd_build_cp(startdev, block, req); | ||
1707 | if (IS_ERR(cqr)) | ||
1708 | private->count--; | ||
1709 | spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags); | ||
1710 | return cqr; | ||
1711 | } | ||
1712 | |||
1713 | static int dasd_eckd_free_alias_cp(struct dasd_ccw_req *cqr, | ||
1714 | struct request *req) | ||
1715 | { | ||
1716 | struct dasd_eckd_private *private; | ||
1717 | unsigned long flags; | ||
1718 | |||
1719 | spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags); | ||
1720 | private = (struct dasd_eckd_private *) cqr->memdev->private; | ||
1721 | private->count--; | ||
1722 | spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags); | ||
1723 | return dasd_eckd_free_cp(cqr, req); | ||
1724 | } | ||
1725 | |||
1374 | static int | 1726 | static int |
1375 | dasd_eckd_fill_info(struct dasd_device * device, | 1727 | dasd_eckd_fill_info(struct dasd_device * device, |
1376 | struct dasd_information2_t * info) | 1728 | struct dasd_information2_t * info) |
@@ -1384,9 +1736,9 @@ dasd_eckd_fill_info(struct dasd_device * device, | |||
1384 | info->characteristics_size = sizeof(struct dasd_eckd_characteristics); | 1736 | info->characteristics_size = sizeof(struct dasd_eckd_characteristics); |
1385 | memcpy(info->characteristics, &private->rdc_data, | 1737 | memcpy(info->characteristics, &private->rdc_data, |
1386 | sizeof(struct dasd_eckd_characteristics)); | 1738 | sizeof(struct dasd_eckd_characteristics)); |
1387 | info->confdata_size = sizeof (struct dasd_eckd_confdata); | 1739 | info->confdata_size = sizeof(struct dasd_eckd_confdata); |
1388 | memcpy(info->configuration_data, &private->conf_data, | 1740 | memcpy(info->configuration_data, &private->conf_data, |
1389 | sizeof (struct dasd_eckd_confdata)); | 1741 | sizeof(struct dasd_eckd_confdata)); |
1390 | return 0; | 1742 | return 0; |
1391 | } | 1743 | } |
1392 | 1744 | ||
@@ -1419,7 +1771,8 @@ dasd_eckd_release(struct dasd_device *device) | |||
1419 | cqr->cpaddr->flags |= CCW_FLAG_SLI; | 1771 | cqr->cpaddr->flags |= CCW_FLAG_SLI; |
1420 | cqr->cpaddr->count = 32; | 1772 | cqr->cpaddr->count = 32; |
1421 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; | 1773 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; |
1422 | cqr->device = device; | 1774 | cqr->startdev = device; |
1775 | cqr->memdev = device; | ||
1423 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 1776 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
1424 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | 1777 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); |
1425 | cqr->retries = 2; /* set retry counter to enable basic ERP */ | 1778 | cqr->retries = 2; /* set retry counter to enable basic ERP */ |
@@ -1429,7 +1782,7 @@ dasd_eckd_release(struct dasd_device *device) | |||
1429 | 1782 | ||
1430 | rc = dasd_sleep_on_immediatly(cqr); | 1783 | rc = dasd_sleep_on_immediatly(cqr); |
1431 | 1784 | ||
1432 | dasd_sfree_request(cqr, cqr->device); | 1785 | dasd_sfree_request(cqr, cqr->memdev); |
1433 | return rc; | 1786 | return rc; |
1434 | } | 1787 | } |
1435 | 1788 | ||
@@ -1459,7 +1812,8 @@ dasd_eckd_reserve(struct dasd_device *device) | |||
1459 | cqr->cpaddr->flags |= CCW_FLAG_SLI; | 1812 | cqr->cpaddr->flags |= CCW_FLAG_SLI; |
1460 | cqr->cpaddr->count = 32; | 1813 | cqr->cpaddr->count = 32; |
1461 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; | 1814 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; |
1462 | cqr->device = device; | 1815 | cqr->startdev = device; |
1816 | cqr->memdev = device; | ||
1463 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 1817 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
1464 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | 1818 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); |
1465 | cqr->retries = 2; /* set retry counter to enable basic ERP */ | 1819 | cqr->retries = 2; /* set retry counter to enable basic ERP */ |
@@ -1469,7 +1823,7 @@ dasd_eckd_reserve(struct dasd_device *device) | |||
1469 | 1823 | ||
1470 | rc = dasd_sleep_on_immediatly(cqr); | 1824 | rc = dasd_sleep_on_immediatly(cqr); |
1471 | 1825 | ||
1472 | dasd_sfree_request(cqr, cqr->device); | 1826 | dasd_sfree_request(cqr, cqr->memdev); |
1473 | return rc; | 1827 | return rc; |
1474 | } | 1828 | } |
1475 | 1829 | ||
@@ -1498,7 +1852,8 @@ dasd_eckd_steal_lock(struct dasd_device *device) | |||
1498 | cqr->cpaddr->flags |= CCW_FLAG_SLI; | 1852 | cqr->cpaddr->flags |= CCW_FLAG_SLI; |
1499 | cqr->cpaddr->count = 32; | 1853 | cqr->cpaddr->count = 32; |
1500 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; | 1854 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; |
1501 | cqr->device = device; | 1855 | cqr->startdev = device; |
1856 | cqr->memdev = device; | ||
1502 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 1857 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
1503 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | 1858 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); |
1504 | cqr->retries = 2; /* set retry counter to enable basic ERP */ | 1859 | cqr->retries = 2; /* set retry counter to enable basic ERP */ |
@@ -1508,7 +1863,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) | |||
1508 | 1863 | ||
1509 | rc = dasd_sleep_on_immediatly(cqr); | 1864 | rc = dasd_sleep_on_immediatly(cqr); |
1510 | 1865 | ||
1511 | dasd_sfree_request(cqr, cqr->device); | 1866 | dasd_sfree_request(cqr, cqr->memdev); |
1512 | return rc; | 1867 | return rc; |
1513 | } | 1868 | } |
1514 | 1869 | ||
@@ -1526,52 +1881,52 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp) | |||
1526 | 1881 | ||
1527 | cqr = dasd_smalloc_request(dasd_eckd_discipline.name, | 1882 | cqr = dasd_smalloc_request(dasd_eckd_discipline.name, |
1528 | 1 /* PSF */ + 1 /* RSSD */ , | 1883 | 1 /* PSF */ + 1 /* RSSD */ , |
1529 | (sizeof (struct dasd_psf_prssd_data) + | 1884 | (sizeof(struct dasd_psf_prssd_data) + |
1530 | sizeof (struct dasd_rssd_perf_stats_t)), | 1885 | sizeof(struct dasd_rssd_perf_stats_t)), |
1531 | device); | 1886 | device); |
1532 | if (IS_ERR(cqr)) { | 1887 | if (IS_ERR(cqr)) { |
1533 | DEV_MESSAGE(KERN_WARNING, device, "%s", | 1888 | DEV_MESSAGE(KERN_WARNING, device, "%s", |
1534 | "Could not allocate initialization request"); | 1889 | "Could not allocate initialization request"); |
1535 | return PTR_ERR(cqr); | 1890 | return PTR_ERR(cqr); |
1536 | } | 1891 | } |
1537 | cqr->device = device; | 1892 | cqr->startdev = device; |
1893 | cqr->memdev = device; | ||
1538 | cqr->retries = 0; | 1894 | cqr->retries = 0; |
1539 | cqr->expires = 10 * HZ; | 1895 | cqr->expires = 10 * HZ; |
1540 | 1896 | ||
1541 | /* Prepare for Read Subsystem Data */ | 1897 | /* Prepare for Read Subsystem Data */ |
1542 | prssdp = (struct dasd_psf_prssd_data *) cqr->data; | 1898 | prssdp = (struct dasd_psf_prssd_data *) cqr->data; |
1543 | memset(prssdp, 0, sizeof (struct dasd_psf_prssd_data)); | 1899 | memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data)); |
1544 | prssdp->order = PSF_ORDER_PRSSD; | 1900 | prssdp->order = PSF_ORDER_PRSSD; |
1545 | prssdp->suborder = 0x01; /* Performance Statistics */ | 1901 | prssdp->suborder = 0x01; /* Performance Statistics */ |
1546 | prssdp->varies[1] = 0x01; /* Perf Statistics for the Subsystem */ | 1902 | prssdp->varies[1] = 0x01; /* Perf Statistics for the Subsystem */ |
1547 | 1903 | ||
1548 | ccw = cqr->cpaddr; | 1904 | ccw = cqr->cpaddr; |
1549 | ccw->cmd_code = DASD_ECKD_CCW_PSF; | 1905 | ccw->cmd_code = DASD_ECKD_CCW_PSF; |
1550 | ccw->count = sizeof (struct dasd_psf_prssd_data); | 1906 | ccw->count = sizeof(struct dasd_psf_prssd_data); |
1551 | ccw->flags |= CCW_FLAG_CC; | 1907 | ccw->flags |= CCW_FLAG_CC; |
1552 | ccw->cda = (__u32)(addr_t) prssdp; | 1908 | ccw->cda = (__u32)(addr_t) prssdp; |
1553 | 1909 | ||
1554 | /* Read Subsystem Data - Performance Statistics */ | 1910 | /* Read Subsystem Data - Performance Statistics */ |
1555 | stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); | 1911 | stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); |
1556 | memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t)); | 1912 | memset(stats, 0, sizeof(struct dasd_rssd_perf_stats_t)); |
1557 | 1913 | ||
1558 | ccw++; | 1914 | ccw++; |
1559 | ccw->cmd_code = DASD_ECKD_CCW_RSSD; | 1915 | ccw->cmd_code = DASD_ECKD_CCW_RSSD; |
1560 | ccw->count = sizeof (struct dasd_rssd_perf_stats_t); | 1916 | ccw->count = sizeof(struct dasd_rssd_perf_stats_t); |
1561 | ccw->cda = (__u32)(addr_t) stats; | 1917 | ccw->cda = (__u32)(addr_t) stats; |
1562 | 1918 | ||
1563 | cqr->buildclk = get_clock(); | 1919 | cqr->buildclk = get_clock(); |
1564 | cqr->status = DASD_CQR_FILLED; | 1920 | cqr->status = DASD_CQR_FILLED; |
1565 | rc = dasd_sleep_on(cqr); | 1921 | rc = dasd_sleep_on(cqr); |
1566 | if (rc == 0) { | 1922 | if (rc == 0) { |
1567 | /* Prepare for Read Subsystem Data */ | ||
1568 | prssdp = (struct dasd_psf_prssd_data *) cqr->data; | 1923 | prssdp = (struct dasd_psf_prssd_data *) cqr->data; |
1569 | stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); | 1924 | stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); |
1570 | if (copy_to_user(argp, stats, | 1925 | if (copy_to_user(argp, stats, |
1571 | sizeof(struct dasd_rssd_perf_stats_t))) | 1926 | sizeof(struct dasd_rssd_perf_stats_t))) |
1572 | rc = -EFAULT; | 1927 | rc = -EFAULT; |
1573 | } | 1928 | } |
1574 | dasd_sfree_request(cqr, cqr->device); | 1929 | dasd_sfree_request(cqr, cqr->memdev); |
1575 | return rc; | 1930 | return rc; |
1576 | } | 1931 | } |
1577 | 1932 | ||
@@ -1594,7 +1949,7 @@ dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp) | |||
1594 | 1949 | ||
1595 | rc = 0; | 1950 | rc = 0; |
1596 | if (copy_to_user(argp, (long *) &attrib, | 1951 | if (copy_to_user(argp, (long *) &attrib, |
1597 | sizeof (struct attrib_data_t))) | 1952 | sizeof(struct attrib_data_t))) |
1598 | rc = -EFAULT; | 1953 | rc = -EFAULT; |
1599 | 1954 | ||
1600 | return rc; | 1955 | return rc; |
@@ -1627,8 +1982,10 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp) | |||
1627 | } | 1982 | } |
1628 | 1983 | ||
1629 | static int | 1984 | static int |
1630 | dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp) | 1985 | dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) |
1631 | { | 1986 | { |
1987 | struct dasd_device *device = block->base; | ||
1988 | |||
1632 | switch (cmd) { | 1989 | switch (cmd) { |
1633 | case BIODASDGATTR: | 1990 | case BIODASDGATTR: |
1634 | return dasd_eckd_get_attrib(device, argp); | 1991 | return dasd_eckd_get_attrib(device, argp); |
@@ -1685,9 +2042,8 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) | |||
1685 | * Print sense data and related channel program. | 2042 | * Print sense data and related channel program. |
1686 | * Parts are printed because printk buffer is only 1024 bytes. | 2043 | * Parts are printed because printk buffer is only 1024 bytes. |
1687 | */ | 2044 | */ |
1688 | static void | 2045 | static void dasd_eckd_dump_sense(struct dasd_device *device, |
1689 | dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, | 2046 | struct dasd_ccw_req *req, struct irb *irb) |
1690 | struct irb *irb) | ||
1691 | { | 2047 | { |
1692 | char *page; | 2048 | char *page; |
1693 | struct ccw1 *first, *last, *fail, *from, *to; | 2049 | struct ccw1 *first, *last, *fail, *from, *to; |
@@ -1743,37 +2099,40 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, | |||
1743 | } | 2099 | } |
1744 | printk("%s", page); | 2100 | printk("%s", page); |
1745 | 2101 | ||
1746 | /* dump the Channel Program (max 140 Bytes per line) */ | 2102 | if (req) { |
1747 | /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */ | 2103 | /* req == NULL for unsolicited interrupts */ |
1748 | first = req->cpaddr; | 2104 | /* dump the Channel Program (max 140 Bytes per line) */ |
1749 | for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++); | 2105 | /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */ |
1750 | to = min(first + 6, last); | 2106 | first = req->cpaddr; |
1751 | len = sprintf(page, KERN_ERR PRINTK_HEADER | 2107 | for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++); |
1752 | " Related CP in req: %p\n", req); | 2108 | to = min(first + 6, last); |
1753 | dasd_eckd_dump_ccw_range(first, to, page + len); | 2109 | len = sprintf(page, KERN_ERR PRINTK_HEADER |
1754 | printk("%s", page); | 2110 | " Related CP in req: %p\n", req); |
2111 | dasd_eckd_dump_ccw_range(first, to, page + len); | ||
2112 | printk("%s", page); | ||
1755 | 2113 | ||
1756 | /* print failing CCW area (maximum 4) */ | 2114 | /* print failing CCW area (maximum 4) */ |
1757 | /* scsw->cda is either valid or zero */ | 2115 | /* scsw->cda is either valid or zero */ |
1758 | len = 0; | 2116 | len = 0; |
1759 | from = ++to; | 2117 | from = ++to; |
1760 | fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */ | 2118 | fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */ |
1761 | if (from < fail - 2) { | 2119 | if (from < fail - 2) { |
1762 | from = fail - 2; /* there is a gap - print header */ | 2120 | from = fail - 2; /* there is a gap - print header */ |
1763 | len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n"); | 2121 | len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n"); |
1764 | } | 2122 | } |
1765 | to = min(fail + 1, last); | 2123 | to = min(fail + 1, last); |
1766 | len += dasd_eckd_dump_ccw_range(from, to, page + len); | 2124 | len += dasd_eckd_dump_ccw_range(from, to, page + len); |
1767 | 2125 | ||
1768 | /* print last CCWs (maximum 2) */ | 2126 | /* print last CCWs (maximum 2) */ |
1769 | from = max(from, ++to); | 2127 | from = max(from, ++to); |
1770 | if (from < last - 1) { | 2128 | if (from < last - 1) { |
1771 | from = last - 1; /* there is a gap - print header */ | 2129 | from = last - 1; /* there is a gap - print header */ |
1772 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); | 2130 | len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); |
2131 | } | ||
2132 | len += dasd_eckd_dump_ccw_range(from, last, page + len); | ||
2133 | if (len > 0) | ||
2134 | printk("%s", page); | ||
1773 | } | 2135 | } |
1774 | len += dasd_eckd_dump_ccw_range(from, last, page + len); | ||
1775 | if (len > 0) | ||
1776 | printk("%s", page); | ||
1777 | free_page((unsigned long) page); | 2136 | free_page((unsigned long) page); |
1778 | } | 2137 | } |
1779 | 2138 | ||
@@ -1796,16 +2155,20 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
1796 | .ebcname = "ECKD", | 2155 | .ebcname = "ECKD", |
1797 | .max_blocks = 240, | 2156 | .max_blocks = 240, |
1798 | .check_device = dasd_eckd_check_characteristics, | 2157 | .check_device = dasd_eckd_check_characteristics, |
2158 | .uncheck_device = dasd_eckd_uncheck_device, | ||
1799 | .do_analysis = dasd_eckd_do_analysis, | 2159 | .do_analysis = dasd_eckd_do_analysis, |
2160 | .ready_to_online = dasd_eckd_ready_to_online, | ||
2161 | .online_to_ready = dasd_eckd_online_to_ready, | ||
1800 | .fill_geometry = dasd_eckd_fill_geometry, | 2162 | .fill_geometry = dasd_eckd_fill_geometry, |
1801 | .start_IO = dasd_start_IO, | 2163 | .start_IO = dasd_start_IO, |
1802 | .term_IO = dasd_term_IO, | 2164 | .term_IO = dasd_term_IO, |
2165 | .handle_terminated_request = dasd_eckd_handle_terminated_request, | ||
1803 | .format_device = dasd_eckd_format_device, | 2166 | .format_device = dasd_eckd_format_device, |
1804 | .examine_error = dasd_eckd_examine_error, | ||
1805 | .erp_action = dasd_eckd_erp_action, | 2167 | .erp_action = dasd_eckd_erp_action, |
1806 | .erp_postaction = dasd_eckd_erp_postaction, | 2168 | .erp_postaction = dasd_eckd_erp_postaction, |
1807 | .build_cp = dasd_eckd_build_cp, | 2169 | .handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt, |
1808 | .free_cp = dasd_eckd_free_cp, | 2170 | .build_cp = dasd_eckd_build_alias_cp, |
2171 | .free_cp = dasd_eckd_free_alias_cp, | ||
1809 | .dump_sense = dasd_eckd_dump_sense, | 2172 | .dump_sense = dasd_eckd_dump_sense, |
1810 | .fill_info = dasd_eckd_fill_info, | 2173 | .fill_info = dasd_eckd_fill_info, |
1811 | .ioctl = dasd_eckd_ioctl, | 2174 | .ioctl = dasd_eckd_ioctl, |