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 | |
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>
-rw-r--r-- | arch/s390/include/asm/idals.h | 17 | ||||
-rw-r--r-- | drivers/s390/block/dasd.c | 70 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 141 | ||||
-rw-r--r-- | drivers/s390/block/dasd_alias.c | 25 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 7 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 972 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 40 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eer.c | 21 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 5 |
9 files changed, 1123 insertions, 175 deletions
diff --git a/arch/s390/include/asm/idals.h b/arch/s390/include/asm/idals.h index e82c10efe65a..aae276d00383 100644 --- a/arch/s390/include/asm/idals.h +++ b/arch/s390/include/asm/idals.h | |||
@@ -44,24 +44,18 @@ idal_is_needed(void *vaddr, unsigned int length) | |||
44 | /* | 44 | /* |
45 | * Return the number of idal words needed for an address/length pair. | 45 | * Return the number of idal words needed for an address/length pair. |
46 | */ | 46 | */ |
47 | static inline unsigned int | 47 | static inline unsigned int idal_nr_words(void *vaddr, unsigned int length) |
48 | idal_nr_words(void *vaddr, unsigned int length) | ||
49 | { | 48 | { |
50 | #ifdef __s390x__ | 49 | return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length + |
51 | if (idal_is_needed(vaddr, length)) | 50 | (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG; |
52 | return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length + | ||
53 | (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG; | ||
54 | #endif | ||
55 | return 0; | ||
56 | } | 51 | } |
57 | 52 | ||
58 | /* | 53 | /* |
59 | * Create the list of idal words for an address/length pair. | 54 | * Create the list of idal words for an address/length pair. |
60 | */ | 55 | */ |
61 | static inline unsigned long * | 56 | static inline unsigned long *idal_create_words(unsigned long *idaws, |
62 | idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length) | 57 | void *vaddr, unsigned int length) |
63 | { | 58 | { |
64 | #ifdef __s390x__ | ||
65 | unsigned long paddr; | 59 | unsigned long paddr; |
66 | unsigned int cidaw; | 60 | unsigned int cidaw; |
67 | 61 | ||
@@ -74,7 +68,6 @@ idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length) | |||
74 | paddr += IDA_BLOCK_SIZE; | 68 | paddr += IDA_BLOCK_SIZE; |
75 | *idaws++ = paddr; | 69 | *idaws++ = paddr; |
76 | } | 70 | } |
77 | #endif | ||
78 | return idaws; | 71 | return idaws; |
79 | } | 72 | } |
80 | 73 | ||
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; |
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index d82aad5224f0..4cee45916144 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c | |||
@@ -1561,6 +1561,13 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) | |||
1561 | cqr = cqr->refers; | 1561 | cqr = cqr->refers; |
1562 | } | 1562 | } |
1563 | 1563 | ||
1564 | if (scsw_is_tm(&cqr->irb.scsw)) { | ||
1565 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | ||
1566 | "32 bit sense, action 1B is not defined" | ||
1567 | " in transport mode - just retry"); | ||
1568 | return default_erp; | ||
1569 | } | ||
1570 | |||
1564 | /* for imprecise ending just do default erp */ | 1571 | /* for imprecise ending just do default erp */ |
1565 | if (sense[1] & 0x01) { | 1572 | if (sense[1] & 0x01) { |
1566 | 1573 | ||
@@ -1599,7 +1606,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) | |||
1599 | oldccw = cqr->cpaddr; | 1606 | oldccw = cqr->cpaddr; |
1600 | if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) { | 1607 | if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) { |
1601 | PFX_data = cqr->data; | 1608 | PFX_data = cqr->data; |
1602 | memcpy(DE_data, &PFX_data->define_extend, | 1609 | memcpy(DE_data, &PFX_data->define_extent, |
1603 | sizeof(struct DE_eckd_data)); | 1610 | sizeof(struct DE_eckd_data)); |
1604 | } else | 1611 | } else |
1605 | memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data)); | 1612 | memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data)); |
@@ -1712,6 +1719,13 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) | |||
1712 | cqr = cqr->refers; | 1719 | cqr = cqr->refers; |
1713 | } | 1720 | } |
1714 | 1721 | ||
1722 | if (scsw_is_tm(&cqr->irb.scsw)) { | ||
1723 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | ||
1724 | "32 bit sense, action 1B, update," | ||
1725 | " in transport mode - just retry"); | ||
1726 | return previous_erp; | ||
1727 | } | ||
1728 | |||
1715 | /* for imprecise ending just do default erp */ | 1729 | /* for imprecise ending just do default erp */ |
1716 | if (sense[1] & 0x01) { | 1730 | if (sense[1] & 0x01) { |
1717 | 1731 | ||
@@ -2171,7 +2185,7 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp) | |||
2171 | { | 2185 | { |
2172 | struct dasd_device *device = erp->startdev; | 2186 | struct dasd_device *device = erp->startdev; |
2173 | 2187 | ||
2174 | if (erp->refers->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | 2188 | if (scsw_cstat(&erp->refers->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK |
2175 | | SCHN_STAT_CHN_CTRL_CHK)) { | 2189 | | SCHN_STAT_CHN_CTRL_CHK)) { |
2176 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | 2190 | DEV_MESSAGE(KERN_DEBUG, device, "%s", |
2177 | "channel or interface control check"); | 2191 | "channel or interface control check"); |
@@ -2193,21 +2207,23 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp) | |||
2193 | * erp_new contens was possibly modified | 2207 | * erp_new contens was possibly modified |
2194 | */ | 2208 | */ |
2195 | static struct dasd_ccw_req * | 2209 | static struct dasd_ccw_req * |
2196 | dasd_3990_erp_inspect(struct dasd_ccw_req * erp) | 2210 | dasd_3990_erp_inspect(struct dasd_ccw_req *erp) |
2197 | { | 2211 | { |
2198 | 2212 | ||
2199 | struct dasd_ccw_req *erp_new = NULL; | 2213 | struct dasd_ccw_req *erp_new = NULL; |
2200 | /* sense data are located in the refers record of the */ | 2214 | char *sense; |
2201 | /* already set up new ERP ! */ | ||
2202 | char *sense = erp->refers->irb.ecw; | ||
2203 | 2215 | ||
2204 | /* if this problem occured on an alias retry on base */ | 2216 | /* if this problem occured on an alias retry on base */ |
2205 | erp_new = dasd_3990_erp_inspect_alias(erp); | 2217 | erp_new = dasd_3990_erp_inspect_alias(erp); |
2206 | if (erp_new) | 2218 | if (erp_new) |
2207 | return erp_new; | 2219 | return erp_new; |
2208 | 2220 | ||
2209 | /* check if no concurrent sens is available */ | 2221 | /* sense data are located in the refers record of the |
2210 | if (!erp->refers->irb.esw.esw0.erw.cons) | 2222 | * already set up new ERP ! |
2223 | * check if concurrent sens is available | ||
2224 | */ | ||
2225 | sense = dasd_get_sense(&erp->refers->irb); | ||
2226 | if (!sense) | ||
2211 | erp_new = dasd_3990_erp_control_check(erp); | 2227 | erp_new = dasd_3990_erp_control_check(erp); |
2212 | /* distinguish between 24 and 32 byte sense data */ | 2228 | /* distinguish between 24 and 32 byte sense data */ |
2213 | else if (sense[27] & DASD_SENSE_BIT_0) { | 2229 | else if (sense[27] & DASD_SENSE_BIT_0) { |
@@ -2231,7 +2247,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp) | |||
2231 | * DESCRIPTION | 2247 | * DESCRIPTION |
2232 | * This funtion adds an additional request block (ERP) to the head of | 2248 | * This funtion adds an additional request block (ERP) to the head of |
2233 | * the given cqr (or erp). | 2249 | * the given cqr (or erp). |
2234 | * This erp is initialized as an default erp (retry TIC) | 2250 | * For a command mode cqr the erp is initialized as an default erp |
2251 | * (retry TIC). | ||
2252 | * For transport mode we make a copy of the original TCW (points to | ||
2253 | * the original TCCB, TIDALs, etc.) but give it a fresh | ||
2254 | * TSB so the original sense data will not be changed. | ||
2235 | * | 2255 | * |
2236 | * PARAMETER | 2256 | * PARAMETER |
2237 | * cqr head of the current ERP-chain (or single cqr if | 2257 | * cqr head of the current ERP-chain (or single cqr if |
@@ -2239,17 +2259,27 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp) | |||
2239 | * RETURN VALUES | 2259 | * RETURN VALUES |
2240 | * erp pointer to new ERP-chain head | 2260 | * erp pointer to new ERP-chain head |
2241 | */ | 2261 | */ |
2242 | static struct dasd_ccw_req * | 2262 | static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) |
2243 | dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) | ||
2244 | { | 2263 | { |
2245 | 2264 | ||
2246 | struct dasd_device *device = cqr->startdev; | 2265 | struct dasd_device *device = cqr->startdev; |
2247 | struct ccw1 *ccw; | 2266 | struct ccw1 *ccw; |
2248 | |||
2249 | /* allocate additional request block */ | ||
2250 | struct dasd_ccw_req *erp; | 2267 | struct dasd_ccw_req *erp; |
2268 | int cplength, datasize; | ||
2269 | struct tcw *tcw; | ||
2270 | struct tsb *tsb; | ||
2271 | |||
2272 | if (cqr->cpmode == 1) { | ||
2273 | cplength = 0; | ||
2274 | datasize = sizeof(struct tcw) + sizeof(struct tsb); | ||
2275 | } else { | ||
2276 | cplength = 2; | ||
2277 | datasize = 0; | ||
2278 | } | ||
2251 | 2279 | ||
2252 | erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, device); | 2280 | /* allocate additional request block */ |
2281 | erp = dasd_alloc_erp_request((char *) &cqr->magic, | ||
2282 | cplength, datasize, device); | ||
2253 | if (IS_ERR(erp)) { | 2283 | if (IS_ERR(erp)) { |
2254 | if (cqr->retries <= 0) { | 2284 | if (cqr->retries <= 0) { |
2255 | DEV_MESSAGE(KERN_ERR, device, "%s", | 2285 | DEV_MESSAGE(KERN_ERR, device, "%s", |
@@ -2266,13 +2296,24 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) | |||
2266 | return cqr; | 2296 | return cqr; |
2267 | } | 2297 | } |
2268 | 2298 | ||
2269 | /* initialize request with default TIC to current ERP/CQR */ | 2299 | if (cqr->cpmode == 1) { |
2270 | ccw = erp->cpaddr; | 2300 | /* make a shallow copy of the original tcw but set new tsb */ |
2271 | ccw->cmd_code = CCW_CMD_NOOP; | 2301 | erp->cpmode = 1; |
2272 | ccw->flags = CCW_FLAG_CC; | 2302 | erp->cpaddr = erp->data; |
2273 | ccw++; | 2303 | tcw = erp->data; |
2274 | ccw->cmd_code = CCW_CMD_TIC; | 2304 | tsb = (struct tsb *) &tcw[1]; |
2275 | ccw->cda = (long)(cqr->cpaddr); | 2305 | *tcw = *((struct tcw *)cqr->cpaddr); |
2306 | tcw->tsb = (long)tsb; | ||
2307 | } else { | ||
2308 | /* initialize request with default TIC to current ERP/CQR */ | ||
2309 | ccw = erp->cpaddr; | ||
2310 | ccw->cmd_code = CCW_CMD_NOOP; | ||
2311 | ccw->flags = CCW_FLAG_CC; | ||
2312 | ccw++; | ||
2313 | ccw->cmd_code = CCW_CMD_TIC; | ||
2314 | ccw->cda = (long)(cqr->cpaddr); | ||
2315 | } | ||
2316 | |||
2276 | erp->function = dasd_3990_erp_add_erp; | 2317 | erp->function = dasd_3990_erp_add_erp; |
2277 | erp->refers = cqr; | 2318 | erp->refers = cqr; |
2278 | erp->startdev = device; | 2319 | erp->startdev = device; |
@@ -2282,7 +2323,6 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) | |||
2282 | erp->expires = 0; | 2323 | erp->expires = 0; |
2283 | erp->retries = 256; | 2324 | erp->retries = 256; |
2284 | erp->buildclk = get_clock(); | 2325 | erp->buildclk = get_clock(); |
2285 | |||
2286 | erp->status = DASD_CQR_FILLED; | 2326 | erp->status = DASD_CQR_FILLED; |
2287 | 2327 | ||
2288 | return erp; | 2328 | return erp; |
@@ -2340,28 +2380,33 @@ dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr) | |||
2340 | * match 'boolean' for match found | 2380 | * match 'boolean' for match found |
2341 | * returns 1 if match found, otherwise 0. | 2381 | * returns 1 if match found, otherwise 0. |
2342 | */ | 2382 | */ |
2343 | static int | 2383 | static int dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, |
2344 | dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) | 2384 | struct dasd_ccw_req *cqr2) |
2345 | { | 2385 | { |
2386 | char *sense1, *sense2; | ||
2346 | 2387 | ||
2347 | if (cqr1->startdev != cqr2->startdev) | 2388 | if (cqr1->startdev != cqr2->startdev) |
2348 | return 0; | 2389 | return 0; |
2349 | 2390 | ||
2350 | if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons) | 2391 | sense1 = dasd_get_sense(&cqr1->irb); |
2351 | return 0; | 2392 | sense2 = dasd_get_sense(&cqr2->irb); |
2352 | 2393 | ||
2353 | if ((cqr1->irb.esw.esw0.erw.cons == 0) && | 2394 | /* one request has sense data, the other not -> no match, return 0 */ |
2354 | (cqr2->irb.esw.esw0.erw.cons == 0)) { | 2395 | if (!sense1 != !sense2) |
2355 | if ((cqr1->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | | 2396 | return 0; |
2356 | SCHN_STAT_CHN_CTRL_CHK)) == | 2397 | /* no sense data in both cases -> check cstat for IFCC */ |
2357 | (cqr2->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | | 2398 | if (!sense1 && !sense2) { |
2358 | SCHN_STAT_CHN_CTRL_CHK))) | 2399 | if ((scsw_cstat(&cqr1->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK | |
2400 | SCHN_STAT_CHN_CTRL_CHK)) == | ||
2401 | (scsw_cstat(&cqr2->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK | | ||
2402 | SCHN_STAT_CHN_CTRL_CHK))) | ||
2359 | return 1; /* match with ifcc*/ | 2403 | return 1; /* match with ifcc*/ |
2360 | } | 2404 | } |
2361 | /* check sense data; byte 0-2,25,27 */ | 2405 | /* check sense data; byte 0-2,25,27 */ |
2362 | if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && | 2406 | if (!(sense1 && sense2 && |
2363 | (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && | 2407 | (memcmp(sense1, sense2, 3) == 0) && |
2364 | (cqr1->irb.ecw[25] == cqr2->irb.ecw[25]))) { | 2408 | (sense1[27] == sense2[27]) && |
2409 | (sense1[25] == sense2[25]))) { | ||
2365 | 2410 | ||
2366 | return 0; /* sense doesn't match */ | 2411 | return 0; /* sense doesn't match */ |
2367 | } | 2412 | } |
@@ -2434,7 +2479,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) | |||
2434 | { | 2479 | { |
2435 | 2480 | ||
2436 | struct dasd_device *device = erp->startdev; | 2481 | struct dasd_device *device = erp->startdev; |
2437 | char *sense = erp->irb.ecw; | 2482 | char *sense = dasd_get_sense(&erp->irb); |
2438 | 2483 | ||
2439 | /* check for 24 byte sense ERP */ | 2484 | /* check for 24 byte sense ERP */ |
2440 | if ((erp->function == dasd_3990_erp_bus_out) || | 2485 | if ((erp->function == dasd_3990_erp_bus_out) || |
@@ -2449,7 +2494,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) | |||
2449 | /* prepare erp for retry on different channel path */ | 2494 | /* prepare erp for retry on different channel path */ |
2450 | erp = dasd_3990_erp_action_1(erp); | 2495 | erp = dasd_3990_erp_action_1(erp); |
2451 | 2496 | ||
2452 | if (!(sense[2] & DASD_SENSE_BIT_0)) { | 2497 | if (sense && !(sense[2] & DASD_SENSE_BIT_0)) { |
2453 | 2498 | ||
2454 | /* issue a Diagnostic Control command with an | 2499 | /* issue a Diagnostic Control command with an |
2455 | * Inhibit Write subcommand */ | 2500 | * Inhibit Write subcommand */ |
@@ -2479,10 +2524,11 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) | |||
2479 | } | 2524 | } |
2480 | 2525 | ||
2481 | /* check for 32 byte sense ERP */ | 2526 | /* check for 32 byte sense ERP */ |
2482 | } else if ((erp->function == dasd_3990_erp_compound_retry) || | 2527 | } else if (sense && |
2483 | (erp->function == dasd_3990_erp_compound_path) || | 2528 | ((erp->function == dasd_3990_erp_compound_retry) || |
2484 | (erp->function == dasd_3990_erp_compound_code) || | 2529 | (erp->function == dasd_3990_erp_compound_path) || |
2485 | (erp->function == dasd_3990_erp_compound_config)) { | 2530 | (erp->function == dasd_3990_erp_compound_code) || |
2531 | (erp->function == dasd_3990_erp_compound_config))) { | ||
2486 | 2532 | ||
2487 | erp = dasd_3990_erp_compound(erp, sense); | 2533 | erp = dasd_3990_erp_compound(erp, sense); |
2488 | 2534 | ||
@@ -2548,18 +2594,19 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, | |||
2548 | 2594 | ||
2549 | if (erp->retries > 0) { | 2595 | if (erp->retries > 0) { |
2550 | 2596 | ||
2551 | char *sense = erp->refers->irb.ecw; | 2597 | char *sense = dasd_get_sense(&erp->refers->irb); |
2552 | 2598 | ||
2553 | /* check for special retries */ | 2599 | /* check for special retries */ |
2554 | if (erp->function == dasd_3990_erp_action_4) { | 2600 | if (sense && erp->function == dasd_3990_erp_action_4) { |
2555 | 2601 | ||
2556 | erp = dasd_3990_erp_action_4(erp, sense); | 2602 | erp = dasd_3990_erp_action_4(erp, sense); |
2557 | 2603 | ||
2558 | } else if (erp->function == dasd_3990_erp_action_1B_32) { | 2604 | } else if (sense && |
2605 | erp->function == dasd_3990_erp_action_1B_32) { | ||
2559 | 2606 | ||
2560 | erp = dasd_3990_update_1B(erp, sense); | 2607 | erp = dasd_3990_update_1B(erp, sense); |
2561 | 2608 | ||
2562 | } else if (erp->function == dasd_3990_erp_int_req) { | 2609 | } else if (sense && erp->function == dasd_3990_erp_int_req) { |
2563 | 2610 | ||
2564 | erp = dasd_3990_erp_int_req(erp); | 2611 | erp = dasd_3990_erp_int_req(erp); |
2565 | 2612 | ||
@@ -2622,8 +2669,8 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) | |||
2622 | } | 2669 | } |
2623 | 2670 | ||
2624 | /* double-check if current erp/cqr was successful */ | 2671 | /* double-check if current erp/cqr was successful */ |
2625 | if ((cqr->irb.scsw.cmd.cstat == 0x00) && | 2672 | if ((scsw_cstat(&cqr->irb.scsw) == 0x00) && |
2626 | (cqr->irb.scsw.cmd.dstat == | 2673 | (scsw_dstat(&cqr->irb.scsw) == |
2627 | (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { | 2674 | (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { |
2628 | 2675 | ||
2629 | DEV_MESSAGE(KERN_DEBUG, device, | 2676 | DEV_MESSAGE(KERN_DEBUG, device, |
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 20676cdef4a5..219bee7bd77c 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
@@ -646,14 +646,16 @@ static int reset_summary_unit_check(struct alias_lcu *lcu, | |||
646 | { | 646 | { |
647 | struct dasd_ccw_req *cqr; | 647 | struct dasd_ccw_req *cqr; |
648 | int rc = 0; | 648 | int rc = 0; |
649 | struct ccw1 *ccw; | ||
649 | 650 | ||
650 | cqr = lcu->rsu_cqr; | 651 | cqr = lcu->rsu_cqr; |
651 | strncpy((char *) &cqr->magic, "ECKD", 4); | 652 | strncpy((char *) &cqr->magic, "ECKD", 4); |
652 | ASCEBC((char *) &cqr->magic, 4); | 653 | ASCEBC((char *) &cqr->magic, 4); |
653 | cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK; | 654 | ccw = cqr->cpaddr; |
654 | cqr->cpaddr->flags = 0 ; | 655 | ccw->cmd_code = DASD_ECKD_CCW_RSCK; |
655 | cqr->cpaddr->count = 16; | 656 | ccw->flags = 0 ; |
656 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; | 657 | ccw->count = 16; |
658 | ccw->cda = (__u32)(addr_t) cqr->data; | ||
657 | ((char *)cqr->data)[0] = reason; | 659 | ((char *)cqr->data)[0] = reason; |
658 | 660 | ||
659 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 661 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
@@ -855,12 +857,21 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, | |||
855 | struct alias_lcu *lcu; | 857 | struct alias_lcu *lcu; |
856 | char reason; | 858 | char reason; |
857 | struct dasd_eckd_private *private; | 859 | struct dasd_eckd_private *private; |
860 | char *sense; | ||
858 | 861 | ||
859 | private = (struct dasd_eckd_private *) device->private; | 862 | private = (struct dasd_eckd_private *) device->private; |
860 | 863 | ||
861 | reason = irb->ecw[8]; | 864 | sense = dasd_get_sense(irb); |
862 | DEV_MESSAGE(KERN_WARNING, device, "%s %x", | 865 | if (sense) { |
863 | "eckd handle summary unit check: reason", reason); | 866 | reason = sense[8]; |
867 | DBF_DEV_EVENT(DBF_NOTICE, device, "%s %x", | ||
868 | "eckd handle summary unit check: reason", reason); | ||
869 | } else { | ||
870 | DBF_DEV_EVENT(DBF_WARNING, device, "%s", | ||
871 | "eckd handle summary unit check:" | ||
872 | " no reason code available"); | ||
873 | return; | ||
874 | } | ||
864 | 875 | ||
865 | lcu = private->lcu; | 876 | lcu = private->lcu; |
866 | if (!lcu) { | 877 | if (!lcu) { |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 34339902efb9..da231a787cee 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -67,6 +67,8 @@ int dasd_probeonly = 0; /* is true, when probeonly mode is active */ | |||
67 | int dasd_autodetect = 0; /* is true, when autodetection is active */ | 67 | int dasd_autodetect = 0; /* is true, when autodetection is active */ |
68 | int dasd_nopav = 0; /* is true, when PAV is disabled */ | 68 | int dasd_nopav = 0; /* is true, when PAV is disabled */ |
69 | EXPORT_SYMBOL_GPL(dasd_nopav); | 69 | EXPORT_SYMBOL_GPL(dasd_nopav); |
70 | int dasd_nofcx; /* disable High Performance Ficon */ | ||
71 | EXPORT_SYMBOL_GPL(dasd_nofcx); | ||
70 | 72 | ||
71 | /* | 73 | /* |
72 | * char *dasd[] is intended to hold the ranges supplied by the dasd= statement | 74 | * char *dasd[] is intended to hold the ranges supplied by the dasd= statement |
@@ -272,6 +274,11 @@ dasd_parse_keyword( char *parsestring ) { | |||
272 | } | 274 | } |
273 | return residual_str; | 275 | return residual_str; |
274 | } | 276 | } |
277 | if (strncmp("nofcx", parsestring, length) == 0) { | ||
278 | dasd_nofcx = 1; | ||
279 | MESSAGE(KERN_INFO, "%s", "disable High Performance Ficon"); | ||
280 | return residual_str; | ||
281 | } | ||
275 | if (strncmp("fixedbuffers", parsestring, length) == 0) { | 282 | if (strncmp("fixedbuffers", parsestring, length) == 0) { |
276 | if (dasd_page_cache) | 283 | if (dasd_page_cache) |
277 | return residual_str; | 284 | return residual_str; |
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 |
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index eecfa776db15..ad45bcac3ce4 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h | |||
@@ -38,8 +38,11 @@ | |||
38 | #define DASD_ECKD_CCW_RELEASE 0x94 | 38 | #define DASD_ECKD_CCW_RELEASE 0x94 |
39 | #define DASD_ECKD_CCW_READ_CKD_MT 0x9e | 39 | #define DASD_ECKD_CCW_READ_CKD_MT 0x9e |
40 | #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d | 40 | #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d |
41 | #define DASD_ECKD_CCW_WRITE_TRACK_DATA 0xA5 | ||
42 | #define DASD_ECKD_CCW_READ_TRACK_DATA 0xA6 | ||
41 | #define DASD_ECKD_CCW_RESERVE 0xB4 | 43 | #define DASD_ECKD_CCW_RESERVE 0xB4 |
42 | #define DASD_ECKD_CCW_PFX 0xE7 | 44 | #define DASD_ECKD_CCW_PFX 0xE7 |
45 | #define DASD_ECKD_CCW_PFX_READ 0xEA | ||
43 | #define DASD_ECKD_CCW_RSCK 0xF9 | 46 | #define DASD_ECKD_CCW_RSCK 0xF9 |
44 | 47 | ||
45 | /* | 48 | /* |
@@ -123,7 +126,9 @@ struct DE_eckd_data { | |||
123 | unsigned long long ep_sys_time; /* Ext Parameter - System Time Stamp */ | 126 | unsigned long long ep_sys_time; /* Ext Parameter - System Time Stamp */ |
124 | __u8 ep_format; /* Extended Parameter format byte */ | 127 | __u8 ep_format; /* Extended Parameter format byte */ |
125 | __u8 ep_prio; /* Extended Parameter priority I/O byte */ | 128 | __u8 ep_prio; /* Extended Parameter priority I/O byte */ |
126 | __u8 ep_reserved[6]; /* Extended Parameter Reserved */ | 129 | __u8 ep_reserved1; /* Extended Parameter Reserved */ |
130 | __u8 ep_rec_per_track; /* Number of records on a track */ | ||
131 | __u8 ep_reserved[4]; /* Extended Parameter Reserved */ | ||
127 | } __attribute__ ((packed)); | 132 | } __attribute__ ((packed)); |
128 | 133 | ||
129 | struct LO_eckd_data { | 134 | struct LO_eckd_data { |
@@ -144,11 +149,37 @@ struct LO_eckd_data { | |||
144 | __u16 length; | 149 | __u16 length; |
145 | } __attribute__ ((packed)); | 150 | } __attribute__ ((packed)); |
146 | 151 | ||
152 | struct LRE_eckd_data { | ||
153 | struct { | ||
154 | unsigned char orientation:2; | ||
155 | unsigned char operation:6; | ||
156 | } __attribute__ ((packed)) operation; | ||
157 | struct { | ||
158 | unsigned char length_valid:1; | ||
159 | unsigned char length_scope:1; | ||
160 | unsigned char imbedded_ccw_valid:1; | ||
161 | unsigned char check_bytes:2; | ||
162 | unsigned char imbedded_count_valid:1; | ||
163 | unsigned char reserved:1; | ||
164 | unsigned char read_count_suffix:1; | ||
165 | } __attribute__ ((packed)) auxiliary; | ||
166 | __u8 imbedded_ccw; | ||
167 | __u8 count; | ||
168 | struct ch_t seek_addr; | ||
169 | struct chr_t search_arg; | ||
170 | __u8 sector; | ||
171 | __u16 length; | ||
172 | __u8 imbedded_count; | ||
173 | __u8 extended_operation; | ||
174 | __u16 extended_parameter_length; | ||
175 | __u8 extended_parameter[0]; | ||
176 | } __attribute__ ((packed)); | ||
177 | |||
147 | /* Prefix data for format 0x00 and 0x01 */ | 178 | /* Prefix data for format 0x00 and 0x01 */ |
148 | struct PFX_eckd_data { | 179 | struct PFX_eckd_data { |
149 | unsigned char format; | 180 | unsigned char format; |
150 | struct { | 181 | struct { |
151 | unsigned char define_extend:1; | 182 | unsigned char define_extent:1; |
152 | unsigned char time_stamp:1; | 183 | unsigned char time_stamp:1; |
153 | unsigned char verify_base:1; | 184 | unsigned char verify_base:1; |
154 | unsigned char hyper_pav:1; | 185 | unsigned char hyper_pav:1; |
@@ -158,9 +189,8 @@ struct PFX_eckd_data { | |||
158 | __u8 aux; | 189 | __u8 aux; |
159 | __u8 base_lss; | 190 | __u8 base_lss; |
160 | __u8 reserved[7]; | 191 | __u8 reserved[7]; |
161 | struct DE_eckd_data define_extend; | 192 | struct DE_eckd_data define_extent; |
162 | struct LO_eckd_data locate_record; | 193 | struct LRE_eckd_data locate_record; |
163 | __u8 LO_extended_data[4]; | ||
164 | } __attribute__ ((packed)); | 194 | } __attribute__ ((packed)); |
165 | 195 | ||
166 | struct dasd_eckd_characteristics { | 196 | struct dasd_eckd_characteristics { |
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index f8e05ce98621..9ce4209552ae 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c | |||
@@ -297,11 +297,12 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device, | |||
297 | struct dasd_eer_header header; | 297 | struct dasd_eer_header header; |
298 | unsigned long flags; | 298 | unsigned long flags; |
299 | struct eerbuffer *eerb; | 299 | struct eerbuffer *eerb; |
300 | char *sense; | ||
300 | 301 | ||
301 | /* go through cqr chain and count the valid sense data sets */ | 302 | /* go through cqr chain and count the valid sense data sets */ |
302 | data_size = 0; | 303 | data_size = 0; |
303 | for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) | 304 | for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) |
304 | if (temp_cqr->irb.esw.esw0.erw.cons) | 305 | if (dasd_get_sense(&temp_cqr->irb)) |
305 | data_size += 32; | 306 | data_size += 32; |
306 | 307 | ||
307 | header.total_size = sizeof(header) + data_size + 4; /* "EOR" */ | 308 | header.total_size = sizeof(header) + data_size + 4; /* "EOR" */ |
@@ -316,9 +317,11 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device, | |||
316 | list_for_each_entry(eerb, &bufferlist, list) { | 317 | list_for_each_entry(eerb, &bufferlist, list) { |
317 | dasd_eer_start_record(eerb, header.total_size); | 318 | dasd_eer_start_record(eerb, header.total_size); |
318 | dasd_eer_write_buffer(eerb, (char *) &header, sizeof(header)); | 319 | dasd_eer_write_buffer(eerb, (char *) &header, sizeof(header)); |
319 | for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) | 320 | for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) { |
320 | if (temp_cqr->irb.esw.esw0.erw.cons) | 321 | sense = dasd_get_sense(&temp_cqr->irb); |
321 | dasd_eer_write_buffer(eerb, cqr->irb.ecw, 32); | 322 | if (sense) |
323 | dasd_eer_write_buffer(eerb, sense, 32); | ||
324 | } | ||
322 | dasd_eer_write_buffer(eerb, "EOR", 4); | 325 | dasd_eer_write_buffer(eerb, "EOR", 4); |
323 | } | 326 | } |
324 | spin_unlock_irqrestore(&bufferlock, flags); | 327 | spin_unlock_irqrestore(&bufferlock, flags); |
@@ -451,6 +454,7 @@ int dasd_eer_enable(struct dasd_device *device) | |||
451 | { | 454 | { |
452 | struct dasd_ccw_req *cqr; | 455 | struct dasd_ccw_req *cqr; |
453 | unsigned long flags; | 456 | unsigned long flags; |
457 | struct ccw1 *ccw; | ||
454 | 458 | ||
455 | if (device->eer_cqr) | 459 | if (device->eer_cqr) |
456 | return 0; | 460 | return 0; |
@@ -468,10 +472,11 @@ int dasd_eer_enable(struct dasd_device *device) | |||
468 | cqr->expires = 10 * HZ; | 472 | cqr->expires = 10 * HZ; |
469 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | 473 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); |
470 | 474 | ||
471 | cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SNSS; | 475 | ccw = cqr->cpaddr; |
472 | cqr->cpaddr->count = SNSS_DATA_SIZE; | 476 | ccw->cmd_code = DASD_ECKD_CCW_SNSS; |
473 | cqr->cpaddr->flags = 0; | 477 | ccw->count = SNSS_DATA_SIZE; |
474 | cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; | 478 | ccw->flags = 0; |
479 | ccw->cda = (__u32)(addr_t) cqr->data; | ||
475 | 480 | ||
476 | cqr->buildclk = get_clock(); | 481 | cqr->buildclk = get_clock(); |
477 | cqr->status = DASD_CQR_FILLED; | 482 | cqr->status = DASD_CQR_FILLED; |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 29991a9fa07a..7b314c1d471e 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -157,7 +157,8 @@ struct dasd_ccw_req { | |||
157 | struct dasd_block *block; /* the originating block device */ | 157 | struct dasd_block *block; /* the originating block device */ |
158 | struct dasd_device *memdev; /* the device used to allocate this */ | 158 | struct dasd_device *memdev; /* the device used to allocate this */ |
159 | struct dasd_device *startdev; /* device the request is started on */ | 159 | struct dasd_device *startdev; /* device the request is started on */ |
160 | struct ccw1 *cpaddr; /* address of channel program */ | 160 | void *cpaddr; /* address of ccw or tcw */ |
161 | unsigned char cpmode; /* 0 = cmd mode, 1 = itcw */ | ||
161 | char status; /* status of this request */ | 162 | char status; /* status of this request */ |
162 | short retries; /* A retry counter */ | 163 | short retries; /* A retry counter */ |
163 | unsigned long flags; /* flags of this request */ | 164 | unsigned long flags; /* flags of this request */ |
@@ -573,12 +574,14 @@ int dasd_generic_notify(struct ccw_device *, int); | |||
573 | void dasd_generic_handle_state_change(struct dasd_device *); | 574 | void dasd_generic_handle_state_change(struct dasd_device *); |
574 | 575 | ||
575 | int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int); | 576 | int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int); |
577 | char *dasd_get_sense(struct irb *); | ||
576 | 578 | ||
577 | /* externals in dasd_devmap.c */ | 579 | /* externals in dasd_devmap.c */ |
578 | extern int dasd_max_devindex; | 580 | extern int dasd_max_devindex; |
579 | extern int dasd_probeonly; | 581 | extern int dasd_probeonly; |
580 | extern int dasd_autodetect; | 582 | extern int dasd_autodetect; |
581 | extern int dasd_nopav; | 583 | extern int dasd_nopav; |
584 | extern int dasd_nofcx; | ||
582 | 585 | ||
583 | int dasd_devmap_init(void); | 586 | int dasd_devmap_init(void); |
584 | void dasd_devmap_exit(void); | 587 | void dasd_devmap_exit(void); |