diff options
author | Asai Thambi S P <asamymuthupa@micron.com> | 2012-04-09 02:35:38 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2012-04-09 02:35:38 -0400 |
commit | f65872177d838a33e90cbae25625b9bec05134ca (patch) | |
tree | e4cc29b3395f8c989b5821f132b2fdb91e9931a7 | |
parent | dad40f16ff683a10f4f2bea55a0b9fd86d3db58e (diff) |
mtip32xx: Add new sysfs entry 'status'
* Add support for detecting the following device status
- write protect
- over temp (thermal shutdown)
* Add new sysfs entry 'status', possible values - online, write_protect, thermal_shutdown
* Add new file 'sysfs-block-rssd' to document ABI (Reported-by: Greg Kroah-Hartman)
Signed-off-by: Asai Thambi S P <asamymuthupa@micron.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | Documentation/ABI/testing/sysfs-block-rssd | 18 | ||||
-rw-r--r-- | drivers/block/mtip32xx/mtip32xx.c | 323 | ||||
-rw-r--r-- | drivers/block/mtip32xx/mtip32xx.h | 19 |
3 files changed, 331 insertions, 29 deletions
diff --git a/Documentation/ABI/testing/sysfs-block-rssd b/Documentation/ABI/testing/sysfs-block-rssd new file mode 100644 index 000000000000..d535757799fe --- /dev/null +++ b/Documentation/ABI/testing/sysfs-block-rssd | |||
@@ -0,0 +1,18 @@ | |||
1 | What: /sys/block/rssd*/registers | ||
2 | Date: March 2012 | ||
3 | KernelVersion: 3.3 | ||
4 | Contact: Asai Thambi S P <asamymuthupa@micron.com> | ||
5 | Description: This is a read-only file. Dumps below driver information and | ||
6 | hardware registers. | ||
7 | - S ACTive | ||
8 | - Command Issue | ||
9 | - Allocated | ||
10 | - Completed | ||
11 | - PORT IRQ STAT | ||
12 | - HOST IRQ STAT | ||
13 | |||
14 | What: /sys/block/rssd*/status | ||
15 | Date: April 2012 | ||
16 | KernelVersion: 3.4 | ||
17 | Contact: Asai Thambi S P <asamymuthupa@micron.com> | ||
18 | Description: This is a read-only file. Indicates the status of the device. | ||
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index aaa82453ae74..79fdb063f9c0 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c | |||
@@ -725,6 +725,10 @@ static void print_tags(struct driver_data *dd, | |||
725 | dev_info(&dd->pdev->dev, "%s [%i tags]\n", msg, count); | 725 | dev_info(&dd->pdev->dev, "%s [%i tags]\n", msg, count); |
726 | } | 726 | } |
727 | 727 | ||
728 | static int mtip_read_log_page(struct mtip_port *port, u8 page, u16 *buffer, | ||
729 | dma_addr_t buffer_dma, unsigned int sectors); | ||
730 | static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id, | ||
731 | struct smart_attr *attrib); | ||
728 | /* | 732 | /* |
729 | * Handle an error. | 733 | * Handle an error. |
730 | * | 734 | * |
@@ -735,12 +739,15 @@ static void print_tags(struct driver_data *dd, | |||
735 | */ | 739 | */ |
736 | static void mtip_handle_tfe(struct driver_data *dd) | 740 | static void mtip_handle_tfe(struct driver_data *dd) |
737 | { | 741 | { |
738 | int group, tag, bit, reissue; | 742 | int group, tag, bit, reissue, rv; |
739 | struct mtip_port *port; | 743 | struct mtip_port *port; |
740 | struct mtip_cmd *command; | 744 | struct mtip_cmd *cmd; |
741 | u32 completed; | 745 | u32 completed; |
742 | struct host_to_dev_fis *fis; | 746 | struct host_to_dev_fis *fis; |
743 | unsigned long tagaccum[SLOTBITS_IN_LONGS]; | 747 | unsigned long tagaccum[SLOTBITS_IN_LONGS]; |
748 | unsigned char *buf; | ||
749 | char *fail_reason = NULL; | ||
750 | int fail_all_ncq_write = 0, fail_all_ncq_cmds = 0; | ||
744 | 751 | ||
745 | dev_warn(&dd->pdev->dev, "Taskfile error\n"); | 752 | dev_warn(&dd->pdev->dev, "Taskfile error\n"); |
746 | 753 | ||
@@ -772,13 +779,13 @@ static void mtip_handle_tfe(struct driver_data *dd) | |||
772 | if (tag == MTIP_TAG_INTERNAL) | 779 | if (tag == MTIP_TAG_INTERNAL) |
773 | continue; | 780 | continue; |
774 | 781 | ||
775 | command = &port->commands[tag]; | 782 | cmd = &port->commands[tag]; |
776 | if (likely(command->comp_func)) { | 783 | if (likely(cmd->comp_func)) { |
777 | set_bit(tag, tagaccum); | 784 | set_bit(tag, tagaccum); |
778 | atomic_set(&port->commands[tag].active, 0); | 785 | atomic_set(&cmd->active, 0); |
779 | command->comp_func(port, | 786 | cmd->comp_func(port, |
780 | tag, | 787 | tag, |
781 | command->comp_data, | 788 | cmd->comp_data, |
782 | 0); | 789 | 0); |
783 | } else { | 790 | } else { |
784 | dev_err(&port->dd->pdev->dev, | 791 | dev_err(&port->dd->pdev->dev, |
@@ -798,6 +805,38 @@ static void mtip_handle_tfe(struct driver_data *dd) | |||
798 | mdelay(20); | 805 | mdelay(20); |
799 | mtip_restart_port(port); | 806 | mtip_restart_port(port); |
800 | 807 | ||
808 | /* Trying to determine the cause of the error */ | ||
809 | rv = mtip_read_log_page(dd->port, ATA_LOG_SATA_NCQ, | ||
810 | dd->port->log_buf, | ||
811 | dd->port->log_buf_dma, 1); | ||
812 | if (rv) { | ||
813 | dev_warn(&dd->pdev->dev, | ||
814 | "Error in READ LOG EXT (10h) command\n"); | ||
815 | /* non-critical error, don't fail the load */ | ||
816 | } else { | ||
817 | buf = (unsigned char *)dd->port->log_buf; | ||
818 | if (buf[259] & 0x1) { | ||
819 | dev_info(&dd->pdev->dev, | ||
820 | "Write protect bit is set.\n"); | ||
821 | set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); | ||
822 | fail_all_ncq_write = 1; | ||
823 | fail_reason = "write protect"; | ||
824 | } | ||
825 | if (buf[288] == 0xF7) { | ||
826 | dev_info(&dd->pdev->dev, | ||
827 | "Exceeded Tmax, drive in thermal shutdown.\n"); | ||
828 | set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); | ||
829 | fail_all_ncq_cmds = 1; | ||
830 | fail_reason = "thermal shutdown"; | ||
831 | } | ||
832 | if (buf[288] == 0xBF) { | ||
833 | dev_info(&dd->pdev->dev, | ||
834 | "Drive indicates rebuild has failed.\n"); | ||
835 | fail_all_ncq_cmds = 1; | ||
836 | fail_reason = "rebuild failed"; | ||
837 | } | ||
838 | } | ||
839 | |||
801 | /* clear the tag accumulator */ | 840 | /* clear the tag accumulator */ |
802 | memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); | 841 | memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); |
803 | 842 | ||
@@ -806,25 +845,44 @@ static void mtip_handle_tfe(struct driver_data *dd) | |||
806 | for (bit = 0; bit < 32; bit++) { | 845 | for (bit = 0; bit < 32; bit++) { |
807 | reissue = 1; | 846 | reissue = 1; |
808 | tag = (group << 5) + bit; | 847 | tag = (group << 5) + bit; |
848 | cmd = &port->commands[tag]; | ||
809 | 849 | ||
810 | /* If the active bit is set re-issue the command */ | 850 | /* If the active bit is set re-issue the command */ |
811 | if (atomic_read(&port->commands[tag].active) == 0) | 851 | if (atomic_read(&cmd->active) == 0) |
812 | continue; | 852 | continue; |
813 | 853 | ||
814 | fis = (struct host_to_dev_fis *) | 854 | fis = (struct host_to_dev_fis *)cmd->command; |
815 | port->commands[tag].command; | ||
816 | 855 | ||
817 | /* Should re-issue? */ | 856 | /* Should re-issue? */ |
818 | if (tag == MTIP_TAG_INTERNAL || | 857 | if (tag == MTIP_TAG_INTERNAL || |
819 | fis->command == ATA_CMD_SET_FEATURES) | 858 | fis->command == ATA_CMD_SET_FEATURES) |
820 | reissue = 0; | 859 | reissue = 0; |
860 | else { | ||
861 | if (fail_all_ncq_cmds || | ||
862 | (fail_all_ncq_write && | ||
863 | fis->command == ATA_CMD_FPDMA_WRITE)) { | ||
864 | dev_warn(&dd->pdev->dev, | ||
865 | " Fail: %s w/tag %d [%s].\n", | ||
866 | fis->command == ATA_CMD_FPDMA_WRITE ? | ||
867 | "write" : "read", | ||
868 | tag, | ||
869 | fail_reason != NULL ? | ||
870 | fail_reason : "unknown"); | ||
871 | atomic_set(&cmd->active, 0); | ||
872 | if (cmd->comp_func) { | ||
873 | cmd->comp_func(port, tag, | ||
874 | cmd->comp_data, | ||
875 | -ENODATA); | ||
876 | } | ||
877 | continue; | ||
878 | } | ||
879 | } | ||
821 | 880 | ||
822 | /* | 881 | /* |
823 | * First check if this command has | 882 | * First check if this command has |
824 | * exceeded its retries. | 883 | * exceeded its retries. |
825 | */ | 884 | */ |
826 | if (reissue && | 885 | if (reissue && (cmd->retries-- > 0)) { |
827 | (port->commands[tag].retries-- > 0)) { | ||
828 | 886 | ||
829 | set_bit(tag, tagaccum); | 887 | set_bit(tag, tagaccum); |
830 | 888 | ||
@@ -837,13 +895,13 @@ static void mtip_handle_tfe(struct driver_data *dd) | |||
837 | /* Retire a command that will not be reissued */ | 895 | /* Retire a command that will not be reissued */ |
838 | dev_warn(&port->dd->pdev->dev, | 896 | dev_warn(&port->dd->pdev->dev, |
839 | "retiring tag %d\n", tag); | 897 | "retiring tag %d\n", tag); |
840 | atomic_set(&port->commands[tag].active, 0); | 898 | atomic_set(&cmd->active, 0); |
841 | 899 | ||
842 | if (port->commands[tag].comp_func) | 900 | if (cmd->comp_func) |
843 | port->commands[tag].comp_func( | 901 | cmd->comp_func( |
844 | port, | 902 | port, |
845 | tag, | 903 | tag, |
846 | port->commands[tag].comp_data, | 904 | cmd->comp_data, |
847 | PORT_IRQ_TF_ERR); | 905 | PORT_IRQ_TF_ERR); |
848 | else | 906 | else |
849 | dev_warn(&port->dd->pdev->dev, | 907 | dev_warn(&port->dd->pdev->dev, |
@@ -1374,6 +1432,7 @@ static int mtip_standby_immediate(struct mtip_port *port) | |||
1374 | { | 1432 | { |
1375 | int rv; | 1433 | int rv; |
1376 | struct host_to_dev_fis fis; | 1434 | struct host_to_dev_fis fis; |
1435 | unsigned long start; | ||
1377 | 1436 | ||
1378 | /* Build the FIS. */ | 1437 | /* Build the FIS. */ |
1379 | memset(&fis, 0, sizeof(struct host_to_dev_fis)); | 1438 | memset(&fis, 0, sizeof(struct host_to_dev_fis)); |
@@ -1381,15 +1440,150 @@ static int mtip_standby_immediate(struct mtip_port *port) | |||
1381 | fis.opts = 1 << 7; | 1440 | fis.opts = 1 << 7; |
1382 | fis.command = ATA_CMD_STANDBYNOW1; | 1441 | fis.command = ATA_CMD_STANDBYNOW1; |
1383 | 1442 | ||
1384 | /* Execute the command. Use a 15-second timeout for large drives. */ | 1443 | start = jiffies; |
1385 | rv = mtip_exec_internal_command(port, | 1444 | rv = mtip_exec_internal_command(port, |
1386 | &fis, | 1445 | &fis, |
1387 | 5, | 1446 | 5, |
1388 | 0, | 1447 | 0, |
1389 | 0, | 1448 | 0, |
1390 | 0, | 1449 | 0, |
1391 | GFP_KERNEL, | 1450 | GFP_ATOMIC, |
1392 | 15000); | 1451 | 15000); |
1452 | dbg_printk(MTIP_DRV_NAME "Time taken to complete standby cmd: %d ms\n", | ||
1453 | jiffies_to_msecs(jiffies - start)); | ||
1454 | if (rv) | ||
1455 | dev_warn(&port->dd->pdev->dev, | ||
1456 | "STANDBY IMMEDIATE command failed.\n"); | ||
1457 | |||
1458 | return rv; | ||
1459 | } | ||
1460 | |||
1461 | /* | ||
1462 | * Issue a READ LOG EXT command to the device. | ||
1463 | * | ||
1464 | * @port pointer to the port structure. | ||
1465 | * @page page number to fetch | ||
1466 | * @buffer pointer to buffer | ||
1467 | * @buffer_dma dma address corresponding to @buffer | ||
1468 | * @sectors page length to fetch, in sectors | ||
1469 | * | ||
1470 | * return value | ||
1471 | * @rv return value from mtip_exec_internal_command() | ||
1472 | */ | ||
1473 | static int mtip_read_log_page(struct mtip_port *port, u8 page, u16 *buffer, | ||
1474 | dma_addr_t buffer_dma, unsigned int sectors) | ||
1475 | { | ||
1476 | struct host_to_dev_fis fis; | ||
1477 | |||
1478 | memset(&fis, 0, sizeof(struct host_to_dev_fis)); | ||
1479 | fis.type = 0x27; | ||
1480 | fis.opts = 1 << 7; | ||
1481 | fis.command = ATA_CMD_READ_LOG_EXT; | ||
1482 | fis.sect_count = sectors & 0xFF; | ||
1483 | fis.sect_cnt_ex = (sectors >> 8) & 0xFF; | ||
1484 | fis.lba_low = page; | ||
1485 | fis.lba_mid = 0; | ||
1486 | fis.device = ATA_DEVICE_OBS; | ||
1487 | |||
1488 | memset(buffer, 0, sectors * ATA_SECT_SIZE); | ||
1489 | |||
1490 | return mtip_exec_internal_command(port, | ||
1491 | &fis, | ||
1492 | 5, | ||
1493 | buffer_dma, | ||
1494 | sectors * ATA_SECT_SIZE, | ||
1495 | 0, | ||
1496 | GFP_ATOMIC, | ||
1497 | MTIP_INTERNAL_COMMAND_TIMEOUT_MS); | ||
1498 | } | ||
1499 | |||
1500 | /* | ||
1501 | * Issue a SMART READ DATA command to the device. | ||
1502 | * | ||
1503 | * @port pointer to the port structure. | ||
1504 | * @buffer pointer to buffer | ||
1505 | * @buffer_dma dma address corresponding to @buffer | ||
1506 | * | ||
1507 | * return value | ||
1508 | * @rv return value from mtip_exec_internal_command() | ||
1509 | */ | ||
1510 | static int mtip_get_smart_data(struct mtip_port *port, u8 *buffer, | ||
1511 | dma_addr_t buffer_dma) | ||
1512 | { | ||
1513 | struct host_to_dev_fis fis; | ||
1514 | |||
1515 | memset(&fis, 0, sizeof(struct host_to_dev_fis)); | ||
1516 | fis.type = 0x27; | ||
1517 | fis.opts = 1 << 7; | ||
1518 | fis.command = ATA_CMD_SMART; | ||
1519 | fis.features = 0xD0; | ||
1520 | fis.sect_count = 1; | ||
1521 | fis.lba_mid = 0x4F; | ||
1522 | fis.lba_hi = 0xC2; | ||
1523 | fis.device = ATA_DEVICE_OBS; | ||
1524 | |||
1525 | return mtip_exec_internal_command(port, | ||
1526 | &fis, | ||
1527 | 5, | ||
1528 | buffer_dma, | ||
1529 | ATA_SECT_SIZE, | ||
1530 | 0, | ||
1531 | GFP_ATOMIC, | ||
1532 | 15000); | ||
1533 | } | ||
1534 | |||
1535 | /* | ||
1536 | * Get the value of a smart attribute | ||
1537 | * | ||
1538 | * @port pointer to the port structure | ||
1539 | * @id attribute number | ||
1540 | * @attrib pointer to return attrib information corresponding to @id | ||
1541 | * | ||
1542 | * return value | ||
1543 | * -EINVAL NULL buffer passed or unsupported attribute @id. | ||
1544 | * -EPERM Identify data not valid, SMART not supported or not enabled | ||
1545 | */ | ||
1546 | static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id, | ||
1547 | struct smart_attr *attrib) | ||
1548 | { | ||
1549 | int rv, i; | ||
1550 | struct smart_attr *pattr; | ||
1551 | |||
1552 | if (!attrib) | ||
1553 | return -EINVAL; | ||
1554 | |||
1555 | if (!port->identify_valid) { | ||
1556 | dev_warn(&port->dd->pdev->dev, "IDENTIFY DATA not valid\n"); | ||
1557 | return -EPERM; | ||
1558 | } | ||
1559 | if (!(port->identify[82] & 0x1)) { | ||
1560 | dev_warn(&port->dd->pdev->dev, "SMART not supported\n"); | ||
1561 | return -EPERM; | ||
1562 | } | ||
1563 | if (!(port->identify[85] & 0x1)) { | ||
1564 | dev_warn(&port->dd->pdev->dev, "SMART not enabled\n"); | ||
1565 | return -EPERM; | ||
1566 | } | ||
1567 | |||
1568 | memset(port->smart_buf, 0, ATA_SECT_SIZE); | ||
1569 | rv = mtip_get_smart_data(port, port->smart_buf, port->smart_buf_dma); | ||
1570 | if (rv) { | ||
1571 | dev_warn(&port->dd->pdev->dev, "Failed to ge SMART data\n"); | ||
1572 | return rv; | ||
1573 | } | ||
1574 | |||
1575 | pattr = (struct smart_attr *)(port->smart_buf + 2); | ||
1576 | for (i = 0; i < 29; i++, pattr++) | ||
1577 | if (pattr->attr_id == id) { | ||
1578 | memcpy(attrib, pattr, sizeof(struct smart_attr)); | ||
1579 | break; | ||
1580 | } | ||
1581 | |||
1582 | if (i == 29) { | ||
1583 | dev_warn(&port->dd->pdev->dev, | ||
1584 | "Query for invalid SMART attribute ID\n"); | ||
1585 | rv = -EINVAL; | ||
1586 | } | ||
1393 | 1587 | ||
1394 | return rv; | 1588 | return rv; |
1395 | } | 1589 | } |
@@ -2272,7 +2466,7 @@ static ssize_t mtip_hw_show_registers(struct device *dev, | |||
2272 | int size = 0; | 2466 | int size = 0; |
2273 | int n; | 2467 | int n; |
2274 | 2468 | ||
2275 | size += sprintf(&buf[size], "%s:\ns_active:\n", __func__); | 2469 | size += sprintf(&buf[size], "S ACTive:\n"); |
2276 | 2470 | ||
2277 | for (n = 0; n < dd->slot_groups; n++) | 2471 | for (n = 0; n < dd->slot_groups; n++) |
2278 | size += sprintf(&buf[size], "0x%08x\n", | 2472 | size += sprintf(&buf[size], "0x%08x\n", |
@@ -2296,20 +2490,39 @@ static ssize_t mtip_hw_show_registers(struct device *dev, | |||
2296 | group_allocated); | 2490 | group_allocated); |
2297 | } | 2491 | } |
2298 | 2492 | ||
2299 | size += sprintf(&buf[size], "completed:\n"); | 2493 | size += sprintf(&buf[size], "Completed:\n"); |
2300 | 2494 | ||
2301 | for (n = 0; n < dd->slot_groups; n++) | 2495 | for (n = 0; n < dd->slot_groups; n++) |
2302 | size += sprintf(&buf[size], "0x%08x\n", | 2496 | size += sprintf(&buf[size], "0x%08x\n", |
2303 | readl(dd->port->completed[n])); | 2497 | readl(dd->port->completed[n])); |
2304 | 2498 | ||
2305 | size += sprintf(&buf[size], "PORT_IRQ_STAT 0x%08x\n", | 2499 | size += sprintf(&buf[size], "PORT IRQ STAT : 0x%08x\n", |
2306 | readl(dd->port->mmio + PORT_IRQ_STAT)); | 2500 | readl(dd->port->mmio + PORT_IRQ_STAT)); |
2307 | size += sprintf(&buf[size], "HOST_IRQ_STAT 0x%08x\n", | 2501 | size += sprintf(&buf[size], "HOST IRQ STAT : 0x%08x\n", |
2308 | readl(dd->mmio + HOST_IRQ_STAT)); | 2502 | readl(dd->mmio + HOST_IRQ_STAT)); |
2309 | 2503 | ||
2310 | return size; | 2504 | return size; |
2311 | } | 2505 | } |
2506 | |||
2507 | static ssize_t mtip_hw_show_status(struct device *dev, | ||
2508 | struct device_attribute *attr, | ||
2509 | char *buf) | ||
2510 | { | ||
2511 | struct driver_data *dd = dev_to_disk(dev)->private_data; | ||
2512 | int size = 0; | ||
2513 | |||
2514 | if (test_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag)) | ||
2515 | size += sprintf(buf, "%s", "thermal_shutdown\n"); | ||
2516 | else if (test_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag)) | ||
2517 | size += sprintf(buf, "%s", "write_protect\n"); | ||
2518 | else | ||
2519 | size += sprintf(buf, "%s", "online\n"); | ||
2520 | |||
2521 | return size; | ||
2522 | } | ||
2523 | |||
2312 | static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL); | 2524 | static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL); |
2525 | static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL); | ||
2313 | 2526 | ||
2314 | /* | 2527 | /* |
2315 | * Create the sysfs related attributes. | 2528 | * Create the sysfs related attributes. |
@@ -2328,7 +2541,10 @@ static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj) | |||
2328 | 2541 | ||
2329 | if (sysfs_create_file(kobj, &dev_attr_registers.attr)) | 2542 | if (sysfs_create_file(kobj, &dev_attr_registers.attr)) |
2330 | dev_warn(&dd->pdev->dev, | 2543 | dev_warn(&dd->pdev->dev, |
2331 | "Error creating registers sysfs entry\n"); | 2544 | "Error creating 'registers' sysfs entry\n"); |
2545 | if (sysfs_create_file(kobj, &dev_attr_status.attr)) | ||
2546 | dev_warn(&dd->pdev->dev, | ||
2547 | "Error creating 'status' sysfs entry\n"); | ||
2332 | return 0; | 2548 | return 0; |
2333 | } | 2549 | } |
2334 | 2550 | ||
@@ -2348,6 +2564,7 @@ static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj) | |||
2348 | return -EINVAL; | 2564 | return -EINVAL; |
2349 | 2565 | ||
2350 | sysfs_remove_file(kobj, &dev_attr_registers.attr); | 2566 | sysfs_remove_file(kobj, &dev_attr_registers.attr); |
2567 | sysfs_remove_file(kobj, &dev_attr_status.attr); | ||
2351 | 2568 | ||
2352 | return 0; | 2569 | return 0; |
2353 | } | 2570 | } |
@@ -2566,6 +2783,8 @@ static int mtip_hw_init(struct driver_data *dd) | |||
2566 | int rv; | 2783 | int rv; |
2567 | unsigned int num_command_slots; | 2784 | unsigned int num_command_slots; |
2568 | unsigned long timeout, timetaken; | 2785 | unsigned long timeout, timetaken; |
2786 | unsigned char *buf; | ||
2787 | struct smart_attr attr242; | ||
2569 | 2788 | ||
2570 | dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; | 2789 | dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; |
2571 | 2790 | ||
@@ -2600,7 +2819,7 @@ static int mtip_hw_init(struct driver_data *dd) | |||
2600 | /* Allocate memory for the command list. */ | 2819 | /* Allocate memory for the command list. */ |
2601 | dd->port->command_list = | 2820 | dd->port->command_list = |
2602 | dmam_alloc_coherent(&dd->pdev->dev, | 2821 | dmam_alloc_coherent(&dd->pdev->dev, |
2603 | HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), | 2822 | HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), |
2604 | &dd->port->command_list_dma, | 2823 | &dd->port->command_list_dma, |
2605 | GFP_KERNEL); | 2824 | GFP_KERNEL); |
2606 | if (!dd->port->command_list) { | 2825 | if (!dd->port->command_list) { |
@@ -2613,7 +2832,7 @@ static int mtip_hw_init(struct driver_data *dd) | |||
2613 | /* Clear the memory we have allocated. */ | 2832 | /* Clear the memory we have allocated. */ |
2614 | memset(dd->port->command_list, | 2833 | memset(dd->port->command_list, |
2615 | 0, | 2834 | 0, |
2616 | HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2)); | 2835 | HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4)); |
2617 | 2836 | ||
2618 | /* Setup the addresse of the RX FIS. */ | 2837 | /* Setup the addresse of the RX FIS. */ |
2619 | dd->port->rxfis = dd->port->command_list + HW_CMD_SLOT_SZ; | 2838 | dd->port->rxfis = dd->port->command_list + HW_CMD_SLOT_SZ; |
@@ -2629,10 +2848,19 @@ static int mtip_hw_init(struct driver_data *dd) | |||
2629 | dd->port->identify_dma = dd->port->command_tbl_dma + | 2848 | dd->port->identify_dma = dd->port->command_tbl_dma + |
2630 | HW_CMD_TBL_AR_SZ; | 2849 | HW_CMD_TBL_AR_SZ; |
2631 | 2850 | ||
2632 | /* Setup the address of the sector buffer. */ | 2851 | /* Setup the address of the sector buffer - for some non-ncq cmds */ |
2633 | dd->port->sector_buffer = (void *) dd->port->identify + ATA_SECT_SIZE; | 2852 | dd->port->sector_buffer = (void *) dd->port->identify + ATA_SECT_SIZE; |
2634 | dd->port->sector_buffer_dma = dd->port->identify_dma + ATA_SECT_SIZE; | 2853 | dd->port->sector_buffer_dma = dd->port->identify_dma + ATA_SECT_SIZE; |
2635 | 2854 | ||
2855 | /* Setup the address of the log buf - for read log command */ | ||
2856 | dd->port->log_buf = (void *)dd->port->sector_buffer + ATA_SECT_SIZE; | ||
2857 | dd->port->log_buf_dma = dd->port->sector_buffer_dma + ATA_SECT_SIZE; | ||
2858 | |||
2859 | /* Setup the address of the smart buf - for smart read data command */ | ||
2860 | dd->port->smart_buf = (void *)dd->port->log_buf + ATA_SECT_SIZE; | ||
2861 | dd->port->smart_buf_dma = dd->port->log_buf_dma + ATA_SECT_SIZE; | ||
2862 | |||
2863 | |||
2636 | /* Point the command headers at the command tables. */ | 2864 | /* Point the command headers at the command tables. */ |
2637 | for (i = 0; i < num_command_slots; i++) { | 2865 | for (i = 0; i < num_command_slots; i++) { |
2638 | dd->port->commands[i].command_header = | 2866 | dd->port->commands[i].command_header = |
@@ -2759,6 +2987,43 @@ static int mtip_hw_init(struct driver_data *dd) | |||
2759 | return MTIP_FTL_REBUILD_MAGIC; | 2987 | return MTIP_FTL_REBUILD_MAGIC; |
2760 | } | 2988 | } |
2761 | mtip_dump_identify(dd->port); | 2989 | mtip_dump_identify(dd->port); |
2990 | |||
2991 | /* check write protect, over temp and rebuild statuses */ | ||
2992 | rv = mtip_read_log_page(dd->port, ATA_LOG_SATA_NCQ, | ||
2993 | dd->port->log_buf, | ||
2994 | dd->port->log_buf_dma, 1); | ||
2995 | if (rv) { | ||
2996 | dev_warn(&dd->pdev->dev, | ||
2997 | "Error in READ LOG EXT (10h) command\n"); | ||
2998 | /* non-critical error, don't fail the load */ | ||
2999 | } else { | ||
3000 | buf = (unsigned char *)dd->port->log_buf; | ||
3001 | if (buf[259] & 0x1) { | ||
3002 | dev_info(&dd->pdev->dev, | ||
3003 | "Write protect bit is set.\n"); | ||
3004 | set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); | ||
3005 | } | ||
3006 | if (buf[288] == 0xF7) { | ||
3007 | dev_info(&dd->pdev->dev, | ||
3008 | "Exceeded Tmax, drive in thermal shutdown.\n"); | ||
3009 | set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); | ||
3010 | } | ||
3011 | if (buf[288] == 0xBF) { | ||
3012 | dev_info(&dd->pdev->dev, | ||
3013 | "Drive indicates rebuild has failed.\n"); | ||
3014 | /* TODO */ | ||
3015 | } | ||
3016 | } | ||
3017 | |||
3018 | /* get write protect progess */ | ||
3019 | memset(&attr242, 0, sizeof(struct smart_attr)); | ||
3020 | if (mtip_get_smart_attr(dd->port, 242, &attr242)) | ||
3021 | dev_warn(&dd->pdev->dev, | ||
3022 | "Unable to check write protect progress\n"); | ||
3023 | else | ||
3024 | dev_info(&dd->pdev->dev, | ||
3025 | "Write protect progress: %d%% (%d blocks)\n", | ||
3026 | attr242.cur, attr242.data); | ||
2762 | return rv; | 3027 | return rv; |
2763 | 3028 | ||
2764 | out3: | 3029 | out3: |
@@ -2776,7 +3041,7 @@ out2: | |||
2776 | 3041 | ||
2777 | /* Free the command/command header memory. */ | 3042 | /* Free the command/command header memory. */ |
2778 | dmam_free_coherent(&dd->pdev->dev, | 3043 | dmam_free_coherent(&dd->pdev->dev, |
2779 | HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), | 3044 | HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), |
2780 | dd->port->command_list, | 3045 | dd->port->command_list, |
2781 | dd->port->command_list_dma); | 3046 | dd->port->command_list_dma); |
2782 | out1: | 3047 | out1: |
@@ -2825,7 +3090,7 @@ static int mtip_hw_exit(struct driver_data *dd) | |||
2825 | 3090 | ||
2826 | /* Free the command/command header memory. */ | 3091 | /* Free the command/command header memory. */ |
2827 | dmam_free_coherent(&dd->pdev->dev, | 3092 | dmam_free_coherent(&dd->pdev->dev, |
2828 | HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), | 3093 | HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), |
2829 | dd->port->command_list, | 3094 | dd->port->command_list, |
2830 | dd->port->command_list_dma); | 3095 | dd->port->command_list_dma); |
2831 | /* Free the memory allocated for the for structure. */ | 3096 | /* Free the memory allocated for the for structure. */ |
@@ -3378,7 +3643,7 @@ static int mtip_block_remove(struct driver_data *dd) | |||
3378 | kthread_stop(dd->mtip_svc_handler); | 3643 | kthread_stop(dd->mtip_svc_handler); |
3379 | } | 3644 | } |
3380 | 3645 | ||
3381 | /* Clean up the sysfs attributes managed by the protocol layer. */ | 3646 | /* Clean up the sysfs attributes, if created */ |
3382 | if (test_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag)) { | 3647 | if (test_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag)) { |
3383 | kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); | 3648 | kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); |
3384 | if (kobj) { | 3649 | if (kobj) { |
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index f4e46cc81d55..ea5c7e7cb50d 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h | |||
@@ -127,6 +127,19 @@ | |||
127 | #define MTIP_DD_FLAG_CLEANUP_BIT 3 | 127 | #define MTIP_DD_FLAG_CLEANUP_BIT 3 |
128 | #define MTIP_DD_FLAG_INIT_DONE_BIT 4 | 128 | #define MTIP_DD_FLAG_INIT_DONE_BIT 4 |
129 | 129 | ||
130 | #define MTIP_DD_FLAG_WRITE_PROTECT_BIT 5 | ||
131 | #define MTIP_DD_FLAG_OVER_TEMP_BIT 6 | ||
132 | #define MTIP_DD_FLAG_REBUILD_FAILED_BIT 7 | ||
133 | |||
134 | __packed struct smart_attr{ | ||
135 | u8 attr_id; | ||
136 | u16 flags; | ||
137 | u8 cur; | ||
138 | u8 worst; | ||
139 | u32 data; | ||
140 | u8 res[3]; | ||
141 | }; | ||
142 | |||
130 | /* Register Frame Information Structure (FIS), host to device. */ | 143 | /* Register Frame Information Structure (FIS), host to device. */ |
131 | struct host_to_dev_fis { | 144 | struct host_to_dev_fis { |
132 | /* | 145 | /* |
@@ -351,6 +364,12 @@ struct mtip_port { | |||
351 | * when the command slot and all associated data structures | 364 | * when the command slot and all associated data structures |
352 | * are no longer needed. | 365 | * are no longer needed. |
353 | */ | 366 | */ |
367 | u16 *log_buf; | ||
368 | dma_addr_t log_buf_dma; | ||
369 | |||
370 | u8 *smart_buf; | ||
371 | dma_addr_t smart_buf_dma; | ||
372 | |||
354 | unsigned long allocated[SLOTBITS_IN_LONGS]; | 373 | unsigned long allocated[SLOTBITS_IN_LONGS]; |
355 | /* | 374 | /* |
356 | * used to queue commands when an internal command is in progress | 375 | * used to queue commands when an internal command is in progress |