mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
ata changes for 6.11-rc1
- ATA PASS-THROUGH sense data cleanups and fixes. (from Igor Pylypiv) Highlights: Store the sense data for ATA PASS-THROUGH commands at the correct offset in the sense buffer when using fixed format sense data. Cleanup the logic related to generating sense data for PASS-THROUGH commands. Generating sense data for PASS-THROUGH commands would overwrite any eventual (real) sense data received from the device. Honor the D_SENSE bit when generating sense data for PASS-THROUGH commands. (The D_SENSE bit can be set by the user, and determines if the returned sense data should be in fixed format or descriptor format.) - ata port allocation cleanups. (from me) Highlights: Assign the ata port print_id at port allocation time, such that the ata_port_* print functions can be used earlier in the init call chain. Change the ata port port print_id to use ida_alloc(), such that print_ids will get reused on rmmod + modprobe, instead of being incremented indefinitely. Remove wrappers that only existed in order to export the internal libata functions which they wrapped, and instead export the libata functions directly. - Update SATA_MOBILE_LPM_POLICY Kconfig default to med_power_with_dipm. Using this default was not always a good idea before, because it would break hot plug support. However, with LPM changes in recent kernels, a port marked as external will not enable LPM (in order to not break hot plug), so it is now safe to change the default value of this Kconfig. All major Linux distros have had SATA_MOBILE_LPM_POLICY set to med_power_with_dipm for quite a long time. (from Mario Limonciello) - Convert ahci-fsl-qoriq device tree binding to yaml format. (from Frank Li) -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRN+ES/c4tHlMch3DzJZDGjmcZNcgUCZpZkrAAKCRDJZDGjmcZN cr/YAP98wiT4VCiEb1iQBShyYYaxpEiVUPtpHCIa+uLC56IZkgEAvAx9fbwF9uJy 2VQS1+x03Ui0W+b2irMJcYbTnhXjmQk= =HOH5 -----END PGP SIGNATURE----- Merge tag 'ata-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux Pull ata updates from Niklas Cassel: - ATA PASS-THROUGH sense data cleanups and fixes (Igor Pylypiv) Store the sense data for ATA PASS-THROUGH commands at the correct offset in the sense buffer when using fixed format sense data. Cleanup the logic related to generating sense data for PASS-THROUGH commands. Generating sense data for PASS-THROUGH commands would overwrite any eventual (real) sense data received from the device. Honor the D_SENSE bit when generating sense data for PASS-THROUGH commands. (The D_SENSE bit can be set by the user, and determines if the returned sense data should be in fixed format or descriptor format) - ata port allocation cleanups (me) Assign the ata port print_id at port allocation time, such that the ata_port_* print functions can be used earlier in the init call chain. Change the ata port port print_id to use ida_alloc(), such that print_ids will get reused on rmmod + modprobe, instead of being incremented indefinitely. Remove wrappers that only existed in order to export the internal libata functions which they wrapped, and instead export the libata functions directly. - Update SATA_MOBILE_LPM_POLICY Kconfig default to med_power_with_dipm (Mario Limonciello) Using this default was not always a good idea before, because it would break hot plug support. However, with LPM changes in recent kernels, a port marked as external will not enable LPM (in order to not break hot plug), so it is now safe to change the default value of this Kconfig. All major Linux distros have had SATA_MOBILE_LPM_POLICY set to med_power_with_dipm for quite a long time - Convert ahci-fsl-qoriq device tree binding to yaml format (Frank Li) * tag 'ata-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux: dt-bindings: ata: ahci-fsl-qoriq: add fsl,ls1046a-ahci and fsl,ls1012a-ahci ata: ahci: Add debug print for external port ata,scsi: Remove wrapper ata_sas_port_alloc() ata: libata-core: Reuse available ata_port print_ids ata: libata: Assign print_id at port allocation time ata: libata-core: Remove local_port_no struct member ata: libata-sata: Remove superfluous assignment in ata_sas_port_alloc() ata: libata-core: Remove support for decreasing the number of ports ata: libata: Remove unused function declaration for ata_scsi_detect() ata,scsi: Remove wrappers ata_sas_tport_{add,delete}() ata: libata-scsi: Check ATA_QCFLAG_RTF_FILLED before using result_tf ata: libata-core: Set ATA_QCFLAG_RTF_FILLED in fill_result_tf() ata: libata-scsi: Do not pass ATA device id to ata_to_sense_error() ata: libata-scsi: Remove redundant sense_buffer memsets ata: libata-scsi: Honor the D_SENSE bit for CK_COND=1 and no error ata: libata-scsi: Do not overwrite valid sense data when CK_COND=1 ata: libata-scsi: Fix offsets for the fixed format sense data dt-bindings: ata: ahci-fsl-qoriq: convert to yaml format ata: Kconfig: Update SATA_MOBILE_LPM_POLICY default to med_power_with_dipm
This commit is contained in:
commit
e2f710f97f
@ -1,21 +0,0 @@
|
||||
Binding for Freescale QorIQ AHCI SATA Controller
|
||||
|
||||
Required properties:
|
||||
- reg: Physical base address and size of the controller's register area.
|
||||
- compatible: Compatibility string. Must be 'fsl,<chip>-ahci', where
|
||||
chip could be ls1021a, ls1043a, ls1046a, ls1088a, ls2080a etc.
|
||||
- clocks: Input clock specifier. Refer to common clock bindings.
|
||||
- interrupts: Interrupt specifier. Refer to interrupt binding.
|
||||
|
||||
Optional properties:
|
||||
- dma-coherent: Enable AHCI coherent DMA operation.
|
||||
- reg-names: register area names when there are more than 1 register area.
|
||||
|
||||
Examples:
|
||||
sata@3200000 {
|
||||
compatible = "fsl,ls1021a-ahci";
|
||||
reg = <0x0 0x3200000 0x0 0x10000>;
|
||||
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&platform_clk 1>;
|
||||
dma-coherent;
|
||||
};
|
64
Documentation/devicetree/bindings/ata/fsl,ahci.yaml
Normal file
64
Documentation/devicetree/bindings/ata/fsl,ahci.yaml
Normal file
@ -0,0 +1,64 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/ata/fsl,ahci.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale QorIQ AHCI SATA Controller
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: SATA controller for ls1012a
|
||||
items:
|
||||
- const: fsl,ls1012a-ahci
|
||||
- const: fsl,ls1043a-ahci
|
||||
- enum:
|
||||
- fsl,ls1021a-ahci
|
||||
- fsl,ls1028a-ahci
|
||||
- fsl,ls1043a-ahci
|
||||
- fsl,ls1046a-ahci
|
||||
- fsl,ls1088a-ahci
|
||||
- fsl,ls2080a-ahci
|
||||
- fsl,lx2160a-ahci
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: ahci
|
||||
- const: sata-ecc
|
||||
minItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
sata@3200000 {
|
||||
compatible = "fsl,ls1021a-ahci";
|
||||
reg = <0x3200000 0x10000>;
|
||||
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&platform_clk 1>;
|
||||
dma-coherent;
|
||||
};
|
@ -118,7 +118,7 @@ config SATA_AHCI
|
||||
config SATA_MOBILE_LPM_POLICY
|
||||
int "Default SATA Link Power Management policy"
|
||||
range 0 4
|
||||
default 0
|
||||
default 3
|
||||
depends on SATA_AHCI
|
||||
help
|
||||
Select the Default SATA Link Power Management (LPM) policy to use
|
||||
|
@ -1732,8 +1732,10 @@ static void ahci_update_initial_lpm_policy(struct ata_port *ap)
|
||||
* Management Interaction in AHCI 1.3.1. Therefore, do not enable
|
||||
* LPM if the port advertises itself as an external port.
|
||||
*/
|
||||
if (ap->pflags & ATA_PFLAG_EXTERNAL)
|
||||
if (ap->pflags & ATA_PFLAG_EXTERNAL) {
|
||||
ata_port_dbg(ap, "external port, not enabling LPM\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If no LPM states are supported by the HBA, do not bother with LPM */
|
||||
if ((ap->host->flags & ATA_HOST_NO_PART) &&
|
||||
|
@ -2075,13 +2075,6 @@ static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
|
||||
struct ahci_port_priv *pp = qc->ap->private_data;
|
||||
u8 *rx_fis = pp->rx_fis;
|
||||
|
||||
/*
|
||||
* rtf may already be filled (e.g. for successful NCQ commands).
|
||||
* If that is the case, we have nothing to do.
|
||||
*/
|
||||
if (qc->flags & ATA_QCFLAG_RTF_FILLED)
|
||||
return;
|
||||
|
||||
if (pp->fbs_enabled)
|
||||
rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
|
||||
|
||||
@ -2095,7 +2088,6 @@ static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
|
||||
!(qc->flags & ATA_QCFLAG_EH)) {
|
||||
ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
|
||||
qc->result_tf.status = (rx_fis + RX_FIS_PIO_SETUP)[15];
|
||||
qc->flags |= ATA_QCFLAG_RTF_FILLED;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2118,12 +2110,10 @@ static void ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
|
||||
*/
|
||||
qc->result_tf.status = fis[2];
|
||||
qc->result_tf.error = fis[3];
|
||||
qc->flags |= ATA_QCFLAG_RTF_FILLED;
|
||||
return;
|
||||
}
|
||||
|
||||
ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
|
||||
qc->flags |= ATA_QCFLAG_RTF_FILLED;
|
||||
}
|
||||
|
||||
static void ahci_qc_ncq_fill_rtf(struct ata_port *ap, u64 done_mask)
|
||||
@ -2158,6 +2148,7 @@ static void ahci_qc_ncq_fill_rtf(struct ata_port *ap, u64 done_mask)
|
||||
if (qc && ata_is_ncq(qc->tf.protocol)) {
|
||||
qc->result_tf.status = status;
|
||||
qc->result_tf.error = error;
|
||||
qc->result_tf.flags = qc->tf.flags;
|
||||
qc->flags |= ATA_QCFLAG_RTF_FILLED;
|
||||
}
|
||||
done_mask &= ~(1ULL << tag);
|
||||
@ -2182,6 +2173,7 @@ static void ahci_qc_ncq_fill_rtf(struct ata_port *ap, u64 done_mask)
|
||||
fis += RX_FIS_SDB;
|
||||
qc->result_tf.status = fis[2];
|
||||
qc->result_tf.error = fis[3];
|
||||
qc->result_tf.flags = qc->tf.flags;
|
||||
qc->flags |= ATA_QCFLAG_RTF_FILLED;
|
||||
}
|
||||
done_mask &= ~(1ULL << tag);
|
||||
|
@ -86,7 +86,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
|
||||
static void ata_dev_xfermask(struct ata_device *dev);
|
||||
static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
|
||||
|
||||
atomic_t ata_print_id = ATOMIC_INIT(0);
|
||||
static DEFINE_IDA(ata_ida);
|
||||
|
||||
#ifdef CONFIG_ATA_FORCE
|
||||
struct ata_force_param {
|
||||
@ -4800,8 +4800,16 @@ static void fill_result_tf(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
|
||||
/*
|
||||
* rtf may already be filled (e.g. for successful NCQ commands).
|
||||
* If that is the case, we have nothing to do.
|
||||
*/
|
||||
if (qc->flags & ATA_QCFLAG_RTF_FILLED)
|
||||
return;
|
||||
|
||||
qc->result_tf.flags = qc->tf.flags;
|
||||
ap->ops->qc_fill_rtf(qc);
|
||||
qc->flags |= ATA_QCFLAG_RTF_FILLED;
|
||||
}
|
||||
|
||||
static void ata_verify_xfer(struct ata_queued_cmd *qc)
|
||||
@ -5455,6 +5463,7 @@ int sata_link_init_spd(struct ata_link *link)
|
||||
struct ata_port *ata_port_alloc(struct ata_host *host)
|
||||
{
|
||||
struct ata_port *ap;
|
||||
int id;
|
||||
|
||||
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
|
||||
if (!ap)
|
||||
@ -5462,8 +5471,12 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
|
||||
|
||||
ap->pflags |= ATA_PFLAG_INITIALIZING | ATA_PFLAG_FROZEN;
|
||||
ap->lock = &host->lock;
|
||||
ap->print_id = -1;
|
||||
ap->local_port_no = -1;
|
||||
id = ida_alloc_min(&ata_ida, 1, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
kfree(ap);
|
||||
return NULL;
|
||||
}
|
||||
ap->print_id = id;
|
||||
ap->host = host;
|
||||
ap->dev = host->dev;
|
||||
|
||||
@ -5488,6 +5501,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
|
||||
|
||||
return ap;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_port_alloc);
|
||||
|
||||
void ata_port_free(struct ata_port *ap)
|
||||
{
|
||||
@ -5497,6 +5511,7 @@ void ata_port_free(struct ata_port *ap)
|
||||
kfree(ap->pmp_link);
|
||||
kfree(ap->slave_link);
|
||||
kfree(ap->ncq_sense_buf);
|
||||
ida_free(&ata_ida, ap->print_id);
|
||||
kfree(ap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_port_free);
|
||||
@ -5547,24 +5562,19 @@ EXPORT_SYMBOL_GPL(ata_host_put);
|
||||
/**
|
||||
* ata_host_alloc - allocate and init basic ATA host resources
|
||||
* @dev: generic device this host is associated with
|
||||
* @max_ports: maximum number of ATA ports associated with this host
|
||||
* @n_ports: the number of ATA ports associated with this host
|
||||
*
|
||||
* Allocate and initialize basic ATA host resources. LLD calls
|
||||
* this function to allocate a host, initializes it fully and
|
||||
* attaches it using ata_host_register().
|
||||
*
|
||||
* @max_ports ports are allocated and host->n_ports is
|
||||
* initialized to @max_ports. The caller is allowed to decrease
|
||||
* host->n_ports before calling ata_host_register(). The unused
|
||||
* ports will be automatically freed on registration.
|
||||
*
|
||||
* RETURNS:
|
||||
* Allocate ATA host on success, NULL on failure.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from calling layer (may sleep).
|
||||
*/
|
||||
struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
|
||||
struct ata_host *ata_host_alloc(struct device *dev, int n_ports)
|
||||
{
|
||||
struct ata_host *host;
|
||||
size_t sz;
|
||||
@ -5572,7 +5582,7 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
|
||||
void *dr;
|
||||
|
||||
/* alloc a container for our list of ATA ports (buses) */
|
||||
sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *);
|
||||
sz = sizeof(struct ata_host) + n_ports * sizeof(void *);
|
||||
host = kzalloc(sz, GFP_KERNEL);
|
||||
if (!host)
|
||||
return NULL;
|
||||
@ -5592,11 +5602,11 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
|
||||
spin_lock_init(&host->lock);
|
||||
mutex_init(&host->eh_mutex);
|
||||
host->dev = dev;
|
||||
host->n_ports = max_ports;
|
||||
host->n_ports = n_ports;
|
||||
kref_init(&host->kref);
|
||||
|
||||
/* allocate ports bound to this host */
|
||||
for (i = 0; i < max_ports; i++) {
|
||||
for (i = 0; i < n_ports; i++) {
|
||||
struct ata_port *ap;
|
||||
|
||||
ap = ata_port_alloc(host);
|
||||
@ -5905,19 +5915,6 @@ int ata_host_register(struct ata_host *host, const struct scsi_host_template *sh
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Blow away unused ports. This happens when LLD can't
|
||||
* determine the exact number of ports to allocate at
|
||||
* allocation time.
|
||||
*/
|
||||
for (i = host->n_ports; host->ports[i]; i++)
|
||||
ata_port_free(host->ports[i]);
|
||||
|
||||
/* give ports names and add SCSI hosts */
|
||||
for (i = 0; i < host->n_ports; i++) {
|
||||
host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
|
||||
host->ports[i]->local_port_no = i + 1;
|
||||
}
|
||||
|
||||
/* Create associated sysfs transport objects */
|
||||
for (i = 0; i < host->n_ports; i++) {
|
||||
rc = ata_tport_add(host->dev,host->ports[i]);
|
||||
|
@ -1204,55 +1204,6 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
|
||||
|
||||
/**
|
||||
* ata_sas_port_alloc - Allocate port for a SAS attached SATA device
|
||||
* @host: ATA host container for all SAS ports
|
||||
* @port_info: Information from low-level host driver
|
||||
* @shost: SCSI host that the scsi device is attached to
|
||||
*
|
||||
* LOCKING:
|
||||
* PCI/etc. bus probe sem.
|
||||
*
|
||||
* RETURNS:
|
||||
* ata_port pointer on success / NULL on failure.
|
||||
*/
|
||||
|
||||
struct ata_port *ata_sas_port_alloc(struct ata_host *host,
|
||||
struct ata_port_info *port_info,
|
||||
struct Scsi_Host *shost)
|
||||
{
|
||||
struct ata_port *ap;
|
||||
|
||||
ap = ata_port_alloc(host);
|
||||
if (!ap)
|
||||
return NULL;
|
||||
|
||||
ap->port_no = 0;
|
||||
ap->lock = &host->lock;
|
||||
ap->pio_mask = port_info->pio_mask;
|
||||
ap->mwdma_mask = port_info->mwdma_mask;
|
||||
ap->udma_mask = port_info->udma_mask;
|
||||
ap->flags |= port_info->flags;
|
||||
ap->ops = port_info->port_ops;
|
||||
ap->cbl = ATA_CBL_SATA;
|
||||
ap->print_id = atomic_inc_return(&ata_print_id);
|
||||
|
||||
return ap;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
|
||||
|
||||
int ata_sas_tport_add(struct device *parent, struct ata_port *ap)
|
||||
{
|
||||
return ata_tport_add(parent, ap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_sas_tport_add);
|
||||
|
||||
void ata_sas_tport_delete(struct ata_port *ap)
|
||||
{
|
||||
ata_tport_delete(ap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_sas_tport_delete);
|
||||
|
||||
/**
|
||||
* ata_sas_device_configure - Default device_configure routine for libata
|
||||
* devices
|
||||
|
@ -230,6 +230,87 @@ void ata_scsi_set_sense_information(struct ata_device *dev,
|
||||
SCSI_SENSE_BUFFERSIZE, information);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scsi_set_passthru_sense_fields - Set ATA fields in sense buffer
|
||||
* @qc: ATA PASS-THROUGH command.
|
||||
*
|
||||
* Populates "ATA Status Return sense data descriptor" / "Fixed format
|
||||
* sense data" with ATA taskfile fields.
|
||||
*
|
||||
* LOCKING:
|
||||
* None.
|
||||
*/
|
||||
static void ata_scsi_set_passthru_sense_fields(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_device *dev = qc->dev;
|
||||
struct scsi_cmnd *cmd = qc->scsicmd;
|
||||
struct ata_taskfile *tf = &qc->result_tf;
|
||||
unsigned char *sb = cmd->sense_buffer;
|
||||
|
||||
if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) {
|
||||
ata_dev_dbg(dev,
|
||||
"missing result TF: can't set ATA PT sense fields\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sb[0] & 0x7f) >= 0x72) {
|
||||
unsigned char *desc;
|
||||
u8 len;
|
||||
|
||||
/* descriptor format */
|
||||
len = sb[7];
|
||||
desc = (char *)scsi_sense_desc_find(sb, len + 8, 9);
|
||||
if (!desc) {
|
||||
if (SCSI_SENSE_BUFFERSIZE < len + 14)
|
||||
return;
|
||||
sb[7] = len + 14;
|
||||
desc = sb + 8 + len;
|
||||
}
|
||||
desc[0] = 9;
|
||||
desc[1] = 12;
|
||||
/*
|
||||
* Copy registers into sense buffer.
|
||||
*/
|
||||
desc[2] = 0x00;
|
||||
desc[3] = tf->error;
|
||||
desc[5] = tf->nsect;
|
||||
desc[7] = tf->lbal;
|
||||
desc[9] = tf->lbam;
|
||||
desc[11] = tf->lbah;
|
||||
desc[12] = tf->device;
|
||||
desc[13] = tf->status;
|
||||
|
||||
/*
|
||||
* Fill in Extend bit, and the high order bytes
|
||||
* if applicable.
|
||||
*/
|
||||
if (tf->flags & ATA_TFLAG_LBA48) {
|
||||
desc[2] |= 0x01;
|
||||
desc[4] = tf->hob_nsect;
|
||||
desc[6] = tf->hob_lbal;
|
||||
desc[8] = tf->hob_lbam;
|
||||
desc[10] = tf->hob_lbah;
|
||||
}
|
||||
} else {
|
||||
/* Fixed sense format */
|
||||
sb[0] |= 0x80;
|
||||
sb[3] = tf->error;
|
||||
sb[4] = tf->status;
|
||||
sb[5] = tf->device;
|
||||
sb[6] = tf->nsect;
|
||||
if (tf->flags & ATA_TFLAG_LBA48) {
|
||||
sb[8] |= 0x80;
|
||||
if (tf->hob_nsect)
|
||||
sb[8] |= 0x40;
|
||||
if (tf->hob_lbal || tf->hob_lbam || tf->hob_lbah)
|
||||
sb[8] |= 0x20;
|
||||
}
|
||||
sb[9] = tf->lbal;
|
||||
sb[10] = tf->lbam;
|
||||
sb[11] = tf->lbah;
|
||||
}
|
||||
}
|
||||
|
||||
static void ata_scsi_set_invalid_field(struct ata_device *dev,
|
||||
struct scsi_cmnd *cmd, u16 field, u8 bit)
|
||||
{
|
||||
@ -711,7 +792,6 @@ static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc)
|
||||
|
||||
/**
|
||||
* ata_to_sense_error - convert ATA error to SCSI error
|
||||
* @id: ATA device number
|
||||
* @drv_stat: value contained in ATA status register
|
||||
* @drv_err: value contained in ATA error register
|
||||
* @sk: the sense key we'll fill out
|
||||
@ -725,8 +805,8 @@ static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc)
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host lock)
|
||||
*/
|
||||
static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
|
||||
u8 *asc, u8 *ascq)
|
||||
static void ata_to_sense_error(u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
|
||||
u8 *ascq)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -837,10 +917,8 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
|
||||
* ata_gen_passthru_sense - Generate check condition sense block.
|
||||
* @qc: Command that completed.
|
||||
*
|
||||
* This function is specific to the ATA descriptor format sense
|
||||
* block specified for the ATA pass through commands. Regardless
|
||||
* of whether the command errored or not, return a sense
|
||||
* block. Copy all controller registers into the sense
|
||||
* This function is specific to the ATA pass through commands.
|
||||
* Regardless of whether the command errored or not, return a sense
|
||||
* block. If there was no error, we get the request from an ATA
|
||||
* passthrough command, so we use the following sense data:
|
||||
* sk = RECOVERED ERROR
|
||||
@ -852,13 +930,16 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
|
||||
*/
|
||||
static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_device *dev = qc->dev;
|
||||
struct scsi_cmnd *cmd = qc->scsicmd;
|
||||
struct ata_taskfile *tf = &qc->result_tf;
|
||||
unsigned char *sb = cmd->sense_buffer;
|
||||
unsigned char *desc = sb + 8;
|
||||
u8 sense_key, asc, ascq;
|
||||
|
||||
memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) {
|
||||
ata_dev_dbg(dev,
|
||||
"missing result TF: can't generate ATA PT sense data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use ata_to_sense_error() to map status register bits
|
||||
@ -866,71 +947,12 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc)
|
||||
*/
|
||||
if (qc->err_mask ||
|
||||
tf->status & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
|
||||
ata_to_sense_error(qc->ap->print_id, tf->status, tf->error,
|
||||
ata_to_sense_error(tf->status, tf->error,
|
||||
&sense_key, &asc, &ascq);
|
||||
ata_scsi_set_sense(qc->dev, cmd, sense_key, asc, ascq);
|
||||
} else {
|
||||
/*
|
||||
* ATA PASS-THROUGH INFORMATION AVAILABLE
|
||||
* Always in descriptor format sense.
|
||||
*/
|
||||
scsi_build_sense(cmd, 1, RECOVERED_ERROR, 0, 0x1D);
|
||||
}
|
||||
|
||||
if ((cmd->sense_buffer[0] & 0x7f) >= 0x72) {
|
||||
u8 len;
|
||||
|
||||
/* descriptor format */
|
||||
len = sb[7];
|
||||
desc = (char *)scsi_sense_desc_find(sb, len + 8, 9);
|
||||
if (!desc) {
|
||||
if (SCSI_SENSE_BUFFERSIZE < len + 14)
|
||||
return;
|
||||
sb[7] = len + 14;
|
||||
desc = sb + 8 + len;
|
||||
}
|
||||
desc[0] = 9;
|
||||
desc[1] = 12;
|
||||
/*
|
||||
* Copy registers into sense buffer.
|
||||
*/
|
||||
desc[2] = 0x00;
|
||||
desc[3] = tf->error;
|
||||
desc[5] = tf->nsect;
|
||||
desc[7] = tf->lbal;
|
||||
desc[9] = tf->lbam;
|
||||
desc[11] = tf->lbah;
|
||||
desc[12] = tf->device;
|
||||
desc[13] = tf->status;
|
||||
|
||||
/*
|
||||
* Fill in Extend bit, and the high order bytes
|
||||
* if applicable.
|
||||
*/
|
||||
if (tf->flags & ATA_TFLAG_LBA48) {
|
||||
desc[2] |= 0x01;
|
||||
desc[4] = tf->hob_nsect;
|
||||
desc[6] = tf->hob_lbal;
|
||||
desc[8] = tf->hob_lbam;
|
||||
desc[10] = tf->hob_lbah;
|
||||
}
|
||||
} else {
|
||||
/* Fixed sense format */
|
||||
desc[0] = tf->error;
|
||||
desc[1] = tf->status;
|
||||
desc[2] = tf->device;
|
||||
desc[3] = tf->nsect;
|
||||
desc[7] = 0;
|
||||
if (tf->flags & ATA_TFLAG_LBA48) {
|
||||
desc[8] |= 0x80;
|
||||
if (tf->hob_nsect)
|
||||
desc[8] |= 0x40;
|
||||
if (tf->hob_lbal || tf->hob_lbam || tf->hob_lbah)
|
||||
desc[8] |= 0x20;
|
||||
}
|
||||
desc[9] = tf->lbal;
|
||||
desc[10] = tf->lbam;
|
||||
desc[11] = tf->lbah;
|
||||
/* ATA PASS-THROUGH INFORMATION AVAILABLE */
|
||||
ata_scsi_set_sense(qc->dev, cmd, RECOVERED_ERROR, 0, 0x1D);
|
||||
}
|
||||
}
|
||||
|
||||
@ -953,20 +975,25 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc)
|
||||
u64 block;
|
||||
u8 sense_key, asc, ascq;
|
||||
|
||||
memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
|
||||
|
||||
if (ata_dev_disabled(dev)) {
|
||||
/* Device disabled after error recovery */
|
||||
/* LOGICAL UNIT NOT READY, HARD RESET REQUIRED */
|
||||
ata_scsi_set_sense(dev, cmd, NOT_READY, 0x04, 0x21);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(qc->flags & ATA_QCFLAG_RTF_FILLED)) {
|
||||
ata_dev_dbg(dev,
|
||||
"missing result TF: can't generate sense data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use ata_to_sense_error() to map status register bits
|
||||
* onto sense key, asc & ascq.
|
||||
*/
|
||||
if (qc->err_mask ||
|
||||
tf->status & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
|
||||
ata_to_sense_error(qc->ap->print_id, tf->status, tf->error,
|
||||
ata_to_sense_error(tf->status, tf->error,
|
||||
&sense_key, &asc, &ascq);
|
||||
ata_scsi_set_sense(dev, cmd, sense_key, asc, ascq);
|
||||
} else {
|
||||
@ -1631,26 +1658,32 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct scsi_cmnd *cmd = qc->scsicmd;
|
||||
u8 *cdb = cmd->cmnd;
|
||||
int need_sense = (qc->err_mask != 0) &&
|
||||
!(qc->flags & ATA_QCFLAG_SENSE_VALID);
|
||||
bool have_sense = qc->flags & ATA_QCFLAG_SENSE_VALID;
|
||||
bool is_ata_passthru = cdb[0] == ATA_16 || cdb[0] == ATA_12;
|
||||
bool is_ck_cond_request = cdb[2] & 0x20;
|
||||
bool is_error = qc->err_mask != 0;
|
||||
|
||||
/* For ATA pass thru (SAT) commands, generate a sense block if
|
||||
* user mandated it or if there's an error. Note that if we
|
||||
* generate because the user forced us to [CK_COND =1], a check
|
||||
* generate because the user forced us to [CK_COND=1], a check
|
||||
* condition is generated and the ATA register values are returned
|
||||
* whether the command completed successfully or not. If there
|
||||
* was no error, we use the following sense data:
|
||||
* was no error, and CK_COND=1, we use the following sense data:
|
||||
* sk = RECOVERED ERROR
|
||||
* asc,ascq = ATA PASS-THROUGH INFORMATION AVAILABLE
|
||||
*/
|
||||
if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
|
||||
((cdb[2] & 0x20) || need_sense))
|
||||
ata_gen_passthru_sense(qc);
|
||||
else if (need_sense)
|
||||
if (is_ata_passthru && (is_ck_cond_request || is_error || have_sense)) {
|
||||
if (!have_sense)
|
||||
ata_gen_passthru_sense(qc);
|
||||
ata_scsi_set_passthru_sense_fields(qc);
|
||||
if (is_ck_cond_request)
|
||||
set_status_byte(qc->scsicmd, SAM_STAT_CHECK_CONDITION);
|
||||
} else if (is_error && !have_sense) {
|
||||
ata_gen_ata_sense(qc);
|
||||
else
|
||||
} else {
|
||||
/* Keep the SCSI ML and status byte, clear host byte. */
|
||||
cmd->result &= 0x0000ffff;
|
||||
}
|
||||
|
||||
ata_qc_done(qc);
|
||||
}
|
||||
@ -2589,14 +2622,8 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
|
||||
/* handle completion from EH */
|
||||
if (unlikely(err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID)) {
|
||||
|
||||
if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
|
||||
/* FIXME: not quite right; we don't want the
|
||||
* translation of taskfile registers into a
|
||||
* sense descriptors, since that's only
|
||||
* correct for ATA, not ATAPI
|
||||
*/
|
||||
if (!(qc->flags & ATA_QCFLAG_SENSE_VALID))
|
||||
ata_gen_passthru_sense(qc);
|
||||
}
|
||||
|
||||
/* SCSI EH automatically locks door if sdev->locked is
|
||||
* set. Sometimes door lock request continues to
|
||||
|
@ -217,7 +217,8 @@ static DEVICE_ATTR(name, S_IRUGO, show_ata_port_##name, NULL)
|
||||
|
||||
ata_port_simple_attr(nr_pmp_links, nr_pmp_links, "%d\n", int);
|
||||
ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long);
|
||||
ata_port_simple_attr(local_port_no, port_no, "%u\n", unsigned int);
|
||||
/* We want the port_no sysfs attibute to start at 1 (ap->port_no starts at 0) */
|
||||
ata_port_simple_attr(port_no + 1, port_no, "%u\n", unsigned int);
|
||||
|
||||
static DECLARE_TRANSPORT_CLASS(ata_port_class,
|
||||
"ata_port", NULL, NULL, NULL);
|
||||
@ -265,6 +266,7 @@ void ata_tport_delete(struct ata_port *ap)
|
||||
transport_destroy_device(dev);
|
||||
put_device(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_tport_delete);
|
||||
|
||||
static const struct device_type ata_port_sas_type = {
|
||||
.name = ATA_PORT_TYPE_NAME,
|
||||
@ -329,6 +331,7 @@ int ata_tport_add(struct device *parent,
|
||||
put_device(dev);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_tport_add);
|
||||
|
||||
/**
|
||||
* ata_port_classify - determine device type based on ATA-spec signature
|
||||
|
@ -8,9 +8,6 @@ extern struct scsi_transport_template *ata_scsi_transport_template;
|
||||
int ata_tlink_add(struct ata_link *link);
|
||||
void ata_tlink_delete(struct ata_link *link);
|
||||
|
||||
int ata_tport_add(struct device *parent, struct ata_port *ap);
|
||||
void ata_tport_delete(struct ata_port *ap);
|
||||
|
||||
struct scsi_transport_template *ata_attach_transport(void);
|
||||
void ata_release_transport(struct scsi_transport_template *t);
|
||||
|
||||
|
@ -32,7 +32,6 @@ enum {
|
||||
|
||||
#define ATA_PORT_TYPE_NAME "ata_port"
|
||||
|
||||
extern atomic_t ata_print_id;
|
||||
extern int atapi_passthru16;
|
||||
extern int libata_fua;
|
||||
extern int libata_noacpi;
|
||||
@ -82,7 +81,6 @@ extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
|
||||
extern int sata_link_init_spd(struct ata_link *link);
|
||||
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
|
||||
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
|
||||
extern struct ata_port *ata_port_alloc(struct ata_host *host);
|
||||
extern const char *sata_spd_string(unsigned int spd);
|
||||
extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
|
||||
u8 page, void *buf, unsigned int sectors);
|
||||
|
@ -572,15 +572,6 @@ static struct ata_port_operations sas_sata_ops = {
|
||||
.end_eh = sas_ata_end_eh,
|
||||
};
|
||||
|
||||
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_FPDMA_AUX,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &sas_sata_ops
|
||||
};
|
||||
|
||||
int sas_ata_init(struct domain_device *found_dev)
|
||||
{
|
||||
struct sas_ha_struct *ha = found_dev->port->ha;
|
||||
@ -597,18 +588,25 @@ int sas_ata_init(struct domain_device *found_dev)
|
||||
|
||||
ata_host_init(ata_host, ha->dev, &sas_sata_ops);
|
||||
|
||||
ap = ata_sas_port_alloc(ata_host, &sata_port_info, shost);
|
||||
ap = ata_port_alloc(ata_host);
|
||||
if (!ap) {
|
||||
pr_err("ata_sas_port_alloc failed.\n");
|
||||
pr_err("ata_port_alloc failed.\n");
|
||||
rc = -ENODEV;
|
||||
goto free_host;
|
||||
}
|
||||
|
||||
ap->port_no = 0;
|
||||
ap->pio_mask = ATA_PIO4;
|
||||
ap->mwdma_mask = ATA_MWDMA2;
|
||||
ap->udma_mask = ATA_UDMA6;
|
||||
ap->flags |= ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ |
|
||||
ATA_FLAG_SAS_HOST | ATA_FLAG_FPDMA_AUX;
|
||||
ap->ops = &sas_sata_ops;
|
||||
ap->private_data = found_dev;
|
||||
ap->cbl = ATA_CBL_SATA;
|
||||
ap->scsi_host = shost;
|
||||
|
||||
rc = ata_sas_tport_add(ata_host->dev, ap);
|
||||
rc = ata_tport_add(ata_host->dev, ap);
|
||||
if (rc)
|
||||
goto free_port;
|
||||
|
||||
|
@ -300,7 +300,7 @@ void sas_free_device(struct kref *kref)
|
||||
kfree(dev->ex_dev.ex_phy);
|
||||
|
||||
if (dev_is_sata(dev) && dev->sata_dev.ap) {
|
||||
ata_sas_tport_delete(dev->sata_dev.ap);
|
||||
ata_tport_delete(dev->sata_dev.ap);
|
||||
ata_port_free(dev->sata_dev.ap);
|
||||
ata_host_put(dev->sata_dev.ata_host);
|
||||
dev->sata_dev.ata_host = NULL;
|
||||
|
@ -814,7 +814,6 @@ struct ata_port {
|
||||
/* Flags that change dynamically, protected by ap->lock */
|
||||
unsigned int pflags; /* ATA_PFLAG_xxx */
|
||||
unsigned int print_id; /* user visible unique port ID */
|
||||
unsigned int local_port_no; /* host local port num */
|
||||
unsigned int port_no; /* 0 based port no. inside the host */
|
||||
|
||||
#ifdef CONFIG_ATA_SFF
|
||||
@ -1069,7 +1068,7 @@ extern int sata_std_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline);
|
||||
extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
|
||||
|
||||
extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
|
||||
extern struct ata_host *ata_host_alloc(struct device *dev, int n_ports);
|
||||
extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
|
||||
const struct ata_port_info * const * ppi, int n_ports);
|
||||
extern void ata_host_get(struct ata_host *host);
|
||||
@ -1082,7 +1081,6 @@ extern int ata_host_activate(struct ata_host *host, int irq,
|
||||
const struct scsi_host_template *sht);
|
||||
extern void ata_host_detach(struct ata_host *host);
|
||||
extern void ata_host_init(struct ata_host *, struct device *, struct ata_port_operations *);
|
||||
extern int ata_scsi_detect(struct scsi_host_template *sht);
|
||||
extern int ata_scsi_ioctl(struct scsi_device *dev, unsigned int cmd,
|
||||
void __user *arg);
|
||||
#ifdef CONFIG_COMPAT
|
||||
@ -1246,12 +1244,11 @@ extern int sata_link_debounce(struct ata_link *link,
|
||||
extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
|
||||
bool spm_wakeup);
|
||||
extern int ata_slave_link_init(struct ata_port *ap);
|
||||
extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
|
||||
struct ata_port_info *, struct Scsi_Host *);
|
||||
extern void ata_port_probe(struct ata_port *ap);
|
||||
extern struct ata_port *ata_port_alloc(struct ata_host *host);
|
||||
extern void ata_port_free(struct ata_port *ap);
|
||||
extern int ata_sas_tport_add(struct device *parent, struct ata_port *ap);
|
||||
extern void ata_sas_tport_delete(struct ata_port *ap);
|
||||
extern int ata_tport_add(struct device *parent, struct ata_port *ap);
|
||||
extern void ata_tport_delete(struct ata_port *ap);
|
||||
int ata_sas_device_configure(struct scsi_device *sdev, struct queue_limits *lim,
|
||||
struct ata_port *ap);
|
||||
extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap);
|
||||
|
Loading…
Reference in New Issue
Block a user