diff options
author | Stefan Weinhuber <wein@de.ibm.com> | 2009-03-26 10:23:48 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-03-26 10:24:05 -0400 |
commit | f3eb5384cf0325c02e306b1d81e70f81a03d7432 (patch) | |
tree | 4d75517ad2c61ac2f8b6431eafd62b5d32c188ed /drivers/s390/block/dasd.c | |
parent | b44b0ab3bac16356f03e94b1b49ba9305710c445 (diff) |
[S390] dasd: add High Performance FICON support
To support High Performance FICON, the DASD device driver has to
translate I/O requests into the new transport mode control words (TCW)
instead of the traditional (command mode) CCW requests.
Signed-off-by: Stefan Weinhuber <wein@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r-- | drivers/s390/block/dasd.c | 70 |
1 files changed, 58 insertions, 12 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 93972ed7f2df..00f7d24b337a 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/ebcdic.h> | 22 | #include <asm/ebcdic.h> |
23 | #include <asm/idals.h> | 23 | #include <asm/idals.h> |
24 | #include <asm/todclk.h> | 24 | #include <asm/todclk.h> |
25 | #include <asm/itcw.h> | ||
25 | 26 | ||
26 | /* This is ugly... */ | 27 | /* This is ugly... */ |
27 | #define PRINTK_HEADER "dasd:" | 28 | #define PRINTK_HEADER "dasd:" |
@@ -852,8 +853,13 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
852 | cqr->startclk = get_clock(); | 853 | cqr->startclk = get_clock(); |
853 | cqr->starttime = jiffies; | 854 | cqr->starttime = jiffies; |
854 | cqr->retries--; | 855 | cqr->retries--; |
855 | rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr, | 856 | if (cqr->cpmode == 1) { |
856 | cqr->lpm, 0); | 857 | rc = ccw_device_tm_start(device->cdev, cqr->cpaddr, |
858 | (long) cqr, cqr->lpm); | ||
859 | } else { | ||
860 | rc = ccw_device_start(device->cdev, cqr->cpaddr, | ||
861 | (long) cqr, cqr->lpm, 0); | ||
862 | } | ||
857 | switch (rc) { | 863 | switch (rc) { |
858 | case 0: | 864 | case 0: |
859 | cqr->status = DASD_CQR_IN_IO; | 865 | cqr->status = DASD_CQR_IN_IO; |
@@ -881,9 +887,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
881 | " retry on all pathes"); | 887 | " retry on all pathes"); |
882 | break; | 888 | break; |
883 | case -ENODEV: | 889 | case -ENODEV: |
890 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | ||
891 | "start_IO: -ENODEV device gone, retry"); | ||
892 | break; | ||
884 | case -EIO: | 893 | case -EIO: |
885 | DBF_DEV_EVENT(DBF_ERR, device, "%s", | 894 | DBF_DEV_EVENT(DBF_ERR, device, "%s", |
886 | "start_IO: device gone, retry"); | 895 | "start_IO: -EIO device gone, retry"); |
887 | break; | 896 | break; |
888 | default: | 897 | default: |
889 | DEV_MESSAGE(KERN_ERR, device, | 898 | DEV_MESSAGE(KERN_ERR, device, |
@@ -1015,9 +1024,9 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1015 | 1024 | ||
1016 | /* check for unsolicited interrupts */ | 1025 | /* check for unsolicited interrupts */ |
1017 | cqr = (struct dasd_ccw_req *) intparm; | 1026 | cqr = (struct dasd_ccw_req *) intparm; |
1018 | if (!cqr || ((irb->scsw.cmd.cc == 1) && | 1027 | if (!cqr || ((scsw_cc(&irb->scsw) == 1) && |
1019 | (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && | 1028 | (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && |
1020 | (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND))) { | 1029 | (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) { |
1021 | if (cqr && cqr->status == DASD_CQR_IN_IO) | 1030 | if (cqr && cqr->status == DASD_CQR_IN_IO) |
1022 | cqr->status = DASD_CQR_QUEUED; | 1031 | cqr->status = DASD_CQR_QUEUED; |
1023 | device = dasd_device_from_cdev_locked(cdev); | 1032 | device = dasd_device_from_cdev_locked(cdev); |
@@ -1040,7 +1049,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1040 | 1049 | ||
1041 | /* Check for clear pending */ | 1050 | /* Check for clear pending */ |
1042 | if (cqr->status == DASD_CQR_CLEAR_PENDING && | 1051 | if (cqr->status == DASD_CQR_CLEAR_PENDING && |
1043 | irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) { | 1052 | scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) { |
1044 | cqr->status = DASD_CQR_CLEARED; | 1053 | cqr->status = DASD_CQR_CLEARED; |
1045 | dasd_device_clear_timer(device); | 1054 | dasd_device_clear_timer(device); |
1046 | wake_up(&dasd_flush_wq); | 1055 | wake_up(&dasd_flush_wq); |
@@ -1048,7 +1057,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1048 | return; | 1057 | return; |
1049 | } | 1058 | } |
1050 | 1059 | ||
1051 | /* check status - the request might have been killed by dyn detach */ | 1060 | /* check status - the request might have been killed by dyn detach */ |
1052 | if (cqr->status != DASD_CQR_IN_IO) { | 1061 | if (cqr->status != DASD_CQR_IN_IO) { |
1053 | MESSAGE(KERN_DEBUG, | 1062 | MESSAGE(KERN_DEBUG, |
1054 | "invalid status: bus_id %s, status %02x", | 1063 | "invalid status: bus_id %s, status %02x", |
@@ -1059,8 +1068,8 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
1059 | ((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), cqr); | 1068 | ((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), cqr); |
1060 | next = NULL; | 1069 | next = NULL; |
1061 | expires = 0; | 1070 | expires = 0; |
1062 | if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && | 1071 | if (scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && |
1063 | irb->scsw.cmd.cstat == 0 && !irb->esw.esw0.erw.cons) { | 1072 | scsw_cstat(&irb->scsw) == 0) { |
1064 | /* request was completed successfully */ | 1073 | /* request was completed successfully */ |
1065 | cqr->status = DASD_CQR_SUCCESS; | 1074 | cqr->status = DASD_CQR_SUCCESS; |
1066 | cqr->stopclk = now; | 1075 | cqr->stopclk = now; |
@@ -1991,8 +2000,11 @@ static void dasd_setup_queue(struct dasd_block *block) | |||
1991 | blk_queue_max_sectors(block->request_queue, max); | 2000 | blk_queue_max_sectors(block->request_queue, max); |
1992 | blk_queue_max_phys_segments(block->request_queue, -1L); | 2001 | blk_queue_max_phys_segments(block->request_queue, -1L); |
1993 | blk_queue_max_hw_segments(block->request_queue, -1L); | 2002 | blk_queue_max_hw_segments(block->request_queue, -1L); |
1994 | blk_queue_max_segment_size(block->request_queue, -1L); | 2003 | /* with page sized segments we can translate each segement into |
1995 | blk_queue_segment_boundary(block->request_queue, -1L); | 2004 | * one idaw/tidaw |
2005 | */ | ||
2006 | blk_queue_max_segment_size(block->request_queue, PAGE_SIZE); | ||
2007 | blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1); | ||
1996 | blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL); | 2008 | blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL); |
1997 | } | 2009 | } |
1998 | 2010 | ||
@@ -2432,6 +2444,40 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, | |||
2432 | } | 2444 | } |
2433 | EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars); | 2445 | EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars); |
2434 | 2446 | ||
2447 | /* | ||
2448 | * In command mode and transport mode we need to look for sense | ||
2449 | * data in different places. The sense data itself is allways | ||
2450 | * an array of 32 bytes, so we can unify the sense data access | ||
2451 | * for both modes. | ||
2452 | */ | ||
2453 | char *dasd_get_sense(struct irb *irb) | ||
2454 | { | ||
2455 | struct tsb *tsb = NULL; | ||
2456 | char *sense = NULL; | ||
2457 | |||
2458 | if (scsw_is_tm(&irb->scsw) && (irb->scsw.tm.fcxs == 0x01)) { | ||
2459 | if (irb->scsw.tm.tcw) | ||
2460 | tsb = tcw_get_tsb((struct tcw *)(unsigned long) | ||
2461 | irb->scsw.tm.tcw); | ||
2462 | if (tsb && tsb->length == 64 && tsb->flags) | ||
2463 | switch (tsb->flags & 0x07) { | ||
2464 | case 1: /* tsa_iostat */ | ||
2465 | sense = tsb->tsa.iostat.sense; | ||
2466 | break; | ||
2467 | case 2: /* tsa_ddpc */ | ||
2468 | sense = tsb->tsa.ddpc.sense; | ||
2469 | break; | ||
2470 | default: | ||
2471 | /* currently we don't use interrogate data */ | ||
2472 | break; | ||
2473 | } | ||
2474 | } else if (irb->esw.esw0.erw.cons) { | ||
2475 | sense = irb->ecw; | ||
2476 | } | ||
2477 | return sense; | ||
2478 | } | ||
2479 | EXPORT_SYMBOL_GPL(dasd_get_sense); | ||
2480 | |||
2435 | static int __init dasd_init(void) | 2481 | static int __init dasd_init(void) |
2436 | { | 2482 | { |
2437 | int rc; | 2483 | int rc; |