aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd.c
diff options
context:
space:
mode:
authorStefan Weinhuber <wein@de.ibm.com>2009-03-26 10:23:48 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-03-26 10:24:05 -0400
commitf3eb5384cf0325c02e306b1d81e70f81a03d7432 (patch)
tree4d75517ad2c61ac2f8b6431eafd62b5d32c188ed /drivers/s390/block/dasd.c
parentb44b0ab3bac16356f03e94b1b49ba9305710c445 (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.c70
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}
2433EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars); 2445EXPORT_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 */
2453char *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}
2479EXPORT_SYMBOL_GPL(dasd_get_sense);
2480
2435static int __init dasd_init(void) 2481static int __init dasd_init(void)
2436{ 2482{
2437 int rc; 2483 int rc;