diff options
author | Hannes Reinecke <hare@suse.de> | 2016-04-25 06:45:54 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2016-05-09 12:36:46 -0400 |
commit | 284b3b77ea883234dadb2cbf97b145c3c30fe4bd (patch) | |
tree | 2faa832ef21a350e2d6b5e4c238f70e38e0e6502 | |
parent | 27708a9579ee069c6e0ebb6e61ac1114ed1d546c (diff) |
libata: NCQ encapsulation for ZAC MANAGEMENT OUT
Add NCQ encapsulation for ZAC MANAGEMENT OUT and evaluate
NCQ Non-Data log pages to figure out if NCQ encapsulation
is supported.
Signed-off-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r-- | drivers/ata/libata-core.c | 43 | ||||
-rw-r--r-- | drivers/ata/libata-scsi.c | 18 | ||||
-rw-r--r-- | drivers/ata/libata-trace.c | 3 | ||||
-rw-r--r-- | include/linux/ata.h | 7 | ||||
-rw-r--r-- | include/linux/libata.h | 7 |
5 files changed, 70 insertions, 8 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b2bd7c499653..1528c7cc0089 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -2121,6 +2121,40 @@ static void ata_dev_config_ncq_send_recv(struct ata_device *dev) | |||
2121 | } | 2121 | } |
2122 | } | 2122 | } |
2123 | 2123 | ||
2124 | static void ata_dev_config_ncq_non_data(struct ata_device *dev) | ||
2125 | { | ||
2126 | struct ata_port *ap = dev->link->ap; | ||
2127 | unsigned int err_mask; | ||
2128 | int log_index = ATA_LOG_NCQ_NON_DATA * 2; | ||
2129 | u16 log_pages; | ||
2130 | |||
2131 | err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY, | ||
2132 | 0, ap->sector_buf, 1); | ||
2133 | if (err_mask) { | ||
2134 | ata_dev_dbg(dev, | ||
2135 | "failed to get Log Directory Emask 0x%x\n", | ||
2136 | err_mask); | ||
2137 | return; | ||
2138 | } | ||
2139 | log_pages = get_unaligned_le16(&ap->sector_buf[log_index]); | ||
2140 | if (!log_pages) { | ||
2141 | ata_dev_warn(dev, | ||
2142 | "NCQ Send/Recv Log not supported\n"); | ||
2143 | return; | ||
2144 | } | ||
2145 | err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_NON_DATA, | ||
2146 | 0, ap->sector_buf, 1); | ||
2147 | if (err_mask) { | ||
2148 | ata_dev_dbg(dev, | ||
2149 | "failed to get NCQ Non-Data Log Emask 0x%x\n", | ||
2150 | err_mask); | ||
2151 | } else { | ||
2152 | u8 *cmds = dev->ncq_non_data_cmds; | ||
2153 | |||
2154 | memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_NON_DATA_SIZE); | ||
2155 | } | ||
2156 | } | ||
2157 | |||
2124 | static int ata_dev_config_ncq(struct ata_device *dev, | 2158 | static int ata_dev_config_ncq(struct ata_device *dev, |
2125 | char *desc, size_t desc_sz) | 2159 | char *desc, size_t desc_sz) |
2126 | { | 2160 | { |
@@ -2165,9 +2199,12 @@ static int ata_dev_config_ncq(struct ata_device *dev, | |||
2165 | snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth, | 2199 | snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth, |
2166 | ddepth, aa_desc); | 2200 | ddepth, aa_desc); |
2167 | 2201 | ||
2168 | if ((ap->flags & ATA_FLAG_FPDMA_AUX) && | 2202 | if ((ap->flags & ATA_FLAG_FPDMA_AUX)) { |
2169 | ata_id_has_ncq_send_and_recv(dev->id)) | 2203 | if (ata_id_has_ncq_send_and_recv(dev->id)) |
2170 | ata_dev_config_ncq_send_recv(dev); | 2204 | ata_dev_config_ncq_send_recv(dev); |
2205 | if (ata_id_has_ncq_non_data(dev->id)) | ||
2206 | ata_dev_config_ncq_non_data(dev); | ||
2207 | } | ||
2171 | 2208 | ||
2172 | return 0; | 2209 | return 0; |
2173 | } | 2210 | } |
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 6afd0840ebbe..43403aa0801f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -3506,11 +3506,19 @@ static unsigned int ata_scsi_zbc_out_xlat(struct ata_queued_cmd *qc) | |||
3506 | 3506 | ||
3507 | reset_all = cdb[14] & 0x1; | 3507 | reset_all = cdb[14] & 0x1; |
3508 | 3508 | ||
3509 | tf->protocol = ATA_PROT_NODATA; | 3509 | if (ata_ncq_enabled(qc->dev) && |
3510 | tf->command = ATA_CMD_ZAC_MGMT_OUT; | 3510 | ata_fpdma_zac_mgmt_out_supported(qc->dev)) { |
3511 | tf->feature = sa; | 3511 | tf->protocol = ATA_PROT_NCQ; |
3512 | tf->hob_feature = reset_all & 0x1; | 3512 | tf->command = ATA_CMD_NCQ_NON_DATA; |
3513 | 3513 | tf->hob_nsect = ATA_SUBCMD_NCQ_NON_DATA_ZAC_MGMT_OUT; | |
3514 | tf->nsect = qc->tag << 3; | ||
3515 | tf->auxiliary = sa | (reset_all & 0x1) << 8; | ||
3516 | } else { | ||
3517 | tf->protocol = ATA_PROT_NODATA; | ||
3518 | tf->command = ATA_CMD_ZAC_MGMT_OUT; | ||
3519 | tf->feature = sa; | ||
3520 | tf->hob_feature = reset_all & 0x1; | ||
3521 | } | ||
3514 | tf->lbah = (block >> 16) & 0xff; | 3522 | tf->lbah = (block >> 16) & 0xff; |
3515 | tf->lbam = (block >> 8) & 0xff; | 3523 | tf->lbam = (block >> 8) & 0xff; |
3516 | tf->lbal = block & 0xff; | 3524 | tf->lbal = block & 0xff; |
diff --git a/drivers/ata/libata-trace.c b/drivers/ata/libata-trace.c index 1111ba7db5b3..f8c550df0615 100644 --- a/drivers/ata/libata-trace.c +++ b/drivers/ata/libata-trace.c | |||
@@ -188,6 +188,9 @@ libata_trace_parse_subcmd(struct trace_seq *p, unsigned char cmd, | |||
188 | case ATA_SUBCMD_NCQ_NON_DATA_ZERO_EXT: | 188 | case ATA_SUBCMD_NCQ_NON_DATA_ZERO_EXT: |
189 | trace_seq_printf(p, " ZERO_EXT"); | 189 | trace_seq_printf(p, " ZERO_EXT"); |
190 | break; | 190 | break; |
191 | case ATA_SUBCMD_NCQ_NON_DATA_ZAC_MGMT_OUT: | ||
192 | trace_seq_printf(p, " ZAC_MGMT_OUT"); | ||
193 | break; | ||
191 | } | 194 | } |
192 | break; | 195 | break; |
193 | case ATA_CMD_ZAC_MGMT_IN: | 196 | case ATA_CMD_ZAC_MGMT_IN: |
diff --git a/include/linux/ata.h b/include/linux/ata.h index 9d7c47075ebc..e62703201e84 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h | |||
@@ -320,6 +320,7 @@ enum { | |||
320 | ATA_SUBCMD_NCQ_NON_DATA_ABORT_QUEUE = 0x00, | 320 | ATA_SUBCMD_NCQ_NON_DATA_ABORT_QUEUE = 0x00, |
321 | ATA_SUBCMD_NCQ_NON_DATA_SET_FEATURES = 0x05, | 321 | ATA_SUBCMD_NCQ_NON_DATA_SET_FEATURES = 0x05, |
322 | ATA_SUBCMD_NCQ_NON_DATA_ZERO_EXT = 0x06, | 322 | ATA_SUBCMD_NCQ_NON_DATA_ZERO_EXT = 0x06, |
323 | ATA_SUBCMD_NCQ_NON_DATA_ZAC_MGMT_OUT = 0x07, | ||
323 | 324 | ||
324 | /* Subcmds for ATA_CMD_ZAC_MGMT_IN */ | 325 | /* Subcmds for ATA_CMD_ZAC_MGMT_IN */ |
325 | ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES = 0x00, | 326 | ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES = 0x00, |
@@ -333,6 +334,7 @@ enum { | |||
333 | /* READ_LOG_EXT pages */ | 334 | /* READ_LOG_EXT pages */ |
334 | ATA_LOG_DIRECTORY = 0x0, | 335 | ATA_LOG_DIRECTORY = 0x0, |
335 | ATA_LOG_SATA_NCQ = 0x10, | 336 | ATA_LOG_SATA_NCQ = 0x10, |
337 | ATA_LOG_NCQ_NON_DATA = 0x12, | ||
336 | ATA_LOG_NCQ_SEND_RECV = 0x13, | 338 | ATA_LOG_NCQ_SEND_RECV = 0x13, |
337 | ATA_LOG_SATA_ID_DEV_DATA = 0x30, | 339 | ATA_LOG_SATA_ID_DEV_DATA = 0x30, |
338 | ATA_LOG_SATA_SETTINGS = 0x08, | 340 | ATA_LOG_SATA_SETTINGS = 0x08, |
@@ -877,6 +879,11 @@ static inline bool ata_id_has_ncq_send_and_recv(const u16 *id) | |||
877 | return id[ATA_ID_SATA_CAPABILITY_2] & BIT(6); | 879 | return id[ATA_ID_SATA_CAPABILITY_2] & BIT(6); |
878 | } | 880 | } |
879 | 881 | ||
882 | static inline bool ata_id_has_ncq_non_data(const u16 *id) | ||
883 | { | ||
884 | return id[ATA_ID_SATA_CAPABILITY_2] & BIT(5); | ||
885 | } | ||
886 | |||
880 | static inline bool ata_id_has_trim(const u16 *id) | 887 | static inline bool ata_id_has_trim(const u16 *id) |
881 | { | 888 | { |
882 | if (ata_id_major_version(id) >= 7 && | 889 | if (ata_id_major_version(id) >= 7 && |
diff --git a/include/linux/libata.h b/include/linux/libata.h index c0806b60c4fa..0019d4b51b11 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -729,6 +729,7 @@ struct ata_device { | |||
729 | 729 | ||
730 | /* NCQ send and receive log subcommand support */ | 730 | /* NCQ send and receive log subcommand support */ |
731 | u8 ncq_send_recv_cmds[ATA_LOG_NCQ_SEND_RECV_SIZE]; | 731 | u8 ncq_send_recv_cmds[ATA_LOG_NCQ_SEND_RECV_SIZE]; |
732 | u8 ncq_non_data_cmds[ATA_LOG_NCQ_NON_DATA_SIZE]; | ||
732 | 733 | ||
733 | /* error history */ | 734 | /* error history */ |
734 | int spdn_cnt; | 735 | int spdn_cnt; |
@@ -1658,6 +1659,12 @@ static inline bool ata_fpdma_zac_mgmt_in_supported(struct ata_device *dev) | |||
1658 | ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_IN_SUPPORTED); | 1659 | ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_IN_SUPPORTED); |
1659 | } | 1660 | } |
1660 | 1661 | ||
1662 | static inline bool ata_fpdma_zac_mgmt_out_supported(struct ata_device *dev) | ||
1663 | { | ||
1664 | return (dev->ncq_non_data_cmds[ATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OFFSET] & | ||
1665 | ATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OUT); | ||
1666 | } | ||
1667 | |||
1661 | static inline void ata_qc_set_polling(struct ata_queued_cmd *qc) | 1668 | static inline void ata_qc_set_polling(struct ata_queued_cmd *qc) |
1662 | { | 1669 | { |
1663 | qc->tf.ctl |= ATA_NIEN; | 1670 | qc->tf.ctl |= ATA_NIEN; |