.. | .. |
---|
42 | 42 | #endif /* PRINTK_HEADER */ |
---|
43 | 43 | #define PRINTK_HEADER "dasd(eckd):" |
---|
44 | 44 | |
---|
45 | | -#define ECKD_C0(i) (i->home_bytes) |
---|
46 | | -#define ECKD_F(i) (i->formula) |
---|
47 | | -#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):\ |
---|
48 | | - (i->factors.f_0x02.f1)) |
---|
49 | | -#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):\ |
---|
50 | | - (i->factors.f_0x02.f2)) |
---|
51 | | -#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):\ |
---|
52 | | - (i->factors.f_0x02.f3)) |
---|
53 | | -#define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0) |
---|
54 | | -#define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0) |
---|
55 | | -#define ECKD_F6(i) (i->factor6) |
---|
56 | | -#define ECKD_F7(i) (i->factor7) |
---|
57 | | -#define ECKD_F8(i) (i->factor8) |
---|
58 | | - |
---|
59 | 45 | /* |
---|
60 | 46 | * raw track access always map to 64k in memory |
---|
61 | 47 | * so it maps to 16 blocks of 4k per track |
---|
.. | .. |
---|
103 | 89 | } *dasd_reserve_req; |
---|
104 | 90 | static DEFINE_MUTEX(dasd_reserve_mutex); |
---|
105 | 91 | |
---|
| 92 | +static struct { |
---|
| 93 | + struct dasd_ccw_req cqr; |
---|
| 94 | + struct ccw1 ccw[2]; |
---|
| 95 | + char data[40]; |
---|
| 96 | +} *dasd_vol_info_req; |
---|
| 97 | +static DEFINE_MUTEX(dasd_vol_info_mutex); |
---|
| 98 | + |
---|
| 99 | +struct ext_pool_exhaust_work_data { |
---|
| 100 | + struct work_struct worker; |
---|
| 101 | + struct dasd_device *device; |
---|
| 102 | + struct dasd_device *base; |
---|
| 103 | +}; |
---|
| 104 | + |
---|
106 | 105 | /* definitions for the path verification worker */ |
---|
107 | | -struct path_verification_work_data { |
---|
| 106 | +struct pe_handler_work_data { |
---|
108 | 107 | struct work_struct worker; |
---|
109 | 108 | struct dasd_device *device; |
---|
110 | 109 | struct dasd_ccw_req cqr; |
---|
.. | .. |
---|
113 | 112 | int isglobal; |
---|
114 | 113 | __u8 tbvpm; |
---|
115 | 114 | }; |
---|
116 | | -static struct path_verification_work_data *path_verification_worker; |
---|
117 | | -static DEFINE_MUTEX(dasd_path_verification_mutex); |
---|
| 115 | +static struct pe_handler_work_data *pe_handler_worker; |
---|
| 116 | +static DEFINE_MUTEX(dasd_pe_handler_mutex); |
---|
118 | 117 | |
---|
119 | 118 | struct check_attention_work_data { |
---|
120 | 119 | struct work_struct worker; |
---|
.. | .. |
---|
122 | 121 | __u8 lpum; |
---|
123 | 122 | }; |
---|
124 | 123 | |
---|
| 124 | +static int dasd_eckd_ext_pool_id(struct dasd_device *); |
---|
125 | 125 | static int prepare_itcw(struct itcw *, unsigned int, unsigned int, int, |
---|
126 | 126 | struct dasd_device *, struct dasd_device *, |
---|
127 | 127 | unsigned int, int, unsigned int, unsigned int, |
---|
.. | .. |
---|
157 | 157 | #define LABEL_SIZE 140 |
---|
158 | 158 | |
---|
159 | 159 | /* head and record addresses of count_area read in analysis ccw */ |
---|
160 | | -static const int count_area_head[] = { 0, 0, 0, 0, 2 }; |
---|
| 160 | +static const int count_area_head[] = { 0, 0, 0, 0, 1 }; |
---|
161 | 161 | static const int count_area_rec[] = { 1, 2, 3, 4, 1 }; |
---|
162 | | - |
---|
163 | | -static inline unsigned int |
---|
164 | | -round_up_multiple(unsigned int no, unsigned int mult) |
---|
165 | | -{ |
---|
166 | | - int rem = no % mult; |
---|
167 | | - return (rem ? no - rem + mult : no); |
---|
168 | | -} |
---|
169 | 162 | |
---|
170 | 163 | static inline unsigned int |
---|
171 | 164 | ceil_quot(unsigned int d1, unsigned int d2) |
---|
.. | .. |
---|
212 | 205 | geo->head = cyl >> 16; |
---|
213 | 206 | geo->head <<= 4; |
---|
214 | 207 | geo->head |= head; |
---|
| 208 | +} |
---|
| 209 | + |
---|
| 210 | +/* |
---|
| 211 | + * calculate failing track from sense data depending if |
---|
| 212 | + * it is an EAV device or not |
---|
| 213 | + */ |
---|
| 214 | +static int dasd_eckd_track_from_irb(struct irb *irb, struct dasd_device *device, |
---|
| 215 | + sector_t *track) |
---|
| 216 | +{ |
---|
| 217 | + struct dasd_eckd_private *private = device->private; |
---|
| 218 | + u8 *sense = NULL; |
---|
| 219 | + u32 cyl; |
---|
| 220 | + u8 head; |
---|
| 221 | + |
---|
| 222 | + sense = dasd_get_sense(irb); |
---|
| 223 | + if (!sense) { |
---|
| 224 | + DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
---|
| 225 | + "ESE error no sense data\n"); |
---|
| 226 | + return -EINVAL; |
---|
| 227 | + } |
---|
| 228 | + if (!(sense[27] & DASD_SENSE_BIT_2)) { |
---|
| 229 | + DBF_DEV_EVENT(DBF_WARNING, device, "%s", |
---|
| 230 | + "ESE error no valid track data\n"); |
---|
| 231 | + return -EINVAL; |
---|
| 232 | + } |
---|
| 233 | + |
---|
| 234 | + if (sense[27] & DASD_SENSE_BIT_3) { |
---|
| 235 | + /* enhanced addressing */ |
---|
| 236 | + cyl = sense[30] << 20; |
---|
| 237 | + cyl |= (sense[31] & 0xF0) << 12; |
---|
| 238 | + cyl |= sense[28] << 8; |
---|
| 239 | + cyl |= sense[29]; |
---|
| 240 | + } else { |
---|
| 241 | + cyl = sense[29] << 8; |
---|
| 242 | + cyl |= sense[30]; |
---|
| 243 | + } |
---|
| 244 | + head = sense[31] & 0x0F; |
---|
| 245 | + *track = cyl * private->rdc_data.trk_per_cyl + head; |
---|
| 246 | + return 0; |
---|
215 | 247 | } |
---|
216 | 248 | |
---|
217 | 249 | static int set_timestamp(struct ccw1 *ccw, struct DE_eckd_data *data, |
---|
.. | .. |
---|
1187 | 1219 | } |
---|
1188 | 1220 | |
---|
1189 | 1221 | static int rebuild_device_uid(struct dasd_device *device, |
---|
1190 | | - struct path_verification_work_data *data) |
---|
| 1222 | + struct pe_handler_work_data *data) |
---|
1191 | 1223 | { |
---|
1192 | 1224 | struct dasd_eckd_private *private = device->private; |
---|
1193 | 1225 | __u8 lpm, opm = dasd_path_get_opm(device); |
---|
.. | .. |
---|
1225 | 1257 | return rc; |
---|
1226 | 1258 | } |
---|
1227 | 1259 | |
---|
1228 | | -static void do_path_verification_work(struct work_struct *work) |
---|
| 1260 | +static void dasd_eckd_path_available_action(struct dasd_device *device, |
---|
| 1261 | + struct pe_handler_work_data *data) |
---|
1229 | 1262 | { |
---|
1230 | | - struct path_verification_work_data *data; |
---|
1231 | | - struct dasd_device *device; |
---|
1232 | 1263 | struct dasd_eckd_private path_private; |
---|
1233 | 1264 | struct dasd_uid *uid; |
---|
1234 | 1265 | __u8 path_rcd_buf[DASD_ECKD_RCD_DATA_SIZE]; |
---|
.. | .. |
---|
1237 | 1268 | char print_uid[60]; |
---|
1238 | 1269 | int rc; |
---|
1239 | 1270 | |
---|
1240 | | - data = container_of(work, struct path_verification_work_data, worker); |
---|
1241 | | - device = data->device; |
---|
1242 | | - |
---|
1243 | | - /* delay path verification until device was resumed */ |
---|
1244 | | - if (test_bit(DASD_FLAG_SUSPENDED, &device->flags)) { |
---|
1245 | | - schedule_work(work); |
---|
1246 | | - return; |
---|
1247 | | - } |
---|
1248 | | - /* check if path verification already running and delay if so */ |
---|
1249 | | - if (test_and_set_bit(DASD_FLAG_PATH_VERIFY, &device->flags)) { |
---|
1250 | | - schedule_work(work); |
---|
1251 | | - return; |
---|
1252 | | - } |
---|
1253 | 1271 | opm = 0; |
---|
1254 | 1272 | npm = 0; |
---|
1255 | 1273 | ppm = 0; |
---|
.. | .. |
---|
1386 | 1404 | dasd_path_add_nohpfpm(device, hpfpm); |
---|
1387 | 1405 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); |
---|
1388 | 1406 | } |
---|
| 1407 | +} |
---|
| 1408 | + |
---|
| 1409 | +static void do_pe_handler_work(struct work_struct *work) |
---|
| 1410 | +{ |
---|
| 1411 | + struct pe_handler_work_data *data; |
---|
| 1412 | + struct dasd_device *device; |
---|
| 1413 | + |
---|
| 1414 | + data = container_of(work, struct pe_handler_work_data, worker); |
---|
| 1415 | + device = data->device; |
---|
| 1416 | + |
---|
| 1417 | + /* delay path verification until device was resumed */ |
---|
| 1418 | + if (test_bit(DASD_FLAG_SUSPENDED, &device->flags)) { |
---|
| 1419 | + schedule_work(work); |
---|
| 1420 | + return; |
---|
| 1421 | + } |
---|
| 1422 | + /* check if path verification already running and delay if so */ |
---|
| 1423 | + if (test_and_set_bit(DASD_FLAG_PATH_VERIFY, &device->flags)) { |
---|
| 1424 | + schedule_work(work); |
---|
| 1425 | + return; |
---|
| 1426 | + } |
---|
| 1427 | + |
---|
| 1428 | + dasd_eckd_path_available_action(device, data); |
---|
| 1429 | + |
---|
1389 | 1430 | clear_bit(DASD_FLAG_PATH_VERIFY, &device->flags); |
---|
1390 | 1431 | dasd_put_device(device); |
---|
1391 | 1432 | if (data->isglobal) |
---|
1392 | | - mutex_unlock(&dasd_path_verification_mutex); |
---|
| 1433 | + mutex_unlock(&dasd_pe_handler_mutex); |
---|
1393 | 1434 | else |
---|
1394 | 1435 | kfree(data); |
---|
1395 | 1436 | } |
---|
1396 | 1437 | |
---|
1397 | | -static int dasd_eckd_verify_path(struct dasd_device *device, __u8 lpm) |
---|
| 1438 | +static int dasd_eckd_pe_handler(struct dasd_device *device, __u8 lpm) |
---|
1398 | 1439 | { |
---|
1399 | | - struct path_verification_work_data *data; |
---|
| 1440 | + struct pe_handler_work_data *data; |
---|
1400 | 1441 | |
---|
1401 | 1442 | data = kmalloc(sizeof(*data), GFP_ATOMIC | GFP_DMA); |
---|
1402 | 1443 | if (!data) { |
---|
1403 | | - if (mutex_trylock(&dasd_path_verification_mutex)) { |
---|
1404 | | - data = path_verification_worker; |
---|
| 1444 | + if (mutex_trylock(&dasd_pe_handler_mutex)) { |
---|
| 1445 | + data = pe_handler_worker; |
---|
1405 | 1446 | data->isglobal = 1; |
---|
1406 | | - } else |
---|
| 1447 | + } else { |
---|
1407 | 1448 | return -ENOMEM; |
---|
| 1449 | + } |
---|
1408 | 1450 | } else { |
---|
1409 | 1451 | memset(data, 0, sizeof(*data)); |
---|
1410 | 1452 | data->isglobal = 0; |
---|
1411 | 1453 | } |
---|
1412 | | - INIT_WORK(&data->worker, do_path_verification_work); |
---|
| 1454 | + INIT_WORK(&data->worker, do_pe_handler_work); |
---|
1413 | 1455 | dasd_get_device(device); |
---|
1414 | 1456 | data->device = device; |
---|
1415 | 1457 | data->tbvpm = lpm; |
---|
.. | .. |
---|
1492 | 1534 | return rc; |
---|
1493 | 1535 | } |
---|
1494 | 1536 | |
---|
| 1537 | +/* Read Volume Information - Volume Storage Query */ |
---|
| 1538 | +static int dasd_eckd_read_vol_info(struct dasd_device *device) |
---|
| 1539 | +{ |
---|
| 1540 | + struct dasd_eckd_private *private = device->private; |
---|
| 1541 | + struct dasd_psf_prssd_data *prssdp; |
---|
| 1542 | + struct dasd_rssd_vsq *vsq; |
---|
| 1543 | + struct dasd_ccw_req *cqr; |
---|
| 1544 | + struct ccw1 *ccw; |
---|
| 1545 | + int useglobal; |
---|
| 1546 | + int rc; |
---|
| 1547 | + |
---|
| 1548 | + /* This command cannot be executed on an alias device */ |
---|
| 1549 | + if (private->uid.type == UA_BASE_PAV_ALIAS || |
---|
| 1550 | + private->uid.type == UA_HYPER_PAV_ALIAS) |
---|
| 1551 | + return 0; |
---|
| 1552 | + |
---|
| 1553 | + useglobal = 0; |
---|
| 1554 | + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 /* PSF + RSSD */, |
---|
| 1555 | + sizeof(*prssdp) + sizeof(*vsq), device, NULL); |
---|
| 1556 | + if (IS_ERR(cqr)) { |
---|
| 1557 | + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", |
---|
| 1558 | + "Could not allocate initialization request"); |
---|
| 1559 | + mutex_lock(&dasd_vol_info_mutex); |
---|
| 1560 | + useglobal = 1; |
---|
| 1561 | + cqr = &dasd_vol_info_req->cqr; |
---|
| 1562 | + memset(cqr, 0, sizeof(*cqr)); |
---|
| 1563 | + memset(dasd_vol_info_req, 0, sizeof(*dasd_vol_info_req)); |
---|
| 1564 | + cqr->cpaddr = &dasd_vol_info_req->ccw; |
---|
| 1565 | + cqr->data = &dasd_vol_info_req->data; |
---|
| 1566 | + cqr->magic = DASD_ECKD_MAGIC; |
---|
| 1567 | + } |
---|
| 1568 | + |
---|
| 1569 | + /* Prepare for Read Subsystem Data */ |
---|
| 1570 | + prssdp = cqr->data; |
---|
| 1571 | + prssdp->order = PSF_ORDER_PRSSD; |
---|
| 1572 | + prssdp->suborder = PSF_SUBORDER_VSQ; /* Volume Storage Query */ |
---|
| 1573 | + prssdp->lss = private->ned->ID; |
---|
| 1574 | + prssdp->volume = private->ned->unit_addr; |
---|
| 1575 | + |
---|
| 1576 | + ccw = cqr->cpaddr; |
---|
| 1577 | + ccw->cmd_code = DASD_ECKD_CCW_PSF; |
---|
| 1578 | + ccw->count = sizeof(*prssdp); |
---|
| 1579 | + ccw->flags |= CCW_FLAG_CC; |
---|
| 1580 | + ccw->cda = (__u32)(addr_t)prssdp; |
---|
| 1581 | + |
---|
| 1582 | + /* Read Subsystem Data - Volume Storage Query */ |
---|
| 1583 | + vsq = (struct dasd_rssd_vsq *)(prssdp + 1); |
---|
| 1584 | + memset(vsq, 0, sizeof(*vsq)); |
---|
| 1585 | + |
---|
| 1586 | + ccw++; |
---|
| 1587 | + ccw->cmd_code = DASD_ECKD_CCW_RSSD; |
---|
| 1588 | + ccw->count = sizeof(*vsq); |
---|
| 1589 | + ccw->flags |= CCW_FLAG_SLI; |
---|
| 1590 | + ccw->cda = (__u32)(addr_t)vsq; |
---|
| 1591 | + |
---|
| 1592 | + cqr->buildclk = get_tod_clock(); |
---|
| 1593 | + cqr->status = DASD_CQR_FILLED; |
---|
| 1594 | + cqr->startdev = device; |
---|
| 1595 | + cqr->memdev = device; |
---|
| 1596 | + cqr->block = NULL; |
---|
| 1597 | + cqr->retries = 256; |
---|
| 1598 | + cqr->expires = device->default_expires * HZ; |
---|
| 1599 | + /* The command might not be supported. Suppress the error output */ |
---|
| 1600 | + __set_bit(DASD_CQR_SUPPRESS_CR, &cqr->flags); |
---|
| 1601 | + |
---|
| 1602 | + rc = dasd_sleep_on_interruptible(cqr); |
---|
| 1603 | + if (rc == 0) { |
---|
| 1604 | + memcpy(&private->vsq, vsq, sizeof(*vsq)); |
---|
| 1605 | + } else { |
---|
| 1606 | + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, |
---|
| 1607 | + "Reading the volume storage information failed with rc=%d", rc); |
---|
| 1608 | + } |
---|
| 1609 | + |
---|
| 1610 | + if (useglobal) |
---|
| 1611 | + mutex_unlock(&dasd_vol_info_mutex); |
---|
| 1612 | + else |
---|
| 1613 | + dasd_sfree_request(cqr, cqr->memdev); |
---|
| 1614 | + |
---|
| 1615 | + return rc; |
---|
| 1616 | +} |
---|
| 1617 | + |
---|
| 1618 | +static int dasd_eckd_is_ese(struct dasd_device *device) |
---|
| 1619 | +{ |
---|
| 1620 | + struct dasd_eckd_private *private = device->private; |
---|
| 1621 | + |
---|
| 1622 | + return private->vsq.vol_info.ese; |
---|
| 1623 | +} |
---|
| 1624 | + |
---|
| 1625 | +static int dasd_eckd_ext_pool_id(struct dasd_device *device) |
---|
| 1626 | +{ |
---|
| 1627 | + struct dasd_eckd_private *private = device->private; |
---|
| 1628 | + |
---|
| 1629 | + return private->vsq.extent_pool_id; |
---|
| 1630 | +} |
---|
| 1631 | + |
---|
| 1632 | +/* |
---|
| 1633 | + * This value represents the total amount of available space. As more space is |
---|
| 1634 | + * allocated by ESE volumes, this value will decrease. |
---|
| 1635 | + * The data for this value is therefore updated on any call. |
---|
| 1636 | + */ |
---|
| 1637 | +static int dasd_eckd_space_configured(struct dasd_device *device) |
---|
| 1638 | +{ |
---|
| 1639 | + struct dasd_eckd_private *private = device->private; |
---|
| 1640 | + int rc; |
---|
| 1641 | + |
---|
| 1642 | + rc = dasd_eckd_read_vol_info(device); |
---|
| 1643 | + |
---|
| 1644 | + return rc ? : private->vsq.space_configured; |
---|
| 1645 | +} |
---|
| 1646 | + |
---|
| 1647 | +/* |
---|
| 1648 | + * The value of space allocated by an ESE volume may have changed and is |
---|
| 1649 | + * therefore updated on any call. |
---|
| 1650 | + */ |
---|
| 1651 | +static int dasd_eckd_space_allocated(struct dasd_device *device) |
---|
| 1652 | +{ |
---|
| 1653 | + struct dasd_eckd_private *private = device->private; |
---|
| 1654 | + int rc; |
---|
| 1655 | + |
---|
| 1656 | + rc = dasd_eckd_read_vol_info(device); |
---|
| 1657 | + |
---|
| 1658 | + return rc ? : private->vsq.space_allocated; |
---|
| 1659 | +} |
---|
| 1660 | + |
---|
| 1661 | +static int dasd_eckd_logical_capacity(struct dasd_device *device) |
---|
| 1662 | +{ |
---|
| 1663 | + struct dasd_eckd_private *private = device->private; |
---|
| 1664 | + |
---|
| 1665 | + return private->vsq.logical_capacity; |
---|
| 1666 | +} |
---|
| 1667 | + |
---|
| 1668 | +static void dasd_eckd_ext_pool_exhaust_work(struct work_struct *work) |
---|
| 1669 | +{ |
---|
| 1670 | + struct ext_pool_exhaust_work_data *data; |
---|
| 1671 | + struct dasd_device *device; |
---|
| 1672 | + struct dasd_device *base; |
---|
| 1673 | + |
---|
| 1674 | + data = container_of(work, struct ext_pool_exhaust_work_data, worker); |
---|
| 1675 | + device = data->device; |
---|
| 1676 | + base = data->base; |
---|
| 1677 | + |
---|
| 1678 | + if (!base) |
---|
| 1679 | + base = device; |
---|
| 1680 | + if (dasd_eckd_space_configured(base) != 0) { |
---|
| 1681 | + dasd_generic_space_avail(device); |
---|
| 1682 | + } else { |
---|
| 1683 | + dev_warn(&device->cdev->dev, "No space left in the extent pool\n"); |
---|
| 1684 | + DBF_DEV_EVENT(DBF_WARNING, device, "%s", "out of space"); |
---|
| 1685 | + } |
---|
| 1686 | + |
---|
| 1687 | + dasd_put_device(device); |
---|
| 1688 | + kfree(data); |
---|
| 1689 | +} |
---|
| 1690 | + |
---|
| 1691 | +static int dasd_eckd_ext_pool_exhaust(struct dasd_device *device, |
---|
| 1692 | + struct dasd_ccw_req *cqr) |
---|
| 1693 | +{ |
---|
| 1694 | + struct ext_pool_exhaust_work_data *data; |
---|
| 1695 | + |
---|
| 1696 | + data = kzalloc(sizeof(*data), GFP_ATOMIC); |
---|
| 1697 | + if (!data) |
---|
| 1698 | + return -ENOMEM; |
---|
| 1699 | + INIT_WORK(&data->worker, dasd_eckd_ext_pool_exhaust_work); |
---|
| 1700 | + dasd_get_device(device); |
---|
| 1701 | + data->device = device; |
---|
| 1702 | + |
---|
| 1703 | + if (cqr->block) |
---|
| 1704 | + data->base = cqr->block->base; |
---|
| 1705 | + else if (cqr->basedev) |
---|
| 1706 | + data->base = cqr->basedev; |
---|
| 1707 | + else |
---|
| 1708 | + data->base = NULL; |
---|
| 1709 | + |
---|
| 1710 | + schedule_work(&data->worker); |
---|
| 1711 | + |
---|
| 1712 | + return 0; |
---|
| 1713 | +} |
---|
| 1714 | + |
---|
| 1715 | +static void dasd_eckd_cpy_ext_pool_data(struct dasd_device *device, |
---|
| 1716 | + struct dasd_rssd_lcq *lcq) |
---|
| 1717 | +{ |
---|
| 1718 | + struct dasd_eckd_private *private = device->private; |
---|
| 1719 | + int pool_id = dasd_eckd_ext_pool_id(device); |
---|
| 1720 | + struct dasd_ext_pool_sum eps; |
---|
| 1721 | + int i; |
---|
| 1722 | + |
---|
| 1723 | + for (i = 0; i < lcq->pool_count; i++) { |
---|
| 1724 | + eps = lcq->ext_pool_sum[i]; |
---|
| 1725 | + if (eps.pool_id == pool_id) { |
---|
| 1726 | + memcpy(&private->eps, &eps, |
---|
| 1727 | + sizeof(struct dasd_ext_pool_sum)); |
---|
| 1728 | + } |
---|
| 1729 | + } |
---|
| 1730 | +} |
---|
| 1731 | + |
---|
| 1732 | +/* Read Extent Pool Information - Logical Configuration Query */ |
---|
| 1733 | +static int dasd_eckd_read_ext_pool_info(struct dasd_device *device) |
---|
| 1734 | +{ |
---|
| 1735 | + struct dasd_eckd_private *private = device->private; |
---|
| 1736 | + struct dasd_psf_prssd_data *prssdp; |
---|
| 1737 | + struct dasd_rssd_lcq *lcq; |
---|
| 1738 | + struct dasd_ccw_req *cqr; |
---|
| 1739 | + struct ccw1 *ccw; |
---|
| 1740 | + int rc; |
---|
| 1741 | + |
---|
| 1742 | + /* This command cannot be executed on an alias device */ |
---|
| 1743 | + if (private->uid.type == UA_BASE_PAV_ALIAS || |
---|
| 1744 | + private->uid.type == UA_HYPER_PAV_ALIAS) |
---|
| 1745 | + return 0; |
---|
| 1746 | + |
---|
| 1747 | + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 /* PSF + RSSD */, |
---|
| 1748 | + sizeof(*prssdp) + sizeof(*lcq), device, NULL); |
---|
| 1749 | + if (IS_ERR(cqr)) { |
---|
| 1750 | + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", |
---|
| 1751 | + "Could not allocate initialization request"); |
---|
| 1752 | + return PTR_ERR(cqr); |
---|
| 1753 | + } |
---|
| 1754 | + |
---|
| 1755 | + /* Prepare for Read Subsystem Data */ |
---|
| 1756 | + prssdp = cqr->data; |
---|
| 1757 | + memset(prssdp, 0, sizeof(*prssdp)); |
---|
| 1758 | + prssdp->order = PSF_ORDER_PRSSD; |
---|
| 1759 | + prssdp->suborder = PSF_SUBORDER_LCQ; /* Logical Configuration Query */ |
---|
| 1760 | + |
---|
| 1761 | + ccw = cqr->cpaddr; |
---|
| 1762 | + ccw->cmd_code = DASD_ECKD_CCW_PSF; |
---|
| 1763 | + ccw->count = sizeof(*prssdp); |
---|
| 1764 | + ccw->flags |= CCW_FLAG_CC; |
---|
| 1765 | + ccw->cda = (__u32)(addr_t)prssdp; |
---|
| 1766 | + |
---|
| 1767 | + lcq = (struct dasd_rssd_lcq *)(prssdp + 1); |
---|
| 1768 | + memset(lcq, 0, sizeof(*lcq)); |
---|
| 1769 | + |
---|
| 1770 | + ccw++; |
---|
| 1771 | + ccw->cmd_code = DASD_ECKD_CCW_RSSD; |
---|
| 1772 | + ccw->count = sizeof(*lcq); |
---|
| 1773 | + ccw->flags |= CCW_FLAG_SLI; |
---|
| 1774 | + ccw->cda = (__u32)(addr_t)lcq; |
---|
| 1775 | + |
---|
| 1776 | + cqr->buildclk = get_tod_clock(); |
---|
| 1777 | + cqr->status = DASD_CQR_FILLED; |
---|
| 1778 | + cqr->startdev = device; |
---|
| 1779 | + cqr->memdev = device; |
---|
| 1780 | + cqr->block = NULL; |
---|
| 1781 | + cqr->retries = 256; |
---|
| 1782 | + cqr->expires = device->default_expires * HZ; |
---|
| 1783 | + /* The command might not be supported. Suppress the error output */ |
---|
| 1784 | + __set_bit(DASD_CQR_SUPPRESS_CR, &cqr->flags); |
---|
| 1785 | + |
---|
| 1786 | + rc = dasd_sleep_on_interruptible(cqr); |
---|
| 1787 | + if (rc == 0) { |
---|
| 1788 | + dasd_eckd_cpy_ext_pool_data(device, lcq); |
---|
| 1789 | + } else { |
---|
| 1790 | + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, |
---|
| 1791 | + "Reading the logical configuration failed with rc=%d", rc); |
---|
| 1792 | + } |
---|
| 1793 | + |
---|
| 1794 | + dasd_sfree_request(cqr, cqr->memdev); |
---|
| 1795 | + |
---|
| 1796 | + return rc; |
---|
| 1797 | +} |
---|
| 1798 | + |
---|
| 1799 | +/* |
---|
| 1800 | + * Depending on the device type, the extent size is specified either as |
---|
| 1801 | + * cylinders per extent (CKD) or size per extent (FBA) |
---|
| 1802 | + * A 1GB size corresponds to 1113cyl, and 16MB to 21cyl. |
---|
| 1803 | + */ |
---|
| 1804 | +static int dasd_eckd_ext_size(struct dasd_device *device) |
---|
| 1805 | +{ |
---|
| 1806 | + struct dasd_eckd_private *private = device->private; |
---|
| 1807 | + struct dasd_ext_pool_sum eps = private->eps; |
---|
| 1808 | + |
---|
| 1809 | + if (!eps.flags.extent_size_valid) |
---|
| 1810 | + return 0; |
---|
| 1811 | + if (eps.extent_size.size_1G) |
---|
| 1812 | + return 1113; |
---|
| 1813 | + if (eps.extent_size.size_16M) |
---|
| 1814 | + return 21; |
---|
| 1815 | + |
---|
| 1816 | + return 0; |
---|
| 1817 | +} |
---|
| 1818 | + |
---|
| 1819 | +static int dasd_eckd_ext_pool_warn_thrshld(struct dasd_device *device) |
---|
| 1820 | +{ |
---|
| 1821 | + struct dasd_eckd_private *private = device->private; |
---|
| 1822 | + |
---|
| 1823 | + return private->eps.warn_thrshld; |
---|
| 1824 | +} |
---|
| 1825 | + |
---|
| 1826 | +static int dasd_eckd_ext_pool_cap_at_warnlevel(struct dasd_device *device) |
---|
| 1827 | +{ |
---|
| 1828 | + struct dasd_eckd_private *private = device->private; |
---|
| 1829 | + |
---|
| 1830 | + return private->eps.flags.capacity_at_warnlevel; |
---|
| 1831 | +} |
---|
| 1832 | + |
---|
| 1833 | +/* |
---|
| 1834 | + * Extent Pool out of space |
---|
| 1835 | + */ |
---|
| 1836 | +static int dasd_eckd_ext_pool_oos(struct dasd_device *device) |
---|
| 1837 | +{ |
---|
| 1838 | + struct dasd_eckd_private *private = device->private; |
---|
| 1839 | + |
---|
| 1840 | + return private->eps.flags.pool_oos; |
---|
| 1841 | +} |
---|
1495 | 1842 | |
---|
1496 | 1843 | /* |
---|
1497 | 1844 | * Build CP for Perform Subsystem Function - SSC. |
---|
.. | .. |
---|
1722 | 2069 | /* Read Feature Codes */ |
---|
1723 | 2070 | dasd_eckd_read_features(device); |
---|
1724 | 2071 | |
---|
| 2072 | + /* Read Volume Information */ |
---|
| 2073 | + dasd_eckd_read_vol_info(device); |
---|
| 2074 | + |
---|
| 2075 | + /* Read Extent Pool Information */ |
---|
| 2076 | + dasd_eckd_read_ext_pool_info(device); |
---|
| 2077 | + |
---|
1725 | 2078 | /* Read Device Characteristics */ |
---|
1726 | 2079 | rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, |
---|
1727 | 2080 | &private->rdc_data, 64); |
---|
.. | .. |
---|
1809 | 2162 | if (IS_ERR(cqr)) |
---|
1810 | 2163 | return cqr; |
---|
1811 | 2164 | ccw = cqr->cpaddr; |
---|
1812 | | - /* Define extent for the first 3 tracks. */ |
---|
1813 | | - define_extent(ccw++, cqr->data, 0, 2, |
---|
| 2165 | + /* Define extent for the first 2 tracks. */ |
---|
| 2166 | + define_extent(ccw++, cqr->data, 0, 1, |
---|
1814 | 2167 | DASD_ECKD_CCW_READ_COUNT, device, 0); |
---|
1815 | 2168 | LO_data = cqr->data + sizeof(struct DE_eckd_data); |
---|
1816 | 2169 | /* Locate record for the first 4 records on track 0. */ |
---|
.. | .. |
---|
1829 | 2182 | count_data++; |
---|
1830 | 2183 | } |
---|
1831 | 2184 | |
---|
1832 | | - /* Locate record for the first record on track 2. */ |
---|
| 2185 | + /* Locate record for the first record on track 1. */ |
---|
1833 | 2186 | ccw[-1].flags |= CCW_FLAG_CC; |
---|
1834 | | - locate_record(ccw++, LO_data++, 2, 0, 1, |
---|
| 2187 | + locate_record(ccw++, LO_data++, 1, 0, 1, |
---|
1835 | 2188 | DASD_ECKD_CCW_READ_COUNT, device, 0); |
---|
1836 | 2189 | /* Read count ccw. */ |
---|
1837 | 2190 | ccw[-1].flags |= CCW_FLAG_CC; |
---|
.. | .. |
---|
1846 | 2199 | cqr->retries = 255; |
---|
1847 | 2200 | cqr->buildclk = get_tod_clock(); |
---|
1848 | 2201 | cqr->status = DASD_CQR_FILLED; |
---|
| 2202 | + /* Set flags to suppress output for expected errors */ |
---|
| 2203 | + set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); |
---|
| 2204 | + |
---|
1849 | 2205 | return cqr; |
---|
1850 | 2206 | } |
---|
1851 | 2207 | |
---|
.. | .. |
---|
1953 | 2309 | } |
---|
1954 | 2310 | } |
---|
1955 | 2311 | if (i == 3) |
---|
1956 | | - count_area = &private->count_area[4]; |
---|
| 2312 | + count_area = &private->count_area[3]; |
---|
1957 | 2313 | |
---|
1958 | 2314 | if (private->uses_cdl == 0) { |
---|
1959 | 2315 | for (i = 0; i < 5; i++) { |
---|
.. | .. |
---|
2085 | 2441 | */ |
---|
2086 | 2442 | itcw_size = itcw_calc_size(0, count, 0); |
---|
2087 | 2443 | |
---|
2088 | | - cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev, |
---|
2089 | | - NULL); |
---|
| 2444 | + cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev); |
---|
2090 | 2445 | if (IS_ERR(cqr)) |
---|
2091 | 2446 | return cqr; |
---|
2092 | 2447 | |
---|
.. | .. |
---|
2179 | 2534 | } |
---|
2180 | 2535 | cplength += count; |
---|
2181 | 2536 | |
---|
2182 | | - cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, |
---|
2183 | | - startdev, NULL); |
---|
| 2537 | + cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev); |
---|
2184 | 2538 | if (IS_ERR(cqr)) |
---|
2185 | 2539 | return cqr; |
---|
2186 | 2540 | |
---|
.. | .. |
---|
2227 | 2581 | } |
---|
2228 | 2582 | |
---|
2229 | 2583 | static struct dasd_ccw_req * |
---|
2230 | | -dasd_eckd_build_format(struct dasd_device *base, |
---|
2231 | | - struct format_data_t *fdata, |
---|
2232 | | - int enable_pav) |
---|
| 2584 | +dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev, |
---|
| 2585 | + struct format_data_t *fdata, int enable_pav) |
---|
2233 | 2586 | { |
---|
2234 | 2587 | struct dasd_eckd_private *base_priv; |
---|
2235 | 2588 | struct dasd_eckd_private *start_priv; |
---|
2236 | | - struct dasd_device *startdev = NULL; |
---|
2237 | 2589 | struct dasd_ccw_req *fcp; |
---|
2238 | 2590 | struct eckd_count *ect; |
---|
2239 | 2591 | struct ch_t address; |
---|
.. | .. |
---|
2324 | 2676 | fdata->intensity); |
---|
2325 | 2677 | return ERR_PTR(-EINVAL); |
---|
2326 | 2678 | } |
---|
2327 | | - /* Allocate the format ccw request. */ |
---|
2328 | | - fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, |
---|
2329 | | - datasize, startdev, NULL); |
---|
| 2679 | + |
---|
| 2680 | + fcp = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev); |
---|
2330 | 2681 | if (IS_ERR(fcp)) |
---|
2331 | 2682 | return fcp; |
---|
2332 | 2683 | |
---|
.. | .. |
---|
2499 | 2850 | struct dasd_ccw_req *ccw_req; |
---|
2500 | 2851 | |
---|
2501 | 2852 | if (!fmt_buffer) { |
---|
2502 | | - ccw_req = dasd_eckd_build_format(base, fdata, enable_pav); |
---|
| 2853 | + ccw_req = dasd_eckd_build_format(base, NULL, fdata, enable_pav); |
---|
2503 | 2854 | } else { |
---|
2504 | 2855 | if (tpm) |
---|
2505 | 2856 | ccw_req = dasd_eckd_build_check_tcw(base, fdata, |
---|
.. | .. |
---|
2645 | 2996 | rc = -EIO; |
---|
2646 | 2997 | } |
---|
2647 | 2998 | list_del_init(&cqr->blocklist); |
---|
2648 | | - dasd_sfree_request(cqr, device); |
---|
| 2999 | + dasd_ffree_request(cqr, device); |
---|
2649 | 3000 | private->count--; |
---|
2650 | 3001 | } |
---|
2651 | 3002 | |
---|
.. | .. |
---|
2682 | 3033 | { |
---|
2683 | 3034 | return dasd_eckd_format_process_data(base, fdata, enable_pav, 0, NULL, |
---|
2684 | 3035 | 0, NULL); |
---|
| 3036 | +} |
---|
| 3037 | + |
---|
| 3038 | +static bool test_and_set_format_track(struct dasd_format_entry *to_format, |
---|
| 3039 | + struct dasd_ccw_req *cqr) |
---|
| 3040 | +{ |
---|
| 3041 | + struct dasd_block *block = cqr->block; |
---|
| 3042 | + struct dasd_format_entry *format; |
---|
| 3043 | + unsigned long flags; |
---|
| 3044 | + bool rc = false; |
---|
| 3045 | + |
---|
| 3046 | + spin_lock_irqsave(&block->format_lock, flags); |
---|
| 3047 | + if (cqr->trkcount != atomic_read(&block->trkcount)) { |
---|
| 3048 | + /* |
---|
| 3049 | + * The number of formatted tracks has changed after request |
---|
| 3050 | + * start and we can not tell if the current track was involved. |
---|
| 3051 | + * To avoid data corruption treat it as if the current track is |
---|
| 3052 | + * involved |
---|
| 3053 | + */ |
---|
| 3054 | + rc = true; |
---|
| 3055 | + goto out; |
---|
| 3056 | + } |
---|
| 3057 | + list_for_each_entry(format, &block->format_list, list) { |
---|
| 3058 | + if (format->track == to_format->track) { |
---|
| 3059 | + rc = true; |
---|
| 3060 | + goto out; |
---|
| 3061 | + } |
---|
| 3062 | + } |
---|
| 3063 | + list_add_tail(&to_format->list, &block->format_list); |
---|
| 3064 | + |
---|
| 3065 | +out: |
---|
| 3066 | + spin_unlock_irqrestore(&block->format_lock, flags); |
---|
| 3067 | + return rc; |
---|
| 3068 | +} |
---|
| 3069 | + |
---|
| 3070 | +static void clear_format_track(struct dasd_format_entry *format, |
---|
| 3071 | + struct dasd_block *block) |
---|
| 3072 | +{ |
---|
| 3073 | + unsigned long flags; |
---|
| 3074 | + |
---|
| 3075 | + spin_lock_irqsave(&block->format_lock, flags); |
---|
| 3076 | + atomic_inc(&block->trkcount); |
---|
| 3077 | + list_del_init(&format->list); |
---|
| 3078 | + spin_unlock_irqrestore(&block->format_lock, flags); |
---|
| 3079 | +} |
---|
| 3080 | + |
---|
| 3081 | +/* |
---|
| 3082 | + * Callback function to free ESE format requests. |
---|
| 3083 | + */ |
---|
| 3084 | +static void dasd_eckd_ese_format_cb(struct dasd_ccw_req *cqr, void *data) |
---|
| 3085 | +{ |
---|
| 3086 | + struct dasd_device *device = cqr->startdev; |
---|
| 3087 | + struct dasd_eckd_private *private = device->private; |
---|
| 3088 | + struct dasd_format_entry *format = data; |
---|
| 3089 | + |
---|
| 3090 | + clear_format_track(format, cqr->basedev->block); |
---|
| 3091 | + private->count--; |
---|
| 3092 | + dasd_ffree_request(cqr, device); |
---|
| 3093 | +} |
---|
| 3094 | + |
---|
| 3095 | +static struct dasd_ccw_req * |
---|
| 3096 | +dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr, |
---|
| 3097 | + struct irb *irb) |
---|
| 3098 | +{ |
---|
| 3099 | + struct dasd_eckd_private *private; |
---|
| 3100 | + struct dasd_format_entry *format; |
---|
| 3101 | + struct format_data_t fdata; |
---|
| 3102 | + unsigned int recs_per_trk; |
---|
| 3103 | + struct dasd_ccw_req *fcqr; |
---|
| 3104 | + struct dasd_device *base; |
---|
| 3105 | + struct dasd_block *block; |
---|
| 3106 | + unsigned int blksize; |
---|
| 3107 | + struct request *req; |
---|
| 3108 | + sector_t first_trk; |
---|
| 3109 | + sector_t last_trk; |
---|
| 3110 | + sector_t curr_trk; |
---|
| 3111 | + int rc; |
---|
| 3112 | + |
---|
| 3113 | + req = dasd_get_callback_data(cqr); |
---|
| 3114 | + block = cqr->block; |
---|
| 3115 | + base = block->base; |
---|
| 3116 | + private = base->private; |
---|
| 3117 | + blksize = block->bp_block; |
---|
| 3118 | + recs_per_trk = recs_per_track(&private->rdc_data, 0, blksize); |
---|
| 3119 | + format = &startdev->format_entry; |
---|
| 3120 | + |
---|
| 3121 | + first_trk = blk_rq_pos(req) >> block->s2b_shift; |
---|
| 3122 | + sector_div(first_trk, recs_per_trk); |
---|
| 3123 | + last_trk = |
---|
| 3124 | + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; |
---|
| 3125 | + sector_div(last_trk, recs_per_trk); |
---|
| 3126 | + rc = dasd_eckd_track_from_irb(irb, base, &curr_trk); |
---|
| 3127 | + if (rc) |
---|
| 3128 | + return ERR_PTR(rc); |
---|
| 3129 | + |
---|
| 3130 | + if (curr_trk < first_trk || curr_trk > last_trk) { |
---|
| 3131 | + DBF_DEV_EVENT(DBF_WARNING, startdev, |
---|
| 3132 | + "ESE error track %llu not within range %llu - %llu\n", |
---|
| 3133 | + curr_trk, first_trk, last_trk); |
---|
| 3134 | + return ERR_PTR(-EINVAL); |
---|
| 3135 | + } |
---|
| 3136 | + format->track = curr_trk; |
---|
| 3137 | + /* test if track is already in formatting by another thread */ |
---|
| 3138 | + if (test_and_set_format_track(format, cqr)) { |
---|
| 3139 | + /* this is no real error so do not count down retries */ |
---|
| 3140 | + cqr->retries++; |
---|
| 3141 | + return ERR_PTR(-EEXIST); |
---|
| 3142 | + } |
---|
| 3143 | + |
---|
| 3144 | + fdata.start_unit = curr_trk; |
---|
| 3145 | + fdata.stop_unit = curr_trk; |
---|
| 3146 | + fdata.blksize = blksize; |
---|
| 3147 | + fdata.intensity = private->uses_cdl ? DASD_FMT_INT_COMPAT : 0; |
---|
| 3148 | + |
---|
| 3149 | + rc = dasd_eckd_format_sanity_checks(base, &fdata); |
---|
| 3150 | + if (rc) |
---|
| 3151 | + return ERR_PTR(-EINVAL); |
---|
| 3152 | + |
---|
| 3153 | + /* |
---|
| 3154 | + * We're building the request with PAV disabled as we're reusing |
---|
| 3155 | + * the former startdev. |
---|
| 3156 | + */ |
---|
| 3157 | + fcqr = dasd_eckd_build_format(base, startdev, &fdata, 0); |
---|
| 3158 | + if (IS_ERR(fcqr)) |
---|
| 3159 | + return fcqr; |
---|
| 3160 | + |
---|
| 3161 | + fcqr->callback = dasd_eckd_ese_format_cb; |
---|
| 3162 | + fcqr->callback_data = (void *) format; |
---|
| 3163 | + |
---|
| 3164 | + return fcqr; |
---|
| 3165 | +} |
---|
| 3166 | + |
---|
| 3167 | +/* |
---|
| 3168 | + * When data is read from an unformatted area of an ESE volume, this function |
---|
| 3169 | + * returns zeroed data and thereby mimics a read of zero data. |
---|
| 3170 | + * |
---|
| 3171 | + * The first unformatted track is the one that got the NRF error, the address is |
---|
| 3172 | + * encoded in the sense data. |
---|
| 3173 | + * |
---|
| 3174 | + * All tracks before have returned valid data and should not be touched. |
---|
| 3175 | + * All tracks after the unformatted track might be formatted or not. This is |
---|
| 3176 | + * currently not known, remember the processed data and return the remainder of |
---|
| 3177 | + * the request to the blocklayer in __dasd_cleanup_cqr(). |
---|
| 3178 | + */ |
---|
| 3179 | +static int dasd_eckd_ese_read(struct dasd_ccw_req *cqr, struct irb *irb) |
---|
| 3180 | +{ |
---|
| 3181 | + struct dasd_eckd_private *private; |
---|
| 3182 | + sector_t first_trk, last_trk; |
---|
| 3183 | + sector_t first_blk, last_blk; |
---|
| 3184 | + unsigned int blksize, off; |
---|
| 3185 | + unsigned int recs_per_trk; |
---|
| 3186 | + struct dasd_device *base; |
---|
| 3187 | + struct req_iterator iter; |
---|
| 3188 | + struct dasd_block *block; |
---|
| 3189 | + unsigned int skip_block; |
---|
| 3190 | + unsigned int blk_count; |
---|
| 3191 | + struct request *req; |
---|
| 3192 | + struct bio_vec bv; |
---|
| 3193 | + sector_t curr_trk; |
---|
| 3194 | + sector_t end_blk; |
---|
| 3195 | + char *dst; |
---|
| 3196 | + int rc; |
---|
| 3197 | + |
---|
| 3198 | + req = (struct request *) cqr->callback_data; |
---|
| 3199 | + base = cqr->block->base; |
---|
| 3200 | + blksize = base->block->bp_block; |
---|
| 3201 | + block = cqr->block; |
---|
| 3202 | + private = base->private; |
---|
| 3203 | + skip_block = 0; |
---|
| 3204 | + blk_count = 0; |
---|
| 3205 | + |
---|
| 3206 | + recs_per_trk = recs_per_track(&private->rdc_data, 0, blksize); |
---|
| 3207 | + first_trk = first_blk = blk_rq_pos(req) >> block->s2b_shift; |
---|
| 3208 | + sector_div(first_trk, recs_per_trk); |
---|
| 3209 | + last_trk = last_blk = |
---|
| 3210 | + (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift; |
---|
| 3211 | + sector_div(last_trk, recs_per_trk); |
---|
| 3212 | + rc = dasd_eckd_track_from_irb(irb, base, &curr_trk); |
---|
| 3213 | + if (rc) |
---|
| 3214 | + return rc; |
---|
| 3215 | + |
---|
| 3216 | + /* sanity check if the current track from sense data is valid */ |
---|
| 3217 | + if (curr_trk < first_trk || curr_trk > last_trk) { |
---|
| 3218 | + DBF_DEV_EVENT(DBF_WARNING, base, |
---|
| 3219 | + "ESE error track %llu not within range %llu - %llu\n", |
---|
| 3220 | + curr_trk, first_trk, last_trk); |
---|
| 3221 | + return -EINVAL; |
---|
| 3222 | + } |
---|
| 3223 | + |
---|
| 3224 | + /* |
---|
| 3225 | + * if not the first track got the NRF error we have to skip over valid |
---|
| 3226 | + * blocks |
---|
| 3227 | + */ |
---|
| 3228 | + if (curr_trk != first_trk) |
---|
| 3229 | + skip_block = curr_trk * recs_per_trk - first_blk; |
---|
| 3230 | + |
---|
| 3231 | + /* we have no information beyond the current track */ |
---|
| 3232 | + end_blk = (curr_trk + 1) * recs_per_trk; |
---|
| 3233 | + |
---|
| 3234 | + rq_for_each_segment(bv, req, iter) { |
---|
| 3235 | + dst = page_address(bv.bv_page) + bv.bv_offset; |
---|
| 3236 | + for (off = 0; off < bv.bv_len; off += blksize) { |
---|
| 3237 | + if (first_blk + blk_count >= end_blk) { |
---|
| 3238 | + cqr->proc_bytes = blk_count * blksize; |
---|
| 3239 | + return 0; |
---|
| 3240 | + } |
---|
| 3241 | + if (dst && !skip_block) |
---|
| 3242 | + memset(dst, 0, blksize); |
---|
| 3243 | + else |
---|
| 3244 | + skip_block--; |
---|
| 3245 | + dst += blksize; |
---|
| 3246 | + blk_count++; |
---|
| 3247 | + } |
---|
| 3248 | + } |
---|
| 3249 | + return 0; |
---|
2685 | 3250 | } |
---|
2686 | 3251 | |
---|
2687 | 3252 | /* |
---|
.. | .. |
---|
3019 | 3584 | } |
---|
3020 | 3585 | } |
---|
3021 | 3586 | |
---|
| 3587 | +static int dasd_eckd_ras_sanity_checks(struct dasd_device *device, |
---|
| 3588 | + unsigned int first_trk, |
---|
| 3589 | + unsigned int last_trk) |
---|
| 3590 | +{ |
---|
| 3591 | + struct dasd_eckd_private *private = device->private; |
---|
| 3592 | + unsigned int trks_per_vol; |
---|
| 3593 | + int rc = 0; |
---|
| 3594 | + |
---|
| 3595 | + trks_per_vol = private->real_cyl * private->rdc_data.trk_per_cyl; |
---|
| 3596 | + |
---|
| 3597 | + if (first_trk >= trks_per_vol) { |
---|
| 3598 | + dev_warn(&device->cdev->dev, |
---|
| 3599 | + "Start track number %u used in the space release command is too big\n", |
---|
| 3600 | + first_trk); |
---|
| 3601 | + rc = -EINVAL; |
---|
| 3602 | + } else if (last_trk >= trks_per_vol) { |
---|
| 3603 | + dev_warn(&device->cdev->dev, |
---|
| 3604 | + "Stop track number %u used in the space release command is too big\n", |
---|
| 3605 | + last_trk); |
---|
| 3606 | + rc = -EINVAL; |
---|
| 3607 | + } else if (first_trk > last_trk) { |
---|
| 3608 | + dev_warn(&device->cdev->dev, |
---|
| 3609 | + "Start track %u used in the space release command exceeds the end track\n", |
---|
| 3610 | + first_trk); |
---|
| 3611 | + rc = -EINVAL; |
---|
| 3612 | + } |
---|
| 3613 | + return rc; |
---|
| 3614 | +} |
---|
| 3615 | + |
---|
| 3616 | +/* |
---|
| 3617 | + * Helper function to count the amount of involved extents within a given range |
---|
| 3618 | + * with extent alignment in mind. |
---|
| 3619 | + */ |
---|
| 3620 | +static int count_exts(unsigned int from, unsigned int to, int trks_per_ext) |
---|
| 3621 | +{ |
---|
| 3622 | + int cur_pos = 0; |
---|
| 3623 | + int count = 0; |
---|
| 3624 | + int tmp; |
---|
| 3625 | + |
---|
| 3626 | + if (from == to) |
---|
| 3627 | + return 1; |
---|
| 3628 | + |
---|
| 3629 | + /* Count first partial extent */ |
---|
| 3630 | + if (from % trks_per_ext != 0) { |
---|
| 3631 | + tmp = from + trks_per_ext - (from % trks_per_ext) - 1; |
---|
| 3632 | + if (tmp > to) |
---|
| 3633 | + tmp = to; |
---|
| 3634 | + cur_pos = tmp - from + 1; |
---|
| 3635 | + count++; |
---|
| 3636 | + } |
---|
| 3637 | + /* Count full extents */ |
---|
| 3638 | + if (to - (from + cur_pos) + 1 >= trks_per_ext) { |
---|
| 3639 | + tmp = to - ((to - trks_per_ext + 1) % trks_per_ext); |
---|
| 3640 | + count += (tmp - (from + cur_pos) + 1) / trks_per_ext; |
---|
| 3641 | + cur_pos = tmp; |
---|
| 3642 | + } |
---|
| 3643 | + /* Count last partial extent */ |
---|
| 3644 | + if (cur_pos < to) |
---|
| 3645 | + count++; |
---|
| 3646 | + |
---|
| 3647 | + return count; |
---|
| 3648 | +} |
---|
| 3649 | + |
---|
| 3650 | +/* |
---|
| 3651 | + * Release allocated space for a given range or an entire volume. |
---|
| 3652 | + */ |
---|
| 3653 | +static struct dasd_ccw_req * |
---|
| 3654 | +dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block, |
---|
| 3655 | + struct request *req, unsigned int first_trk, |
---|
| 3656 | + unsigned int last_trk, int by_extent) |
---|
| 3657 | +{ |
---|
| 3658 | + struct dasd_eckd_private *private = device->private; |
---|
| 3659 | + struct dasd_dso_ras_ext_range *ras_range; |
---|
| 3660 | + struct dasd_rssd_features *features; |
---|
| 3661 | + struct dasd_dso_ras_data *ras_data; |
---|
| 3662 | + u16 heads, beg_head, end_head; |
---|
| 3663 | + int cur_to_trk, cur_from_trk; |
---|
| 3664 | + struct dasd_ccw_req *cqr; |
---|
| 3665 | + u32 beg_cyl, end_cyl; |
---|
| 3666 | + struct ccw1 *ccw; |
---|
| 3667 | + int trks_per_ext; |
---|
| 3668 | + size_t ras_size; |
---|
| 3669 | + size_t size; |
---|
| 3670 | + int nr_exts; |
---|
| 3671 | + void *rq; |
---|
| 3672 | + int i; |
---|
| 3673 | + |
---|
| 3674 | + if (dasd_eckd_ras_sanity_checks(device, first_trk, last_trk)) |
---|
| 3675 | + return ERR_PTR(-EINVAL); |
---|
| 3676 | + |
---|
| 3677 | + rq = req ? blk_mq_rq_to_pdu(req) : NULL; |
---|
| 3678 | + |
---|
| 3679 | + features = &private->features; |
---|
| 3680 | + |
---|
| 3681 | + trks_per_ext = dasd_eckd_ext_size(device) * private->rdc_data.trk_per_cyl; |
---|
| 3682 | + nr_exts = 0; |
---|
| 3683 | + if (by_extent) |
---|
| 3684 | + nr_exts = count_exts(first_trk, last_trk, trks_per_ext); |
---|
| 3685 | + ras_size = sizeof(*ras_data); |
---|
| 3686 | + size = ras_size + (nr_exts * sizeof(*ras_range)); |
---|
| 3687 | + |
---|
| 3688 | + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, size, device, rq); |
---|
| 3689 | + if (IS_ERR(cqr)) { |
---|
| 3690 | + DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", |
---|
| 3691 | + "Could not allocate RAS request"); |
---|
| 3692 | + return cqr; |
---|
| 3693 | + } |
---|
| 3694 | + |
---|
| 3695 | + ras_data = cqr->data; |
---|
| 3696 | + memset(ras_data, 0, size); |
---|
| 3697 | + |
---|
| 3698 | + ras_data->order = DSO_ORDER_RAS; |
---|
| 3699 | + ras_data->flags.vol_type = 0; /* CKD volume */ |
---|
| 3700 | + /* Release specified extents or entire volume */ |
---|
| 3701 | + ras_data->op_flags.by_extent = by_extent; |
---|
| 3702 | + /* |
---|
| 3703 | + * This bit guarantees initialisation of tracks within an extent that is |
---|
| 3704 | + * not fully specified, but is only supported with a certain feature |
---|
| 3705 | + * subset. |
---|
| 3706 | + */ |
---|
| 3707 | + ras_data->op_flags.guarantee_init = !!(features->feature[56] & 0x01); |
---|
| 3708 | + ras_data->lss = private->ned->ID; |
---|
| 3709 | + ras_data->dev_addr = private->ned->unit_addr; |
---|
| 3710 | + ras_data->nr_exts = nr_exts; |
---|
| 3711 | + |
---|
| 3712 | + if (by_extent) { |
---|
| 3713 | + heads = private->rdc_data.trk_per_cyl; |
---|
| 3714 | + cur_from_trk = first_trk; |
---|
| 3715 | + cur_to_trk = first_trk + trks_per_ext - |
---|
| 3716 | + (first_trk % trks_per_ext) - 1; |
---|
| 3717 | + if (cur_to_trk > last_trk) |
---|
| 3718 | + cur_to_trk = last_trk; |
---|
| 3719 | + ras_range = (struct dasd_dso_ras_ext_range *)(cqr->data + ras_size); |
---|
| 3720 | + |
---|
| 3721 | + for (i = 0; i < nr_exts; i++) { |
---|
| 3722 | + beg_cyl = cur_from_trk / heads; |
---|
| 3723 | + beg_head = cur_from_trk % heads; |
---|
| 3724 | + end_cyl = cur_to_trk / heads; |
---|
| 3725 | + end_head = cur_to_trk % heads; |
---|
| 3726 | + |
---|
| 3727 | + set_ch_t(&ras_range->beg_ext, beg_cyl, beg_head); |
---|
| 3728 | + set_ch_t(&ras_range->end_ext, end_cyl, end_head); |
---|
| 3729 | + |
---|
| 3730 | + cur_from_trk = cur_to_trk + 1; |
---|
| 3731 | + cur_to_trk = cur_from_trk + trks_per_ext - 1; |
---|
| 3732 | + if (cur_to_trk > last_trk) |
---|
| 3733 | + cur_to_trk = last_trk; |
---|
| 3734 | + ras_range++; |
---|
| 3735 | + } |
---|
| 3736 | + } |
---|
| 3737 | + |
---|
| 3738 | + ccw = cqr->cpaddr; |
---|
| 3739 | + ccw->cda = (__u32)(addr_t)cqr->data; |
---|
| 3740 | + ccw->cmd_code = DASD_ECKD_CCW_DSO; |
---|
| 3741 | + ccw->count = size; |
---|
| 3742 | + |
---|
| 3743 | + cqr->startdev = device; |
---|
| 3744 | + cqr->memdev = device; |
---|
| 3745 | + cqr->block = block; |
---|
| 3746 | + cqr->retries = 256; |
---|
| 3747 | + cqr->expires = device->default_expires * HZ; |
---|
| 3748 | + cqr->buildclk = get_tod_clock(); |
---|
| 3749 | + cqr->status = DASD_CQR_FILLED; |
---|
| 3750 | + |
---|
| 3751 | + return cqr; |
---|
| 3752 | +} |
---|
| 3753 | + |
---|
| 3754 | +static int dasd_eckd_release_space_full(struct dasd_device *device) |
---|
| 3755 | +{ |
---|
| 3756 | + struct dasd_ccw_req *cqr; |
---|
| 3757 | + int rc; |
---|
| 3758 | + |
---|
| 3759 | + cqr = dasd_eckd_dso_ras(device, NULL, NULL, 0, 0, 0); |
---|
| 3760 | + if (IS_ERR(cqr)) |
---|
| 3761 | + return PTR_ERR(cqr); |
---|
| 3762 | + |
---|
| 3763 | + rc = dasd_sleep_on_interruptible(cqr); |
---|
| 3764 | + |
---|
| 3765 | + dasd_sfree_request(cqr, cqr->memdev); |
---|
| 3766 | + |
---|
| 3767 | + return rc; |
---|
| 3768 | +} |
---|
| 3769 | + |
---|
| 3770 | +static int dasd_eckd_release_space_trks(struct dasd_device *device, |
---|
| 3771 | + unsigned int from, unsigned int to) |
---|
| 3772 | +{ |
---|
| 3773 | + struct dasd_eckd_private *private = device->private; |
---|
| 3774 | + struct dasd_block *block = device->block; |
---|
| 3775 | + struct dasd_ccw_req *cqr, *n; |
---|
| 3776 | + struct list_head ras_queue; |
---|
| 3777 | + unsigned int device_exts; |
---|
| 3778 | + int trks_per_ext; |
---|
| 3779 | + int stop, step; |
---|
| 3780 | + int cur_pos; |
---|
| 3781 | + int rc = 0; |
---|
| 3782 | + int retry; |
---|
| 3783 | + |
---|
| 3784 | + INIT_LIST_HEAD(&ras_queue); |
---|
| 3785 | + |
---|
| 3786 | + device_exts = private->real_cyl / dasd_eckd_ext_size(device); |
---|
| 3787 | + trks_per_ext = dasd_eckd_ext_size(device) * private->rdc_data.trk_per_cyl; |
---|
| 3788 | + |
---|
| 3789 | + /* Make sure device limits are not exceeded */ |
---|
| 3790 | + step = trks_per_ext * min(device_exts, DASD_ECKD_RAS_EXTS_MAX); |
---|
| 3791 | + cur_pos = from; |
---|
| 3792 | + |
---|
| 3793 | + do { |
---|
| 3794 | + retry = 0; |
---|
| 3795 | + while (cur_pos < to) { |
---|
| 3796 | + stop = cur_pos + step - |
---|
| 3797 | + ((cur_pos + step) % trks_per_ext) - 1; |
---|
| 3798 | + if (stop > to) |
---|
| 3799 | + stop = to; |
---|
| 3800 | + |
---|
| 3801 | + cqr = dasd_eckd_dso_ras(device, NULL, NULL, cur_pos, stop, 1); |
---|
| 3802 | + if (IS_ERR(cqr)) { |
---|
| 3803 | + rc = PTR_ERR(cqr); |
---|
| 3804 | + if (rc == -ENOMEM) { |
---|
| 3805 | + if (list_empty(&ras_queue)) |
---|
| 3806 | + goto out; |
---|
| 3807 | + retry = 1; |
---|
| 3808 | + break; |
---|
| 3809 | + } |
---|
| 3810 | + goto err_out; |
---|
| 3811 | + } |
---|
| 3812 | + |
---|
| 3813 | + spin_lock_irq(&block->queue_lock); |
---|
| 3814 | + list_add_tail(&cqr->blocklist, &ras_queue); |
---|
| 3815 | + spin_unlock_irq(&block->queue_lock); |
---|
| 3816 | + cur_pos = stop + 1; |
---|
| 3817 | + } |
---|
| 3818 | + |
---|
| 3819 | + rc = dasd_sleep_on_queue_interruptible(&ras_queue); |
---|
| 3820 | + |
---|
| 3821 | +err_out: |
---|
| 3822 | + list_for_each_entry_safe(cqr, n, &ras_queue, blocklist) { |
---|
| 3823 | + device = cqr->startdev; |
---|
| 3824 | + private = device->private; |
---|
| 3825 | + |
---|
| 3826 | + spin_lock_irq(&block->queue_lock); |
---|
| 3827 | + list_del_init(&cqr->blocklist); |
---|
| 3828 | + spin_unlock_irq(&block->queue_lock); |
---|
| 3829 | + dasd_sfree_request(cqr, device); |
---|
| 3830 | + private->count--; |
---|
| 3831 | + } |
---|
| 3832 | + } while (retry); |
---|
| 3833 | + |
---|
| 3834 | +out: |
---|
| 3835 | + return rc; |
---|
| 3836 | +} |
---|
| 3837 | + |
---|
| 3838 | +static int dasd_eckd_release_space(struct dasd_device *device, |
---|
| 3839 | + struct format_data_t *rdata) |
---|
| 3840 | +{ |
---|
| 3841 | + if (rdata->intensity & DASD_FMT_INT_ESE_FULL) |
---|
| 3842 | + return dasd_eckd_release_space_full(device); |
---|
| 3843 | + else if (rdata->intensity == 0) |
---|
| 3844 | + return dasd_eckd_release_space_trks(device, rdata->start_unit, |
---|
| 3845 | + rdata->stop_unit); |
---|
| 3846 | + else |
---|
| 3847 | + return -EINVAL; |
---|
| 3848 | +} |
---|
| 3849 | + |
---|
3022 | 3850 | static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( |
---|
3023 | 3851 | struct dasd_device *startdev, |
---|
3024 | 3852 | struct dasd_block *block, |
---|
.. | .. |
---|
3200 | 4028 | cqr->retries = startdev->default_retries; |
---|
3201 | 4029 | cqr->buildclk = get_tod_clock(); |
---|
3202 | 4030 | cqr->status = DASD_CQR_FILLED; |
---|
| 4031 | + |
---|
| 4032 | + /* Set flags to suppress output for expected errors */ |
---|
| 4033 | + if (dasd_eckd_is_ese(basedev)) { |
---|
| 4034 | + set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags); |
---|
| 4035 | + set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags); |
---|
| 4036 | + set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); |
---|
| 4037 | + } |
---|
| 4038 | + |
---|
3203 | 4039 | return cqr; |
---|
3204 | 4040 | } |
---|
3205 | 4041 | |
---|
.. | .. |
---|
3371 | 4207 | cqr->retries = startdev->default_retries; |
---|
3372 | 4208 | cqr->buildclk = get_tod_clock(); |
---|
3373 | 4209 | cqr->status = DASD_CQR_FILLED; |
---|
| 4210 | + |
---|
| 4211 | + /* Set flags to suppress output for expected errors */ |
---|
| 4212 | + if (dasd_eckd_is_ese(basedev)) |
---|
| 4213 | + set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); |
---|
| 4214 | + |
---|
3374 | 4215 | return cqr; |
---|
3375 | 4216 | } |
---|
3376 | 4217 | |
---|
.. | .. |
---|
3690 | 4531 | cqr->retries = startdev->default_retries; |
---|
3691 | 4532 | cqr->buildclk = get_tod_clock(); |
---|
3692 | 4533 | cqr->status = DASD_CQR_FILLED; |
---|
| 4534 | + |
---|
| 4535 | + /* Set flags to suppress output for expected errors */ |
---|
| 4536 | + if (dasd_eckd_is_ese(basedev)) { |
---|
| 4537 | + set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags); |
---|
| 4538 | + set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags); |
---|
| 4539 | + set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); |
---|
| 4540 | + } |
---|
| 4541 | + |
---|
3693 | 4542 | return cqr; |
---|
3694 | 4543 | out_error: |
---|
3695 | 4544 | dasd_sfree_request(cqr, startdev); |
---|
.. | .. |
---|
3788 | 4637 | struct dasd_device *basedev; |
---|
3789 | 4638 | struct req_iterator iter; |
---|
3790 | 4639 | struct dasd_ccw_req *cqr; |
---|
3791 | | - unsigned int first_offs; |
---|
3792 | 4640 | unsigned int trkcount; |
---|
3793 | 4641 | unsigned long *idaws; |
---|
3794 | 4642 | unsigned int size; |
---|
.. | .. |
---|
3813 | 4661 | if ((start_padding_sectors || end_padding_sectors) && |
---|
3814 | 4662 | (rq_data_dir(req) == WRITE)) { |
---|
3815 | 4663 | DBF_DEV_EVENT(DBF_ERR, basedev, |
---|
3816 | | - "raw write not track aligned (%lu,%lu) req %p", |
---|
| 4664 | + "raw write not track aligned (%llu,%llu) req %p", |
---|
3817 | 4665 | start_padding_sectors, end_padding_sectors, req); |
---|
3818 | 4666 | return ERR_PTR(-EINVAL); |
---|
3819 | 4667 | } |
---|
.. | .. |
---|
3822 | 4670 | last_trk = (blk_rq_pos(req) + blk_rq_sectors(req) - 1) / |
---|
3823 | 4671 | DASD_RAW_SECTORS_PER_TRACK; |
---|
3824 | 4672 | trkcount = last_trk - first_trk + 1; |
---|
3825 | | - first_offs = 0; |
---|
3826 | 4673 | |
---|
3827 | 4674 | if (rq_data_dir(req) == READ) |
---|
3828 | 4675 | cmd = DASD_ECKD_CCW_READ_TRACK; |
---|
.. | .. |
---|
3866 | 4713 | |
---|
3867 | 4714 | if (use_prefix) { |
---|
3868 | 4715 | prefix_LRE(ccw++, data, first_trk, last_trk, cmd, basedev, |
---|
3869 | | - startdev, 1, first_offs + 1, trkcount, 0, 0); |
---|
| 4716 | + startdev, 1, 0, trkcount, 0, 0); |
---|
3870 | 4717 | } else { |
---|
3871 | 4718 | define_extent(ccw++, data, first_trk, last_trk, cmd, basedev, 0); |
---|
3872 | 4719 | ccw[-1].flags |= CCW_FLAG_CC; |
---|
3873 | 4720 | |
---|
3874 | 4721 | data += sizeof(struct DE_eckd_data); |
---|
3875 | | - locate_record_ext(ccw++, data, first_trk, first_offs + 1, |
---|
| 4722 | + locate_record_ext(ccw++, data, first_trk, 0, |
---|
3876 | 4723 | trkcount, cmd, basedev, 0, 0); |
---|
3877 | 4724 | } |
---|
3878 | 4725 | |
---|
.. | .. |
---|
4951 | 5798 | /* Read Feature Codes */ |
---|
4952 | 5799 | dasd_eckd_read_features(device); |
---|
4953 | 5800 | |
---|
| 5801 | + /* Read Volume Information */ |
---|
| 5802 | + dasd_eckd_read_vol_info(device); |
---|
| 5803 | + |
---|
| 5804 | + /* Read Extent Pool Information */ |
---|
| 5805 | + dasd_eckd_read_ext_pool_info(device); |
---|
| 5806 | + |
---|
4954 | 5807 | /* Read Device Characteristics */ |
---|
4955 | 5808 | rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC, |
---|
4956 | 5809 | &temp_rdc_data, 64); |
---|
.. | .. |
---|
5621 | 6474 | device->discipline->check_attention(device, lpum); |
---|
5622 | 6475 | } |
---|
5623 | 6476 | |
---|
| 6477 | +static void dasd_eckd_oos_resume(struct dasd_device *device) |
---|
| 6478 | +{ |
---|
| 6479 | + struct dasd_eckd_private *private = device->private; |
---|
| 6480 | + struct alias_pav_group *pavgroup, *tempgroup; |
---|
| 6481 | + struct dasd_device *dev, *n; |
---|
| 6482 | + unsigned long flags; |
---|
| 6483 | + |
---|
| 6484 | + spin_lock_irqsave(&private->lcu->lock, flags); |
---|
| 6485 | + list_for_each_entry_safe(dev, n, &private->lcu->active_devices, |
---|
| 6486 | + alias_list) { |
---|
| 6487 | + if (dev->stopped & DASD_STOPPED_NOSPC) |
---|
| 6488 | + dasd_generic_space_avail(dev); |
---|
| 6489 | + } |
---|
| 6490 | + list_for_each_entry_safe(dev, n, &private->lcu->inactive_devices, |
---|
| 6491 | + alias_list) { |
---|
| 6492 | + if (dev->stopped & DASD_STOPPED_NOSPC) |
---|
| 6493 | + dasd_generic_space_avail(dev); |
---|
| 6494 | + } |
---|
| 6495 | + /* devices in PAV groups */ |
---|
| 6496 | + list_for_each_entry_safe(pavgroup, tempgroup, |
---|
| 6497 | + &private->lcu->grouplist, |
---|
| 6498 | + group) { |
---|
| 6499 | + list_for_each_entry_safe(dev, n, &pavgroup->baselist, |
---|
| 6500 | + alias_list) { |
---|
| 6501 | + if (dev->stopped & DASD_STOPPED_NOSPC) |
---|
| 6502 | + dasd_generic_space_avail(dev); |
---|
| 6503 | + } |
---|
| 6504 | + list_for_each_entry_safe(dev, n, &pavgroup->aliaslist, |
---|
| 6505 | + alias_list) { |
---|
| 6506 | + if (dev->stopped & DASD_STOPPED_NOSPC) |
---|
| 6507 | + dasd_generic_space_avail(dev); |
---|
| 6508 | + } |
---|
| 6509 | + } |
---|
| 6510 | + spin_unlock_irqrestore(&private->lcu->lock, flags); |
---|
| 6511 | +} |
---|
| 6512 | + |
---|
| 6513 | +static void dasd_eckd_handle_oos(struct dasd_device *device, void *messages, |
---|
| 6514 | + __u8 lpum) |
---|
| 6515 | +{ |
---|
| 6516 | + struct dasd_oos_message *oos = messages; |
---|
| 6517 | + |
---|
| 6518 | + switch (oos->code) { |
---|
| 6519 | + case REPO_WARN: |
---|
| 6520 | + case POOL_WARN: |
---|
| 6521 | + dev_warn(&device->cdev->dev, |
---|
| 6522 | + "Extent pool usage has reached a critical value\n"); |
---|
| 6523 | + dasd_eckd_oos_resume(device); |
---|
| 6524 | + break; |
---|
| 6525 | + case REPO_EXHAUST: |
---|
| 6526 | + case POOL_EXHAUST: |
---|
| 6527 | + dev_warn(&device->cdev->dev, |
---|
| 6528 | + "Extent pool is exhausted\n"); |
---|
| 6529 | + break; |
---|
| 6530 | + case REPO_RELIEVE: |
---|
| 6531 | + case POOL_RELIEVE: |
---|
| 6532 | + dev_info(&device->cdev->dev, |
---|
| 6533 | + "Extent pool physical space constraint has been relieved\n"); |
---|
| 6534 | + break; |
---|
| 6535 | + } |
---|
| 6536 | + |
---|
| 6537 | + /* In any case, update related data */ |
---|
| 6538 | + dasd_eckd_read_ext_pool_info(device); |
---|
| 6539 | + |
---|
| 6540 | + /* to make sure there is no attention left schedule work again */ |
---|
| 6541 | + device->discipline->check_attention(device, lpum); |
---|
| 6542 | +} |
---|
| 6543 | + |
---|
5624 | 6544 | static void dasd_eckd_check_attention_work(struct work_struct *work) |
---|
5625 | 6545 | { |
---|
5626 | 6546 | struct check_attention_work_data *data; |
---|
.. | .. |
---|
5639 | 6559 | rc = dasd_eckd_read_message_buffer(device, messages, data->lpum); |
---|
5640 | 6560 | if (rc) |
---|
5641 | 6561 | goto out; |
---|
| 6562 | + |
---|
5642 | 6563 | if (messages->length == ATTENTION_LENGTH_CUIR && |
---|
5643 | 6564 | messages->format == ATTENTION_FORMAT_CUIR) |
---|
5644 | 6565 | dasd_eckd_handle_cuir(device, messages, data->lpum); |
---|
| 6566 | + if (messages->length == ATTENTION_LENGTH_OOS && |
---|
| 6567 | + messages->format == ATTENTION_FORMAT_OOS) |
---|
| 6568 | + dasd_eckd_handle_oos(device, messages, data->lpum); |
---|
| 6569 | + |
---|
5645 | 6570 | out: |
---|
5646 | 6571 | dasd_put_device(device); |
---|
5647 | 6572 | kfree(messages); |
---|
.. | .. |
---|
5720 | 6645 | dasd_schedule_requeue(device); |
---|
5721 | 6646 | } |
---|
5722 | 6647 | |
---|
| 6648 | +/* |
---|
| 6649 | + * Initialize block layer request queue. |
---|
| 6650 | + */ |
---|
| 6651 | +static void dasd_eckd_setup_blk_queue(struct dasd_block *block) |
---|
| 6652 | +{ |
---|
| 6653 | + unsigned int logical_block_size = block->bp_block; |
---|
| 6654 | + struct request_queue *q = block->request_queue; |
---|
| 6655 | + struct dasd_device *device = block->base; |
---|
| 6656 | + int max; |
---|
| 6657 | + |
---|
| 6658 | + if (device->features & DASD_FEATURE_USERAW) { |
---|
| 6659 | + /* |
---|
| 6660 | + * the max_blocks value for raw_track access is 256 |
---|
| 6661 | + * it is higher than the native ECKD value because we |
---|
| 6662 | + * only need one ccw per track |
---|
| 6663 | + * so the max_hw_sectors are |
---|
| 6664 | + * 2048 x 512B = 1024kB = 16 tracks |
---|
| 6665 | + */ |
---|
| 6666 | + max = DASD_ECKD_MAX_BLOCKS_RAW << block->s2b_shift; |
---|
| 6667 | + } else { |
---|
| 6668 | + max = DASD_ECKD_MAX_BLOCKS << block->s2b_shift; |
---|
| 6669 | + } |
---|
| 6670 | + blk_queue_flag_set(QUEUE_FLAG_NONROT, q); |
---|
| 6671 | + q->limits.max_dev_sectors = max; |
---|
| 6672 | + blk_queue_logical_block_size(q, logical_block_size); |
---|
| 6673 | + blk_queue_max_hw_sectors(q, max); |
---|
| 6674 | + blk_queue_max_segments(q, USHRT_MAX); |
---|
| 6675 | + /* With page sized segments each segment can be translated into one idaw/tidaw */ |
---|
| 6676 | + blk_queue_max_segment_size(q, PAGE_SIZE); |
---|
| 6677 | + blk_queue_segment_boundary(q, PAGE_SIZE - 1); |
---|
| 6678 | +} |
---|
| 6679 | + |
---|
5723 | 6680 | static struct ccw_driver dasd_eckd_driver = { |
---|
5724 | 6681 | .driver = { |
---|
5725 | 6682 | .name = "dasd-eckd", |
---|
.. | .. |
---|
5740 | 6697 | .int_class = IRQIO_DAS, |
---|
5741 | 6698 | }; |
---|
5742 | 6699 | |
---|
5743 | | -/* |
---|
5744 | | - * max_blocks is dependent on the amount of storage that is available |
---|
5745 | | - * in the static io buffer for each device. Currently each device has |
---|
5746 | | - * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has |
---|
5747 | | - * 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use |
---|
5748 | | - * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In |
---|
5749 | | - * addition we have one define extent ccw + 16 bytes of data and one |
---|
5750 | | - * locate record ccw + 16 bytes of data. That makes: |
---|
5751 | | - * (8192 - 24 - 136 - 8 - 16 - 8 - 16) / 16 = 499 blocks at maximum. |
---|
5752 | | - * We want to fit two into the available memory so that we can immediately |
---|
5753 | | - * start the next request if one finishes off. That makes 249.5 blocks |
---|
5754 | | - * for one request. Give a little safety and the result is 240. |
---|
5755 | | - */ |
---|
5756 | 6700 | static struct dasd_discipline dasd_eckd_discipline = { |
---|
5757 | 6701 | .owner = THIS_MODULE, |
---|
5758 | 6702 | .name = "ECKD", |
---|
5759 | 6703 | .ebcname = "ECKD", |
---|
5760 | | - .max_blocks = 190, |
---|
5761 | 6704 | .check_device = dasd_eckd_check_characteristics, |
---|
5762 | 6705 | .uncheck_device = dasd_eckd_uncheck_device, |
---|
5763 | 6706 | .do_analysis = dasd_eckd_do_analysis, |
---|
5764 | | - .verify_path = dasd_eckd_verify_path, |
---|
| 6707 | + .pe_handler = dasd_eckd_pe_handler, |
---|
5765 | 6708 | .basic_to_ready = dasd_eckd_basic_to_ready, |
---|
5766 | 6709 | .online_to_ready = dasd_eckd_online_to_ready, |
---|
5767 | 6710 | .basic_to_known = dasd_eckd_basic_to_known, |
---|
| 6711 | + .setup_blk_queue = dasd_eckd_setup_blk_queue, |
---|
5768 | 6712 | .fill_geometry = dasd_eckd_fill_geometry, |
---|
5769 | 6713 | .start_IO = dasd_start_IO, |
---|
5770 | 6714 | .term_IO = dasd_term_IO, |
---|
.. | .. |
---|
5792 | 6736 | .disable_hpf = dasd_eckd_disable_hpf_device, |
---|
5793 | 6737 | .hpf_enabled = dasd_eckd_hpf_enabled, |
---|
5794 | 6738 | .reset_path = dasd_eckd_reset_path, |
---|
| 6739 | + .is_ese = dasd_eckd_is_ese, |
---|
| 6740 | + .space_allocated = dasd_eckd_space_allocated, |
---|
| 6741 | + .space_configured = dasd_eckd_space_configured, |
---|
| 6742 | + .logical_capacity = dasd_eckd_logical_capacity, |
---|
| 6743 | + .release_space = dasd_eckd_release_space, |
---|
| 6744 | + .ext_pool_id = dasd_eckd_ext_pool_id, |
---|
| 6745 | + .ext_size = dasd_eckd_ext_size, |
---|
| 6746 | + .ext_pool_cap_at_warnlevel = dasd_eckd_ext_pool_cap_at_warnlevel, |
---|
| 6747 | + .ext_pool_warn_thrshld = dasd_eckd_ext_pool_warn_thrshld, |
---|
| 6748 | + .ext_pool_oos = dasd_eckd_ext_pool_oos, |
---|
| 6749 | + .ext_pool_exhaust = dasd_eckd_ext_pool_exhaust, |
---|
| 6750 | + .ese_format = dasd_eckd_ese_format, |
---|
| 6751 | + .ese_read = dasd_eckd_ese_read, |
---|
5795 | 6752 | }; |
---|
5796 | 6753 | |
---|
5797 | 6754 | static int __init |
---|
.. | .. |
---|
5804 | 6761 | GFP_KERNEL | GFP_DMA); |
---|
5805 | 6762 | if (!dasd_reserve_req) |
---|
5806 | 6763 | return -ENOMEM; |
---|
5807 | | - path_verification_worker = kmalloc(sizeof(*path_verification_worker), |
---|
5808 | | - GFP_KERNEL | GFP_DMA); |
---|
5809 | | - if (!path_verification_worker) { |
---|
| 6764 | + dasd_vol_info_req = kmalloc(sizeof(*dasd_vol_info_req), |
---|
| 6765 | + GFP_KERNEL | GFP_DMA); |
---|
| 6766 | + if (!dasd_vol_info_req) { |
---|
5810 | 6767 | kfree(dasd_reserve_req); |
---|
| 6768 | + return -ENOMEM; |
---|
| 6769 | + } |
---|
| 6770 | + pe_handler_worker = kmalloc(sizeof(*pe_handler_worker), |
---|
| 6771 | + GFP_KERNEL | GFP_DMA); |
---|
| 6772 | + if (!pe_handler_worker) { |
---|
| 6773 | + kfree(dasd_reserve_req); |
---|
| 6774 | + kfree(dasd_vol_info_req); |
---|
5811 | 6775 | return -ENOMEM; |
---|
5812 | 6776 | } |
---|
5813 | 6777 | rawpadpage = (void *)__get_free_page(GFP_KERNEL); |
---|
5814 | 6778 | if (!rawpadpage) { |
---|
5815 | | - kfree(path_verification_worker); |
---|
| 6779 | + kfree(pe_handler_worker); |
---|
5816 | 6780 | kfree(dasd_reserve_req); |
---|
| 6781 | + kfree(dasd_vol_info_req); |
---|
5817 | 6782 | return -ENOMEM; |
---|
5818 | 6783 | } |
---|
5819 | 6784 | ret = ccw_driver_register(&dasd_eckd_driver); |
---|
5820 | 6785 | if (!ret) |
---|
5821 | 6786 | wait_for_device_probe(); |
---|
5822 | 6787 | else { |
---|
5823 | | - kfree(path_verification_worker); |
---|
| 6788 | + kfree(pe_handler_worker); |
---|
5824 | 6789 | kfree(dasd_reserve_req); |
---|
| 6790 | + kfree(dasd_vol_info_req); |
---|
5825 | 6791 | free_page((unsigned long)rawpadpage); |
---|
5826 | 6792 | } |
---|
5827 | 6793 | return ret; |
---|
.. | .. |
---|
5831 | 6797 | dasd_eckd_cleanup(void) |
---|
5832 | 6798 | { |
---|
5833 | 6799 | ccw_driver_unregister(&dasd_eckd_driver); |
---|
5834 | | - kfree(path_verification_worker); |
---|
| 6800 | + kfree(pe_handler_worker); |
---|
5835 | 6801 | kfree(dasd_reserve_req); |
---|
5836 | 6802 | free_page((unsigned long)rawpadpage); |
---|
5837 | 6803 | } |
---|