Commit e4f7bdc2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-4.7-zac' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata

Pull libata ZAC support from Tejun Heo:
 "This contains Zone ATA Command support for Shingled Magnetic Recording
  devices.

  In addition to sending the new commands down to the device, as ZAC
  commands depend on getting a lot of responses from the device, piping
  up responses is beefed up too.  However, it doesn't involve changes to
  libata core mechanism or its interaction with upper layers, so I'm not
  expecting too many fallouts.

  Kudos to Hannes for driving SMR support"

* 'for-4.7-zac' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: (28 commits)
  libata: support host-aware and host-managed ZAC devices
  libata: support device-managed ZAC devices
  libata: NCQ encapsulation for ZAC MANAGEMENT OUT
  libata: Implement ZBC OUT translation
  libata: implement ZBC IN translation
  libata: fixup ZAC device disabling
  libata-scsi: Generate sense code for disabled devices
  libata-trace: decode subcommands
  libata: Check log page directory before accessing pages
  libata: Add command definitions for NCQ Encapsulation for READ LOG DMA EXT
  libata: Separate out ata_dev_config_ncq_send_recv()
  libata/libsas: Define ATA_CMD_NCQ_NON_DATA
  libsas: enable FPDMA SEND/RECEIVE
  libata: do not attempt to retrieve sense code twice
  libata-scsi: Set information sense field for invalid parameter
  libata-scsi: set bit pointer for sense code information
  libata-scsi: Set field pointer in sense code
  scsi: add scsi_set_sense_field_pointer()
  libata: Implement control mode page to select sense format
  libata-scsi: generate correct ATA pass-through sense
  ...
parents 3159ee58 6d1003ae
......@@ -66,6 +66,7 @@
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <linux/cdrom.h>
#include <linux/ratelimit.h>
#include <linux/pm_runtime.h>
......@@ -695,7 +696,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
* RETURNS:
* Block address read from @tf.
*/
u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
u64 ata_tf_read_block(const struct ata_taskfile *tf, struct ata_device *dev)
{
u64 block = 0;
......@@ -720,7 +721,7 @@ u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
if (!sect) {
ata_dev_warn(dev,
"device reported invalid CHS sector 0\n");
sect = 1; /* oh well */
return U64_MAX;
}
block = (cyl * dev->heads + head) * dev->sectors + sect - 1;
......@@ -2079,6 +2080,81 @@ static inline u8 ata_dev_knobble(struct ata_device *dev)
return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
}
static void ata_dev_config_ncq_send_recv(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
unsigned int err_mask;
int log_index = ATA_LOG_NCQ_SEND_RECV * 2;
u16 log_pages;
err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
0, ap->sector_buf, 1);
if (err_mask) {
ata_dev_dbg(dev,
"failed to get Log Directory Emask 0x%x\n",
err_mask);
return;
}
log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
if (!log_pages) {
ata_dev_warn(dev,
"NCQ Send/Recv Log not supported\n");
return;
}
err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV,
0, ap->sector_buf, 1);
if (err_mask) {
ata_dev_dbg(dev,
"failed to get NCQ Send/Recv Log Emask 0x%x\n",
err_mask);
} else {
u8 *cmds = dev->ncq_send_recv_cmds;
dev->flags |= ATA_DFLAG_NCQ_SEND_RECV;
memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_SEND_RECV_SIZE);
if (dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) {
ata_dev_dbg(dev, "disabling queued TRIM support\n");
cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &=
~ATA_LOG_NCQ_SEND_RECV_DSM_TRIM;
}
}
}
static void ata_dev_config_ncq_non_data(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
unsigned int err_mask;
int log_index = ATA_LOG_NCQ_NON_DATA * 2;
u16 log_pages;
err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
0, ap->sector_buf, 1);
if (err_mask) {
ata_dev_dbg(dev,
"failed to get Log Directory Emask 0x%x\n",
err_mask);
return;
}
log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
if (!log_pages) {
ata_dev_warn(dev,
"NCQ Send/Recv Log not supported\n");
return;
}
err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_NON_DATA,
0, ap->sector_buf, 1);
if (err_mask) {
ata_dev_dbg(dev,
"failed to get NCQ Non-Data Log Emask 0x%x\n",
err_mask);
} else {
u8 *cmds = dev->ncq_non_data_cmds;
memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_NON_DATA_SIZE);
}
}
static int ata_dev_config_ncq(struct ata_device *dev,
char *desc, size_t desc_sz)
{
......@@ -2123,29 +2199,125 @@ static int ata_dev_config_ncq(struct ata_device *dev,
snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth,
ddepth, aa_desc);
if ((ap->flags & ATA_FLAG_FPDMA_AUX) &&
ata_id_has_ncq_send_and_recv(dev->id)) {
err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV,
0, ap->sector_buf, 1);
if ((ap->flags & ATA_FLAG_FPDMA_AUX)) {
if (ata_id_has_ncq_send_and_recv(dev->id))
ata_dev_config_ncq_send_recv(dev);
if (ata_id_has_ncq_non_data(dev->id))
ata_dev_config_ncq_non_data(dev);
}
return 0;
}
static void ata_dev_config_sense_reporting(struct ata_device *dev)
{
unsigned int err_mask;
if (!ata_id_has_sense_reporting(dev->id))
return;
if (ata_id_sense_reporting_enabled(dev->id))
return;
err_mask = ata_dev_set_feature(dev, SETFEATURE_SENSE_DATA, 0x1);
if (err_mask) {
ata_dev_dbg(dev,
"failed to get NCQ Send/Recv Log Emask 0x%x\n",
"failed to enable Sense Data Reporting, Emask 0x%x\n",
err_mask);
} else {
u8 *cmds = dev->ncq_send_recv_cmds;
}
}
dev->flags |= ATA_DFLAG_NCQ_SEND_RECV;
memcpy(cmds, ap->sector_buf, ATA_LOG_NCQ_SEND_RECV_SIZE);
static void ata_dev_config_zac(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
unsigned int err_mask;
u8 *identify_buf = ap->sector_buf;
int log_index = ATA_LOG_SATA_ID_DEV_DATA * 2, i, found = 0;
u16 log_pages;
if (dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM) {
ata_dev_dbg(dev, "disabling queued TRIM support\n");
cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &=
~ATA_LOG_NCQ_SEND_RECV_DSM_TRIM;
dev->zac_zones_optimal_open = U32_MAX;
dev->zac_zones_optimal_nonseq = U32_MAX;
dev->zac_zones_max_open = U32_MAX;
/*
* Always set the 'ZAC' flag for Host-managed devices.
*/
if (dev->class == ATA_DEV_ZAC)
dev->flags |= ATA_DFLAG_ZAC;
else if (ata_id_zoned_cap(dev->id) == 0x01)
/*
* Check for host-aware devices.
*/
dev->flags |= ATA_DFLAG_ZAC;
if (!(dev->flags & ATA_DFLAG_ZAC))
return;
/*
* Read Log Directory to figure out if IDENTIFY DEVICE log
* is supported.
*/
err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
0, ap->sector_buf, 1);
if (err_mask) {
ata_dev_info(dev,
"failed to get Log Directory Emask 0x%x\n",
err_mask);
return;
}
log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
if (log_pages == 0) {
ata_dev_warn(dev,
"ATA Identify Device Log not supported\n");
return;
}
/*
* Read IDENTIFY DEVICE data log, page 0, to figure out
* if page 9 is supported.
*/
err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA, 0,
identify_buf, 1);
if (err_mask) {
ata_dev_info(dev,
"failed to get Device Identify Log Emask 0x%x\n",
err_mask);
return;
}
log_pages = identify_buf[8];
for (i = 0; i < log_pages; i++) {
if (identify_buf[9 + i] == ATA_LOG_ZONED_INFORMATION) {
found++;
break;
}
}
if (!found) {
ata_dev_warn(dev,
"ATA Zoned Information Log not supported\n");
return;
}
return 0;
/*
* Read IDENTIFY DEVICE data log, page 9 (Zoned-device information)
*/
err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA,
ATA_LOG_ZONED_INFORMATION,
identify_buf, 1);
if (!err_mask) {
u64 zoned_cap, opt_open, opt_nonseq, max_open;
zoned_cap = get_unaligned_le64(&identify_buf[8]);
if ((zoned_cap >> 63))
dev->zac_zoned_cap = (zoned_cap & 1);
opt_open = get_unaligned_le64(&identify_buf[24]);
if ((opt_open >> 63))
dev->zac_zones_optimal_open = (u32)opt_open;
opt_nonseq = get_unaligned_le64(&identify_buf[32]);
if ((opt_nonseq >> 63))
dev->zac_zones_optimal_nonseq = (u32)opt_nonseq;
max_open = get_unaligned_le64(&identify_buf[40]);
if ((max_open >> 63))
dev->zac_zones_max_open = (u32)max_open;
}
}
/**
......@@ -2370,7 +2542,8 @@ int ata_dev_configure(struct ata_device *dev)
dev->devslp_timing[i] = sata_setting[j];
}
}
ata_dev_config_sense_reporting(dev);
ata_dev_config_zac(dev);
dev->cdb_len = 16;
}
......
......@@ -1600,6 +1600,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
tf->hob_lbah = buf[10];
tf->nsect = buf[12];
tf->hob_nsect = buf[13];
if (ata_id_has_ncq_autosense(dev->id))
tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
return 0;
}
......@@ -1635,6 +1637,56 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
return err_mask;
}
/**
* ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
* @dev: device to perform REQUEST_SENSE_SENSE_DATA_EXT to
* @cmd: scsi command for which the sense code should be set
*
* Perform REQUEST_SENSE_DATA_EXT after the device reported CHECK
* SENSE. This function is an EH helper.
*
* LOCKING:
* Kernel thread context (may sleep).
*/
static void ata_eh_request_sense(struct ata_queued_cmd *qc,
struct scsi_cmnd *cmd)
{
struct ata_device *dev = qc->dev;
struct ata_taskfile tf;
unsigned int err_mask;
if (qc->ap->pflags & ATA_PFLAG_FROZEN) {
ata_dev_warn(dev, "sense data available but port frozen\n");
return;
}
if (!cmd || qc->flags & ATA_QCFLAG_SENSE_VALID)
return;
if (!ata_id_sense_reporting_enabled(dev->id)) {
ata_dev_warn(qc->dev, "sense data reporting disabled\n");
return;
}
DPRINTK("ATA request sense\n");
ata_tf_init(dev, &tf);
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
tf.command = ATA_CMD_REQ_SENSE_DATA;
tf.protocol = ATA_PROT_NODATA;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
/* Ignore err_mask; ATA_ERR might be set */
if (tf.command & ATA_SENSE) {
ata_scsi_set_sense(dev, cmd, tf.lbah, tf.lbam, tf.lbal);
qc->flags |= ATA_QCFLAG_SENSE_VALID;
} else {
ata_dev_warn(dev, "request sense failed stat %02x emask %x\n",
tf.command, err_mask);
}
}
/**
* atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
* @dev: device to perform REQUEST_SENSE to
......@@ -1797,6 +1849,18 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
memcpy(&qc->result_tf, &tf, sizeof(tf));
qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
if ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary) {
char sense_key, asc, ascq;
sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
asc = (qc->result_tf.auxiliary >> 8) & 0xff;
ascq = qc->result_tf.auxiliary & 0xff;
ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, ascq);
ata_scsi_set_sense_information(dev, qc->scsicmd,
&qc->result_tf);
qc->flags |= ATA_QCFLAG_SENSE_VALID;
}
ehc->i.err_mask &= ~AC_ERR_DEV;
}
......@@ -1826,14 +1890,23 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
return ATA_EH_RESET;
}
if (stat & (ATA_ERR | ATA_DF))
if (stat & (ATA_ERR | ATA_DF)) {
qc->err_mask |= AC_ERR_DEV;
else
/*
* Sense data reporting does not work if the
* device fault bit is set.
*/
if (stat & ATA_DF)
stat &= ~ATA_SENSE;
} else {
return 0;
}
switch (qc->dev->class) {
case ATA_DEV_ATA:
case ATA_DEV_ZAC:
if (stat & ATA_SENSE)
ata_eh_request_sense(qc, qc->scsicmd);
if (err & ATA_ICRC)
qc->err_mask |= AC_ERR_ATA_BUS;
if (err & (ATA_UNC | ATA_AMNF))
......@@ -1847,20 +1920,31 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
tmp = atapi_eh_request_sense(qc->dev,
qc->scsicmd->sense_buffer,
qc->result_tf.feature >> 4);
if (!tmp) {
/* ATA_QCFLAG_SENSE_VALID is used to
* tell atapi_qc_complete() that sense
* data is already valid.
*
* TODO: interpret sense data and set
* appropriate err_mask.
*/
if (!tmp)
qc->flags |= ATA_QCFLAG_SENSE_VALID;
} else
else
qc->err_mask |= tmp;
}
}
if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
int ret = scsi_check_sense(qc->scsicmd);
/*
* SUCCESS here means that the sense code could
* evaluated and should be passed to the upper layers
* for correct evaluation.
* FAILED means the sense code could not interpreted
* and the device would need to be reset.
* NEEDS_RETRY and ADD_TO_MLQUEUE means that the
* command would need to be retried.
*/
if (ret == NEEDS_RETRY || ret == ADD_TO_MLQUEUE) {
qc->flags |= ATA_QCFLAG_RETRY;
qc->err_mask |= AC_ERR_OTHER;
} else if (ret != SUCCESS) {
qc->err_mask |= AC_ERR_HSM;
}
}
if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
action |= ATA_EH_RESET;
......@@ -2398,6 +2482,8 @@ const char *ata_get_cmd_descript(u8 command)
{ ATA_CMD_CFA_WRITE_MULT_NE, "CFA WRITE MULTIPLE WITHOUT ERASE" },
{ ATA_CMD_REQ_SENSE_DATA, "REQUEST SENSE DATA EXT" },
{ ATA_CMD_SANITIZE_DEVICE, "SANITIZE DEVICE" },
{ ATA_CMD_ZAC_MGMT_IN, "ZAC MANAGEMENT IN" },
{ ATA_CMD_ZAC_MGMT_OUT, "ZAC MANAGEMENT OUT" },
{ ATA_CMD_READ_LONG, "READ LONG (with retries)" },
{ ATA_CMD_READ_LONG_ONCE, "READ LONG (without retries)" },
{ ATA_CMD_WRITE_LONG, "WRITE LONG (with retries)" },
......@@ -2569,14 +2655,15 @@ static void ata_eh_link_report(struct ata_link *link)
#ifdef CONFIG_ATA_VERBOSE_ERROR
if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
ATA_ERR)) {
ATA_SENSE | ATA_ERR)) {
if (res->command & ATA_BUSY)
ata_dev_err(qc->dev, "status: { Busy }\n");
else
ata_dev_err(qc->dev, "status: { %s%s%s%s}\n",
ata_dev_err(qc->dev, "status: { %s%s%s%s%s}\n",
res->command & ATA_DRDY ? "DRDY " : "",
res->command & ATA_DF ? "DF " : "",
res->command & ATA_DRQ ? "DRQ " : "",
res->command & ATA_SENSE ? "SENSE " : "",
res->command & ATA_ERR ? "ERR " : "");
}
......
This diff is collapsed.
......@@ -149,3 +149,75 @@ libata_trace_parse_qc_flags(struct trace_seq *p, unsigned int qc_flags)
return ret;
}
const char *
libata_trace_parse_subcmd(struct trace_seq *p, unsigned char cmd,
unsigned char feature, unsigned char hob_nsect)
{
const char *ret = trace_seq_buffer_ptr(p);
switch (cmd) {
case ATA_CMD_FPDMA_RECV:
switch (hob_nsect & 0x5f) {
case ATA_SUBCMD_FPDMA_RECV_RD_LOG_DMA_EXT:
trace_seq_printf(p, " READ_LOG_DMA_EXT");
break;
case ATA_SUBCMD_FPDMA_RECV_ZAC_MGMT_IN:
trace_seq_printf(p, " ZAC_MGMT_IN");
break;
}
break;
case ATA_CMD_FPDMA_SEND:
switch (hob_nsect & 0x5f) {
case ATA_SUBCMD_FPDMA_SEND_WR_LOG_DMA_EXT:
trace_seq_printf(p, " WRITE_LOG_DMA_EXT");
break;
case ATA_SUBCMD_FPDMA_SEND_DSM:
trace_seq_printf(p, " DATASET_MANAGEMENT");
break;
}
break;
case ATA_CMD_NCQ_NON_DATA:
switch (feature) {
case ATA_SUBCMD_NCQ_NON_DATA_ABORT_QUEUE:
trace_seq_printf(p, " ABORT_QUEUE");
break;
case ATA_SUBCMD_NCQ_NON_DATA_SET_FEATURES:
trace_seq_printf(p, " SET_FEATURES");
break;
case ATA_SUBCMD_NCQ_NON_DATA_ZERO_EXT:
trace_seq_printf(p, " ZERO_EXT");
break;
case ATA_SUBCMD_NCQ_NON_DATA_ZAC_MGMT_OUT:
trace_seq_printf(p, " ZAC_MGMT_OUT");
break;
}
break;
case ATA_CMD_ZAC_MGMT_IN:
switch (feature) {
case ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES:
trace_seq_printf(p, " REPORT_ZONES");
break;
}
break;
case ATA_CMD_ZAC_MGMT_OUT:
switch (feature) {
case ATA_SUBCMD_ZAC_MGMT_OUT_CLOSE_ZONE:
trace_seq_printf(p, " CLOSE_ZONE");
break;
case ATA_SUBCMD_ZAC_MGMT_OUT_FINISH_ZONE:
trace_seq_printf(p, " FINISH_ZONE");
break;
case ATA_SUBCMD_ZAC_MGMT_OUT_OPEN_ZONE:
trace_seq_printf(p, " OPEN_ZONE");
break;
case ATA_SUBCMD_ZAC_MGMT_OUT_RESET_WRITE_POINTER:
trace_seq_printf(p, " RESET_WRITE_POINTER");
break;
}
break;
}
trace_seq_putc(p, 0);
return ret;
}
......@@ -67,7 +67,8 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
u64 block, u32 n_block, unsigned int tf_flags,
unsigned int tag);
extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev);
extern u64 ata_tf_read_block(const struct ata_taskfile *tf,
struct ata_device *dev);
extern unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, void *buf, unsigned int buflen,
......@@ -137,6 +138,11 @@ extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht);
extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_set_sense(struct ata_device *dev,
struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq);
extern void ata_scsi_set_sense_information(struct ata_device *dev,
struct scsi_cmnd *cmd,
const struct ata_taskfile *tf);
extern void ata_scsi_media_change_notify(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
......
......@@ -1630,6 +1630,9 @@ static u8 get_ata_protocol(u8 cmd, int direction)
switch (cmd) {
case ATA_CMD_FPDMA_WRITE:
case ATA_CMD_FPDMA_READ:
case ATA_CMD_FPDMA_RECV:
case ATA_CMD_FPDMA_SEND:
case ATA_CMD_NCQ_NON_DATA:
return SATA_PROTOCOL_FPDMA;
case ATA_CMD_ID_ATA:
......
......@@ -3169,7 +3169,10 @@ static enum sci_status isci_request_stp_request_construct(struct isci_request *i
status = sci_io_request_construct_basic_sata(ireq);
if (qc && (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
qc->tf.command == ATA_CMD_FPDMA_READ)) {
qc->tf.command == ATA_CMD_FPDMA_READ ||
qc->tf.command == ATA_CMD_FPDMA_RECV ||
qc->tf.command == ATA_CMD_FPDMA_SEND ||
qc->tf.command == ATA_CMD_NCQ_NON_DATA)) {
fis->sector_count = qc->tag << 3;
ireq->tc->type.stp.ncq_tag = qc->tag;
}
......
......@@ -205,7 +205,10 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
task->task_done = sas_ata_task_done;
if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
qc->tf.command == ATA_CMD_FPDMA_READ) {
qc->tf.command == ATA_CMD_FPDMA_READ ||
qc->tf.command == ATA_CMD_FPDMA_RECV ||
qc->tf.command == ATA_CMD_FPDMA_SEND ||
qc->tf.command == ATA_CMD_NCQ_NON_DATA) {
/* Need to zero out the tag libata assigned us */
qc->tf.nsect = 0;
}
......@@ -548,7 +551,7 @@ static struct ata_port_operations sas_sata_ops = {
static struct ata_port_info sata_port_info = {
.flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ |
ATA_FLAG_SAS_HOST,
ATA_FLAG_SAS_HOST | ATA_FLAG_FPDMA_AUX,
.pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
......
......@@ -429,7 +429,10 @@ static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag)
if (qc) {
if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
qc->tf.command == ATA_CMD_FPDMA_READ) {
qc->tf.command == ATA_CMD_FPDMA_READ ||
qc->tf.command == ATA_CMD_FPDMA_RECV ||
qc->tf.command == ATA_CMD_FPDMA_SEND ||
qc->tf.command == ATA_CMD_NCQ_NON_DATA) {
*tag = qc->tag;
return 1;
}
......
......@@ -280,7 +280,10 @@ u32 pm8001_get_ncq_tag(struct sas_task *task, u32 *tag)
struct ata_queued_cmd *qc = task->uldd_task;
if (qc) {
if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
qc->tf.command == ATA_CMD_FPDMA_READ) {
qc->tf.command == ATA_CMD_FPDMA_READ ||
qc->tf.command == ATA_CMD_FPDMA_RECV ||
qc->tf.command == ATA_CMD_FPDMA_SEND ||
qc->tf.command == ATA_CMD_NCQ_NON_DATA) {
*tag = qc->tag;
return 1;
}
......
......@@ -293,3 +293,56 @@ int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
return 0;
}
EXPORT_SYMBOL(scsi_set_sense_information);
/**
* scsi_set_sense_field_pointer - set the field pointer sense key
* specific information in a formatted sense data buffer
* @buf: Where to build sense data
* @buf_len: buffer length
* @fp: field pointer to be set
* @bp: bit pointer to be set
* @cd: command/data bit
*
* Return value:
* 0 on success or EINVAL for invalid sense buffer length
*/
int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd)
{
u8 *ucp, len;
if ((buf[0] & 0x7f) == 0x72) {
len = buf[7];
ucp = (char *)scsi_sense_desc_find(buf, len + 8, 2);
if (!ucp) {
buf[7] = len + 8;
ucp = buf + 8 + len;
}
if (buf_len < len + 8)
/* Not enough room for info */
return -EINVAL;
ucp[0] = 2;
ucp[1] = 6;
ucp[4] = 0x80; /* Valid bit */
if (cd)
ucp[4] |= 0x40;
if (bp < 0x8)
ucp[4] |= 0x8 | bp;
put_unaligned_be16(fp, &ucp[5]);
} else if ((buf[0] & 0x7f) == 0x70) {
len = buf[7];
if (len < 18)
buf[7] = 18;
buf[15] = 0x80;
if (cd)
buf[15] |= 0x40;
if (bp < 0x8)
buf[15] |= 0x8 | bp;
put_unaligned_be16(fp, &buf[16]);
}
return 0;
}
EXPORT_SYMBOL(scsi_set_sense_field_pointer);
......@@ -452,7 +452,7 @@ static void scsi_report_sense(struct scsi_device *sdev,
* When a deferred error is detected the current command has
* not been executed and needs retrying.
*/
static int scsi_check_sense(struct scsi_cmnd *scmd)
int scsi_check_sense(struct scsi_cmnd *scmd)
{
struct scsi_device *sdev = scmd->device;
struct scsi_sense_hdr sshdr;
......@@ -602,6 +602,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
return SUCCESS;
}
}
EXPORT_SYMBOL_GPL(scsi_check_sense);
static void scsi_handle_queue_ramp_up(struct scsi_device *sdev)
{
......
......@@ -243,6 +243,7 @@ enum {
ATA_CMD_WRITE_QUEUED_FUA_EXT = 0x3E,
ATA_CMD_FPDMA_READ = 0x60,
ATA_CMD_FPDMA_WRITE = 0x61,
ATA_CMD_NCQ_NON_DATA = 0x63,
ATA_CMD_FPDMA_SEND = 0x64,
ATA_CMD_FPDMA_RECV = 0x65,
ATA_CMD_PIO_READ = 0x20,
......@@ -301,19 +302,43 @@ enum {
ATA_CMD_CFA_WRITE_MULT_NE = 0xCD,
ATA_CMD_REQ_SENSE_DATA = 0x0B,
ATA_CMD_SANITIZE_DEVICE = 0xB4,
ATA_CMD_ZAC_MGMT_IN = 0x4A,
ATA_CMD_ZAC_MGMT_OUT = 0x9F,
/* marked obsolete in the ATA/ATAPI-7 spec */
ATA_CMD_RESTORE = 0x10,
/* Subcmds for ATA_CMD_FPDMA_RECV */
ATA_SUBCMD_FPDMA_RECV_RD_LOG_DMA_EXT = 0x01,
ATA_SUBCMD_FPDMA_RECV_ZAC_MGMT_IN = 0x02,
/* Subcmds for ATA_CMD_FPDMA_SEND */
ATA_SUBCMD_FPDMA_SEND_DSM = 0x00,
ATA_SUBCMD_FPDMA_SEND_WR_LOG_DMA_EXT = 0x02,
/* Subcmds for ATA_CMD_NCQ_NON_DATA */
ATA_SUBCMD_NCQ_NON_DATA_ABORT_QUEUE = 0x00,
ATA_SUBCMD_NCQ_NON_DATA_SET_FEATURES = 0x05,
ATA_SUBCMD_NCQ_NON_DATA_ZERO_EXT = 0x06,
ATA_SUBCMD_NCQ_NON_DATA_ZAC_MGMT_OUT = 0x07,
/* Subcmds for ATA_CMD_ZAC_MGMT_IN */
ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES = 0x00,
/* Subcmds for ATA_CMD_ZAC_MGMT_OUT */
ATA_SUBCMD_ZAC_MGMT_OUT_CLOSE_ZONE = 0x01,
ATA_SUBCMD_ZAC_MGMT_OUT_FINISH_ZONE = 0x02,
ATA_SUBCMD_ZAC_MGMT_OUT_OPEN_ZONE = 0x03,
ATA_SUBCMD_ZAC_MGMT_OUT_RESET_WRITE_POINTER = 0x04,
/* READ_LOG_EXT pages */
ATA_LOG_DIRECTORY = 0x0,
ATA_LOG_SATA_NCQ = 0x10,
ATA_LOG_NCQ_NON_DATA = 0x12,
ATA_LOG_NCQ_SEND_RECV = 0x13,
ATA_LOG_SATA_ID_DEV_DATA = 0x30,
ATA_LOG_SATA_SETTINGS = 0x08,
ATA_LOG_ZONED_INFORMATION = 0x09,
ATA_LOG_DEVSLP_OFFSET = 0x30,
ATA_LOG_DEVSLP_SIZE = 0x08,
ATA_LOG_DEVSLP_MDAT = 0x00,
......@@ -328,8 +353,25 @@ enum {
ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET = 0x04,
ATA_LOG_NCQ_SEND_RECV_DSM_TRIM = (1 << 0),
ATA_LOG_NCQ_SEND_RECV_RD_LOG_OFFSET = 0x08,
ATA_LOG_NCQ_SEND_RECV_RD_LOG_SUPPORTED = (1 << 0),
ATA_LOG_NCQ_SEND_RECV_WR_LOG_OFFSET = 0x0C,
ATA_LOG_NCQ_SEND_RECV_SIZE = 0x10,
ATA_LOG_NCQ_SEND_RECV_WR_LOG_SUPPORTED = (1 << 0),
ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_OFFSET = 0x10,
ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_OUT_SUPPORTED = (1 << 0),
ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_IN_SUPPORTED = (1 << 1),
ATA_LOG_NCQ_SEND_RECV_SIZE = 0x14,
/* NCQ Non-Data log */
ATA_LOG_NCQ_NON_DATA_SUBCMDS_OFFSET = 0x00,
ATA_LOG_NCQ_NON_DATA_ABORT_OFFSET = 0x00,
ATA_LOG_NCQ_NON_DATA_ABORT_NCQ = (1 << 0),
ATA_LOG_NCQ_NON_DATA_ABORT_ALL = (1 << 1),
ATA_LOG_NCQ_NON_DATA_ABORT_STREAMING = (1 << 2),
ATA_LOG_NCQ_NON_DATA_ABORT_NON_STREAMING = (1 << 3),
ATA_LOG_NCQ_NON_DATA_ABORT_SELECTED = (1 << 4),
ATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OFFSET = 0x1C,
ATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OUT = (1 << 0),
ATA_LOG_NCQ_NON_DATA_SIZE = 0x40,
/* READ/WRITE LONG (obsolete) */
ATA_CMD_READ_LONG = 0x22,
......@@ -386,6 +428,8 @@ enum {
SATA_SSP = 0x06, /* Software Settings Preservation */
SATA_DEVSLP = 0x09, /* Device Sleep */
SETFEATURE_SENSE_DATA = 0xC3, /* Sense Data Reporting feature */
/* feature values for SET_MAX */
ATA_SET_MAX_ADDR = 0x00,
ATA_SET_MAX_PASSWD = 0x01,
......@@ -529,6 +573,8 @@ struct ata_bmdma_prd {
#define ata_id_cdb_intr(id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20)
#define ata_id_has_da(id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4))
#define ata_id_has_devslp(id) ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8))
#define ata_id_has_ncq_autosense(id) \
((id)[ATA_ID_FEATURE_SUPP] & (1 << 7))
static inline bool ata_id_has_hipm(const u16 *id)
{
......@@ -717,6 +763,20 @@ static inline bool ata_id_has_read_log_dma_ext(const u16 *id)
return false;
}
static inline bool ata_id_has_sense_reporting(const u16 *id)
{
if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
return false;
return id[ATA_ID_COMMAND_SET_3] & (1 << 6);
}
static inline bool ata_id_sense_reporting_enabled(const u16 *id)
{
if (!(id[ATA_ID_CFS_ENABLE_2] & (1 << 15)))
return false;
return id[ATA_ID_COMMAND_SET_4] & (1 << 6);
}
/**
* ata_id_major_version - get ATA level of drive
* @id: Identify data
......@@ -821,6 +881,11 @@ static inline bool ata_id_has_ncq_send_and_recv(const u16 *id)
return id[ATA_ID_SATA_CAPABILITY_2] & BIT(6);
}
static inline bool ata_id_has_ncq_non_data(const u16 *id)
{
return id[ATA_ID_SATA_CAPABILITY_2] & BIT(5);
}
static inline bool ata_id_has_trim(const u16 *id)
{
if (ata_id_major_version(id) >= 7 &&
......@@ -872,6 +937,11 @@ static inline bool ata_id_is_ssd(const u16 *id)
return id[ATA_ID_ROT_SPEED] == 0x01;
}
static inline u8 ata_id_zoned_cap(const u16 *id)
{
return (id[ATA_ID_ADDITIONAL_SUPP] & 0x3);
}
static inline bool ata_id_pio_need_iordy(const u16 *id, const u8 pio)
{
/* CF spec. r4.1 Table 22 says no IORDY on PIO5 and PIO6. */
......
......@@ -180,6 +180,8 @@ enum {
ATA_DFLAG_DA = (1 << 26), /* device supports Device Attention */
ATA_DFLAG_DEVSLP = (1 << 27), /* device supports Device Sleep */
ATA_DFLAG_ACPI_DISABLED = (1 << 28), /* ACPI for the device is disabled */
ATA_DFLAG_D_SENSE = (1 << 29), /* Descriptor sense requested */
ATA_DFLAG_ZAC = (1 << 30), /* ZAC device */
ATA_DEV_UNKNOWN = 0, /* unknown device */
ATA_DEV_ATA = 1, /* ATA device */
......@@ -191,7 +193,8 @@ enum {
ATA_DEV_SEMB = 7, /* SEMB */
ATA_DEV_SEMB_UNSUP = 8, /* SEMB (unsupported) */
ATA_DEV_ZAC = 9, /* ZAC device */
ATA_DEV_NONE = 10, /* no device */
ATA_DEV_ZAC_UNSUP = 10, /* ZAC device (unsupported) */
ATA_DEV_NONE = 11, /* no device */
/* struct ata_link flags */
ATA_LFLAG_NO_HRST = (1 << 1), /* avoid hardreset */
......@@ -727,6 +730,13 @@ struct ata_device {
/* NCQ send and receive log subcommand support */
u8 ncq_send_recv_cmds[ATA_LOG_NCQ_SEND_RECV_SIZE];
u8 ncq_non_data_cmds[ATA_LOG_NCQ_NON_DATA_SIZE];
/* ZAC zone configuration */
u32 zac_zoned_cap;
u32 zac_zones_optimal_open;
u32 zac_zones_optimal_nonseq;
u32 zac_zones_max_open;
/* error history */
int spdn_cnt;
......@@ -1523,7 +1533,8 @@ static inline unsigned int ata_class_enabled(unsigned int class)
static inline unsigned int ata_class_disabled(unsigned int class)
{
return class == ATA_DEV_ATA_UNSUP || class == ATA_DEV_ATAPI_UNSUP ||
class == ATA_DEV_PMP_UNSUP || class == ATA_DEV_SEMB_UNSUP;
class == ATA_DEV_PMP_UNSUP || class == ATA_DEV_SEMB_UNSUP ||
class == ATA_DEV_ZAC_UNSUP;
}
static inline unsigned int ata_class_absent(unsigned int class)
......@@ -1641,6 +1652,26 @@ static inline bool ata_fpdma_dsm_supported(struct ata_device *dev)
ATA_LOG_NCQ_SEND_RECV_DSM_TRIM);
}
static inline bool ata_fpdma_read_log_supported(struct ata_device *dev)
{
return (dev->flags & ATA_DFLAG_NCQ_SEND_RECV) &&
(dev->ncq_send_recv_cmds[ATA_LOG_NCQ_SEND_RECV_RD_LOG_OFFSET] &
ATA_LOG_NCQ_SEND_RECV_RD_LOG_SUPPORTED);
}
static inline bool ata_fpdma_zac_mgmt_in_supported(struct ata_device *dev)
{
return (dev->flags & ATA_DFLAG_NCQ_SEND_RECV) &&
(dev->ncq_send_recv_cmds[ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_OFFSET] &
ATA_LOG_NCQ_SEND_RECV_ZAC_MGMT_IN_SUPPORTED);
}
static inline bool ata_fpdma_zac_mgmt_out_supported(struct ata_device *dev)
{
return (dev->ncq_non_data_cmds[ATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OFFSET] &
ATA_LOG_NCQ_NON_DATA_ZAC_MGMT_OUT);
}
static inline void ata_qc_set_polling(struct ata_queued_cmd *qc)
{
qc->tf.ctl |= ATA_NIEN;
......
......@@ -63,6 +63,7 @@ extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
int scsi_set_sense_information(u8 *buf, int buf_len, u64 info);
int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd);
extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
int desc_type);
......
......@@ -16,6 +16,7 @@ extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
extern int scsi_block_when_processing_errors(struct scsi_device *);
extern bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
struct scsi_sense_hdr *sshdr);
extern int scsi_check_sense(struct scsi_cmnd *);
static inline bool scsi_sense_is_deferred(const struct scsi_sense_hdr *sshdr)
{
......
......@@ -39,6 +39,7 @@
ata_opcode_name(ATA_CMD_WRITE_QUEUED_FUA_EXT), \
ata_opcode_name(ATA_CMD_FPDMA_READ), \
ata_opcode_name(ATA_CMD_FPDMA_WRITE), \
ata_opcode_name(ATA_CMD_NCQ_NON_DATA), \
ata_opcode_name(ATA_CMD_FPDMA_SEND), \
ata_opcode_name(ATA_CMD_FPDMA_RECV), \
ata_opcode_name(ATA_CMD_PIO_READ), \
......@@ -97,6 +98,8 @@
ata_opcode_name(ATA_CMD_CFA_WRITE_MULT_NE), \
ata_opcode_name(ATA_CMD_REQ_SENSE_DATA), \
ata_opcode_name(ATA_CMD_SANITIZE_DEVICE), \
ata_opcode_name(ATA_CMD_ZAC_MGMT_IN), \
ata_opcode_name(ATA_CMD_ZAC_MGMT_OUT), \
ata_opcode_name(ATA_CMD_RESTORE), \
ata_opcode_name(ATA_CMD_READ_LONG), \
ata_opcode_name(ATA_CMD_READ_LONG_ONCE), \
......@@ -139,6 +142,10 @@ const char *libata_trace_parse_eh_err_mask(struct trace_seq *, unsigned int);
const char *libata_trace_parse_qc_flags(struct trace_seq *, unsigned int);
#define __parse_qc_flags(f) libata_trace_parse_qc_flags(p, f)
const char *libata_trace_parse_subcmd(struct trace_seq *, unsigned char,
unsigned char, unsigned char);
#define __parse_subcmd(c,f,h) libata_trace_parse_subcmd(p, c, f, h)
TRACE_EVENT(ata_qc_issue,
TP_PROTO(struct ata_queued_cmd *qc),
......@@ -185,11 +192,12 @@ TRACE_EVENT(ata_qc_issue,
__entry->hob_nsect = qc->tf.hob_nsect;
),
TP_printk("ata_port=%u ata_dev=%u tag=%d proto=%s cmd=%s " \
TP_printk("ata_port=%u ata_dev=%u tag=%d proto=%s cmd=%s%s " \
" tf=(%02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x)",
__entry->ata_port, __entry->ata_dev, __entry->tag,
show_protocol_name(__entry->proto),
show_opcode_name(__entry->cmd),
__parse_subcmd(__entry->cmd, __entry->feature, __entry->hob_nsect),
__entry->cmd, __entry->feature, __entry->nsect,
__entry->lbal, __entry->lbam, __entry->lbah,
__entry->hob_feature, __entry->hob_nsect,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment