#include <scsi/scsi_transport.h>
#include <linux/libata.h>
#include <linux/hdreg.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "libata.h"
typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);
-static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev);
-static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
+static struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev);
static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun);
#define ALL_SUB_MPAGES 0xff
-static const u8 def_rw_recovery_mpage[] = {
+static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
RW_RECOVERY_MPAGE,
RW_RECOVERY_MPAGE_LEN - 2,
- (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */
- (1 << 6), /* ARRE (auto read reallocation) */
+ (1 << 7), /* AWRE */
0, /* read retry count */
0, 0, 0, 0,
0, /* write retry count */
};
+static const struct {
+ enum link_pm value;
+ const char *name;
+} link_pm_policy[] = {
+ { NOT_AVAILABLE, "max_performance" },
+ { MIN_POWER, "min_power" },
+ { MAX_PERFORMANCE, "max_performance" },
+ { MEDIUM_POWER, "medium_power" },
+};
+
+static const char *ata_scsi_lpm_get(enum link_pm policy)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++)
+ if (link_pm_policy[i].value == policy)
+ return link_pm_policy[i].name;
+
+ return NULL;
+}
+
+static ssize_t ata_scsi_lpm_put(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ enum link_pm policy = 0;
+ int i;
+
+ /*
+ * we are skipping array location 0 on purpose - this
+ * is because a value of NOT_AVAILABLE is displayed
+ * to the user as max_performance, but when the user
+ * writes "max_performance", they actually want the
+ * value to match MAX_PERFORMANCE.
+ */
+ for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) {
+ const int len = strlen(link_pm_policy[i].name);
+ if (strncmp(link_pm_policy[i].name, buf, len) == 0 &&
+ buf[len] == '\n') {
+ policy = link_pm_policy[i].value;
+ break;
+ }
+ }
+ if (!policy)
+ return -EINVAL;
+
+ ata_lpm_schedule(ap, policy);
+ return count;
+}
+
+static ssize_t
+ata_scsi_lpm_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ const char *policy =
+ ata_scsi_lpm_get(ap->pm_policy);
+
+ if (!policy)
+ return -EINVAL;
+
+ return snprintf(buf, 23, "%s\n", policy);
+}
+DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
+ ata_scsi_lpm_show, ata_scsi_lpm_put);
+EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
+
+static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+{
+ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
+}
+
static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
scsi_cmd[1] = (4 << 1); /* PIO Data-in */
scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev,
- block count in sector count field */
+ block count in sector count field */
data_dir = DMA_FROM_DEVICE;
} else {
scsi_cmd[1] = (3 << 1); /* Non-data */
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command() for default case... */
cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
- sensebuf, (10*HZ), 5, 0);
+ sensebuf, (10*HZ), 5, 0);
if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
u8 *desc = sensebuf + 8;
if (cmd_result & SAM_STAT_CHECK_CONDITION) {
struct scsi_sense_hdr sshdr;
scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
- &sshdr);
- if (sshdr.sense_key==0 &&
- sshdr.asc==0 && sshdr.ascq==0)
+ &sshdr);
+ if (sshdr.sense_key == 0 &&
+ sshdr.asc == 0 && sshdr.ascq == 0)
cmd_result &= ~SAM_STAT_CHECK_CONDITION;
}
/* Send userspace a few ATA registers (same as drivers/ide) */
- if (sensebuf[0] == 0x72 && /* format is "descriptor" */
- desc[0] == 0x09 ) { /* code is "ATA Descriptor" */
- args[0] = desc[13]; /* status */
- args[1] = desc[3]; /* error */
- args[2] = desc[5]; /* sector count (0:7) */
+ if (sensebuf[0] == 0x72 && /* format is "descriptor" */
+ desc[0] == 0x09) { /* code is "ATA Descriptor" */
+ args[0] = desc[13]; /* status */
+ args[1] = desc[3]; /* error */
+ args[2] = desc[5]; /* sector count (0:7) */
if (copy_to_user(arg, args, sizeof(args)))
rc = -EFAULT;
}
struct scsi_sense_hdr sshdr;
scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
&sshdr);
- if (sshdr.sense_key==0 &&
- sshdr.asc==0 && sshdr.ascq==0)
+ if (sshdr.sense_key == 0 &&
+ sshdr.asc == 0 && sshdr.ascq == 0)
cmd_result &= ~SAM_STAT_CHECK_CONDITION;
}
qc->scsicmd = cmd;
qc->scsidone = done;
- qc->__sg = (struct scatterlist *) cmd->request_buffer;
- qc->n_elem = cmd->use_sg;
+ qc->sg = scsi_sglist(cmd);
+ qc->n_elem = scsi_sg_count(cmd);
} else {
cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
done(cmd);
return qc;
}
+static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+
+ qc->extrabytes = scmd->request->extra_len;
+ qc->nbytes = scsi_bufflen(scmd) + qc->extrabytes;
+}
+
/**
* ata_dump_status - user friendly display of error info
* @id: id of the port in question
{
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
+
+ /* Schedule policy is determined by ->qc_defer() callback and
+ * it needs to see every deferred qc. Set dev_blocked to 1 to
+ * prevent SCSI midlayer from automatically deferring
+ * requests.
+ */
+ sdev->max_device_blocked = 1;
+}
+
+/**
+ * atapi_drain_needed - Check whether data transfer may overflow
+ * @rq: request to be checked
+ *
+ * ATAPI commands which transfer variable length data to host
+ * might overflow due to application error or hardare bug. This
+ * function checks whether overflow should be drained and ignored
+ * for @request.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if ; otherwise, 0.
+ */
+static int atapi_drain_needed(struct request *rq)
+{
+ if (likely(!blk_pc_request(rq)))
+ return 0;
+
+ if (!rq->data_len || (rq->cmd_flags & REQ_RW))
+ return 0;
+
+ return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC;
}
-static void ata_scsi_dev_config(struct scsi_device *sdev,
- struct ata_device *dev)
+static int ata_scsi_dev_config(struct scsi_device *sdev,
+ struct ata_device *dev)
{
/* configure max sectors */
blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);
- /* SATA DMA transfers must be multiples of 4 byte, so
- * we need to pad ATAPI transfers using an extra sg.
- * Decrement max hw segments accordingly.
- */
if (dev->class == ATA_DEV_ATAPI) {
struct request_queue *q = sdev->request_queue;
- blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
+ void *buf;
+
+ /* set the min alignment and padding */
+ blk_queue_update_dma_alignment(sdev->request_queue,
+ ATA_DMA_PAD_SZ - 1);
+ blk_queue_dma_pad(sdev->request_queue, ATA_DMA_PAD_SZ - 1);
+
+ /* configure draining */
+ buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL);
+ if (!buf) {
+ ata_dev_printk(dev, KERN_ERR,
+ "drain buffer allocation failed\n");
+ return -ENOMEM;
+ }
+
+ blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
+ } else {
+ /* ATA devices must be sector aligned */
+ blk_queue_update_dma_alignment(sdev->request_queue,
+ ATA_SECT_SIZE - 1);
+ sdev->manage_start_stop = 1;
}
+ if (dev->flags & ATA_DFLAG_AN)
+ set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
+
if (dev->flags & ATA_DFLAG_NCQ) {
int depth;
depth = min(ATA_MAX_QUEUE - 1, depth);
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
}
+
+ return 0;
}
/**
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+ int rc = 0;
ata_scsi_sdev_config(sdev);
- blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
-
- sdev->manage_start_stop = 1;
-
if (dev)
- ata_scsi_dev_config(sdev, dev);
+ rc = ata_scsi_dev_config(sdev, dev);
- return 0; /* scsi layer doesn't check return value, sigh */
+ return rc;
}
/**
void ata_scsi_slave_destroy(struct scsi_device *sdev)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct request_queue *q = sdev->request_queue;
unsigned long flags;
struct ata_device *dev;
ata_port_schedule_eh(ap);
}
spin_unlock_irqrestore(ap->lock, flags);
+
+ kfree(q->dma_drain_buffer);
+ q->dma_drain_buffer = NULL;
+ q->dma_drain_size = 0;
}
/**
goto invalid_fld; /* LOEJ bit set not supported */
if (((cdb[4] >> 4) & 0xf) != 0)
goto invalid_fld; /* power conditions not supported */
+
+ if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) {
+ /* the device lacks PM support, finish without doing anything */
+ scmd->result = SAM_STAT_GOOD;
+ return 1;
+ }
+
if (cdb[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
if ((qc->dev->flags & ATA_DFLAG_SPUNDOWN) &&
(system_state == SYSTEM_HALT ||
system_state == SYSTEM_POWER_OFF)) {
- static unsigned long warned = 0;
+ static unsigned long warned;
if (!test_and_set_bit(0, &warned)) {
ata_dev_printk(qc->dev, KERN_WARNING,
else
tf->command = ATA_CMD_FLUSH;
+ /* flush is critical for IO integrity, consider it an IO command */
+ qc->flags |= ATA_QCFLAG_IO;
+
return 0;
}
struct ata_port *ap = qc->ap;
struct scsi_cmnd *cmd = qc->scsicmd;
u8 *cdb = cmd->cmnd;
- int need_sense = (qc->err_mask != 0);
-
- /* We snoop the SET_FEATURES - Write Cache ON/OFF command, and
- * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
- * cache
- */
- if (ap->ops->error_handler && !need_sense) {
- switch (qc->tf.command) {
- case ATA_CMD_SET_FEATURES:
- if ((qc->tf.feature == SETFEATURES_WC_ON) ||
- (qc->tf.feature == SETFEATURES_WC_OFF)) {
- ap->link.eh_info.action |= ATA_EH_REVALIDATE;
- ata_port_schedule_eh(ap);
- }
- break;
-
- case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
- case ATA_CMD_SET_MULTI: /* multi_count changed */
- ap->link.eh_info.action |= ATA_EH_REVALIDATE;
- ata_port_schedule_eh(ap);
- break;
- }
- }
+ int need_sense = (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
* was no error, SK, ASC and ASCQ will all be zero.
*/
if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
- ((cdb[2] & 0x20) || need_sense)) {
+ ((cdb[2] & 0x20) || need_sense)) {
ata_gen_passthru_sense(qc);
} else {
if (!need_sense) {
}
/**
- * ata_scmd_need_defer - Check whether we need to defer scmd
- * @dev: ATA device to which the command is addressed
- * @is_io: Is the command IO (and thus possibly NCQ)?
- *
- * NCQ and non-NCQ commands cannot run together. As upper layer
- * only knows the queue depth, we are responsible for maintaining
- * exclusion. This function checks whether a new command can be
- * issued to @dev.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * 1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
- struct ata_link *link = dev->link;
- int is_ncq = is_io && ata_ncq_enabled(dev);
-
- if (is_ncq) {
- if (!ata_tag_valid(link->active_tag))
- return 0;
- } else {
- if (!ata_tag_valid(link->active_tag) && !link->sactive)
- return 0;
- }
- return 1;
-}
-
-/**
* ata_scsi_translate - Translate then issue SCSI command to ATA device
* @dev: ATA device to which the command is addressed
* @cmd: SCSI command to execute
void (*done)(struct scsi_cmnd *),
ata_xlat_func_t xlat_func)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
- int is_io = xlat_func == ata_scsi_rw_xlat;
+ int rc;
VPRINTK("ENTER\n");
- if (unlikely(ata_scmd_need_defer(dev, is_io)))
- goto defer;
-
qc = ata_scsi_qc_new(dev, cmd, done);
if (!qc)
goto err_mem;
/* data is present; dma-map it */
if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
cmd->sc_data_direction == DMA_TO_DEVICE) {
- if (unlikely(cmd->request_bufflen < 1)) {
+ if (unlikely(scsi_bufflen(cmd) < 1)) {
ata_dev_printk(dev, KERN_WARNING,
"WARNING: zero len r/w req\n");
goto err_did;
}
- ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
+ ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd));
qc->dma_dir = cmd->sc_data_direction;
}
if (xlat_func(qc))
goto early_finish;
+ if (ap->ops->qc_defer) {
+ if ((rc = ap->ops->qc_defer(qc)))
+ goto defer;
+ }
+
/* select device, send command to hardware */
ata_qc_issue(qc);
return 0;
early_finish:
- ata_qc_free(qc);
+ ata_qc_free(qc);
qc->scsidone(cmd);
DPRINTK("EXIT - early finish (good or error)\n");
return 0;
return 0;
defer:
+ ata_qc_free(qc);
DPRINTK("EXIT - defer\n");
- return SCSI_MLQUEUE_DEVICE_BUSY;
+ if (rc == ATA_DEFER_LINK)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ else
+ return SCSI_MLQUEUE_HOST_BUSY;
}
/**
u8 *buf;
unsigned int buflen;
- struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer;
+ struct scatterlist *sg = scsi_sglist(cmd);
if (sg) {
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
buflen = sg->length;
} else {
buf = NULL;
static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
{
- struct scatterlist *sg = (struct scatterlist *) cmd->request_buffer;
+ struct scatterlist *sg = scsi_sglist(cmd);
if (sg)
kunmap_atomic(buf - sg->offset, KM_IRQ0);
}
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen))
+static void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+ unsigned int (*actor)(struct ata_scsi_args *args,
+ u8 *rbuf, unsigned int buflen))
{
u8 *rbuf;
unsigned int buflen, rc;
struct scsi_cmnd *cmd = args->cmd;
+ unsigned long flags;
+
+ local_irq_save(flags);
buflen = ata_scsi_rbuf_get(cmd, &rbuf);
memset(rbuf, 0, buflen);
rc = actor(args, rbuf, buflen);
ata_scsi_rbuf_put(cmd, rbuf);
+ local_irq_restore(flags);
+
if (rc == 0)
cmd->result = SAM_STAT_GOOD;
args->done(cmd);
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
{
u8 hdr[] = {
TYPE_DISK,
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
{
const u8 pages[] = {
0x00, /* page 0x00, this page */
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
{
const u8 hdr[] = {
0,
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
{
int num;
const int sat_model_serial_desc_len = 68;
}
/**
+ * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Yields SAT-specified ATA VPD page.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ u8 pbuf[60];
+ struct ata_taskfile tf;
+ unsigned int i;
+
+ if (!buflen)
+ return 0;
+
+ memset(&pbuf, 0, sizeof(pbuf));
+ memset(&tf, 0, sizeof(tf));
+
+ pbuf[1] = 0x89; /* our page code */
+ pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */
+ pbuf[3] = (0x238 & 0xff);
+
+ memcpy(&pbuf[8], "linux ", 8);
+ memcpy(&pbuf[16], "libata ", 16);
+ memcpy(&pbuf[32], DRV_VERSION, 4);
+ ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);
+
+ /* we don't store the ATA device signature, so we fake it */
+
+ tf.command = ATA_DRDY; /* really, this is Status reg */
+ tf.lbal = 0x1;
+ tf.nsect = 0x1;
+
+ ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */
+ pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */
+
+ pbuf[56] = ATA_CMD_ID_ATA;
+
+ i = min(buflen, 60U);
+ memcpy(rbuf, &pbuf[0], i);
+ buflen -= i;
+
+ if (!buflen)
+ return 0;
+
+ memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));
+ return 0;
+}
+
+/**
* ata_scsiop_noop - Command handler that simply returns success.
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
{
VPRINTK("ENTER\n");
return 0;
* None.
*/
unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+ unsigned int buflen)
{
u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */
/* sector size */
ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8);
- ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE);
+ ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff);
} else {
/* sector count, 64-bit */
ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7));
/* sector size */
ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8);
- ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE);
+ ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff);
}
return 0;
return 0;
}
-/**
- * ata_scsi_set_sense - Set SCSI sense data and status
- * @cmd: SCSI request to be handled
- * @sk: SCSI-defined sense key
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that builds a valid fixed format, current
- * response code and the given sense key (sk), additional sense
- * code (asc) and additional sense code qualifier (ascq) with
- * a SCSI command status of %SAM_STAT_CHECK_CONDITION and
- * DRIVER_SENSE set in the upper bits of scsi_cmnd::result .
- *
- * LOCKING:
- * Not required
- */
-
-void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
-{
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
- cmd->sense_buffer[0] = 0x70; /* fixed format, current */
- cmd->sense_buffer[2] = sk;
- cmd->sense_buffer[7] = 18 - 8; /* additional sense length */
- cmd->sense_buffer[12] = asc;
- cmd->sense_buffer[13] = ascq;
-}
-
-/**
- * ata_scsi_badcmd - End a SCSI request with an error
- * @cmd: SCSI request to be handled
- * @done: SCSI command completion function
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that completes a SCSI command with
- * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
- * and the specified additional sense codes.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
-{
- DPRINTK("ENTER\n");
- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);
-
- done(cmd);
-}
-
static void atapi_sense_complete(struct ata_queued_cmd *qc)
{
if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {
DPRINTK("ATAPI request sense\n");
/* FIXME: is this needed? */
- memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- ap->ops->tf_read(ap, &qc->tf);
+#ifdef CONFIG_ATA_SFF
+ if (ap->ops->sff_tf_read)
+ ap->ops->sff_tf_read(ap, &qc->tf);
+#endif
/* fill these in, for the case where they are -not- overwritten */
cmd->sense_buffer[0] = 0x70;
ata_qc_reinit(qc);
- ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
+ /* setup sg table and init transfer direction */
+ sg_init_one(&qc->sgent, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+ ata_sg_init(qc, &qc->sgent, 1);
qc->dma_dir = DMA_FROM_DEVICE;
memset(&qc->cdb, 0, qc->dev->cdb_len);
qc->tf.command = ATA_CMD_PACKET;
if (ata_pio_use_silly(ap)) {
- qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+ qc->tf.protocol = ATAPI_PROT_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
} else {
- qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
+ qc->tf.protocol = ATAPI_PROT_PIO;
+ qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;
+ qc->tf.lbah = 0;
}
qc->nbytes = SCSI_SENSE_BUFFERSIZE;
if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
u8 *buf = NULL;
unsigned int buflen;
+ unsigned long flags;
+
+ local_irq_save(flags);
buflen = ata_scsi_rbuf_get(cmd, &buf);
}
ata_scsi_rbuf_put(cmd, buf);
+
+ local_irq_restore(flags);
}
cmd->result = SAM_STAT_GOOD;
struct ata_device *dev = qc->dev;
int using_pio = (dev->flags & ATA_DFLAG_PIO);
int nodata = (scmd->sc_data_direction == DMA_NONE);
+ unsigned int nbytes;
memset(qc->cdb, 0, dev->cdb_len);
memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len);
}
qc->tf.command = ATA_CMD_PACKET;
- qc->nbytes = scmd->request_bufflen;
+ ata_qc_set_pc_nbytes(qc);
/* check whether ATAPI DMA is safe */
if (!using_pio && ata_check_atapi_dma(qc))
using_pio = 1;
+ /* Some controller variants snoop this value for Packet
+ * transfers to do state machine and FIFO management. Thus we
+ * want to set it properly, and for DMA where it is
+ * effectively meaningless.
+ */
+ nbytes = min(ata_qc_raw_nbytes(qc), (unsigned int)63 * 1024);
+
+ /* Most ATAPI devices which honor transfer chunk size don't
+ * behave according to the spec when odd chunk size which
+ * matches the transfer length is specified. If the number of
+ * bytes to transfer is 2n+1. According to the spec, what
+ * should happen is to indicate that 2n+1 is going to be
+ * transferred and transfer 2n+2 bytes where the last byte is
+ * padding.
+ *
+ * In practice, this doesn't happen. ATAPI devices first
+ * indicate and transfer 2n bytes and then indicate and
+ * transfer 2 bytes where the last byte is padding.
+ *
+ * This inconsistency confuses several controllers which
+ * perform PIO using DMA such as Intel AHCIs and sil3124/32.
+ * These controllers use actual number of transferred bytes to
+ * update DMA poitner and transfer of 4n+2 bytes make those
+ * controller push DMA pointer by 4n+4 bytes because SATA data
+ * FISes are aligned to 4 bytes. This causes data corruption
+ * and buffer overrun.
+ *
+ * Always setting nbytes to even number solves this problem
+ * because then ATAPI devices don't have to split data at 2n
+ * boundaries.
+ */
+ if (nbytes & 0x1)
+ nbytes++;
+
+ qc->tf.lbam = (nbytes & 0xFF);
+ qc->tf.lbah = (nbytes >> 8);
+
if (using_pio || nodata) {
/* no data, or PIO data xfer */
if (nodata)
- qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
+ qc->tf.protocol = ATAPI_PROT_NODATA;
else
- qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
+ qc->tf.protocol = ATAPI_PROT_PIO;
} else {
/* DMA data xfer */
- qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+ qc->tf.protocol = ATAPI_PROT_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
- if (atapi_dmadir && (scmd->sc_data_direction != DMA_TO_DEVICE))
+ if ((dev->flags & ATA_DFLAG_DMADIR) &&
+ (scmd->sc_data_direction != DMA_TO_DEVICE))
/* some SATA bridges need us to indicate data xfer direction */
qc->tf.feature |= ATAPI_DMADIR;
}
+
+ /* FIXME: We need to translate 0x05 READ_BLOCK_LIMITS to a MODE_SENSE
+ as ATAPI tape drives don't get this right otherwise */
return 0;
}
-static struct ata_device * ata_find_dev(struct ata_port *ap, int devno)
+static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
{
- if (ap->nr_pmp_links == 0) {
+ if (!sata_pmp_attached(ap)) {
if (likely(devno < ata_link_max_devices(&ap->link)))
return &ap->link.device[devno];
} else {
return NULL;
}
-static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
- const struct scsi_device *scsidev)
+static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
+ const struct scsi_device *scsidev)
{
int devno;
/* skip commands not addressed to targets we simulate */
- if (ap->nr_pmp_links == 0) {
+ if (!sata_pmp_attached(ap)) {
if (unlikely(scsidev->channel || scsidev->lun))
return NULL;
devno = scsidev->id;
ata_scsi_map_proto(u8 byte1)
{
switch((byte1 & 0x1e) >> 1) {
- case 3: /* Non-data */
- return ATA_PROT_NODATA;
-
- case 6: /* DMA */
- case 10: /* UDMA Data-in */
- case 11: /* UDMA Data-Out */
- return ATA_PROT_DMA;
-
- case 4: /* PIO Data-in */
- case 5: /* PIO Data-out */
- return ATA_PROT_PIO;
-
- case 0: /* Hard Reset */
- case 1: /* SRST */
- case 8: /* Device Diagnostic */
- case 9: /* Device Reset */
- case 7: /* DMA Queued */
- case 12: /* FPDMA */
- case 15: /* Return Response Info */
- default: /* Reserved */
- break;
+ case 3: /* Non-data */
+ return ATA_PROT_NODATA;
+
+ case 6: /* DMA */
+ case 10: /* UDMA Data-in */
+ case 11: /* UDMA Data-Out */
+ return ATA_PROT_DMA;
+
+ case 4: /* PIO Data-in */
+ case 5: /* PIO Data-out */
+ return ATA_PROT_PIO;
+
+ case 0: /* Hard Reset */
+ case 1: /* SRST */
+ case 8: /* Device Diagnostic */
+ case 9: /* Device Reset */
+ case 7: /* DMA Queued */
+ case 12: /* FPDMA */
+ case 15: /* Return Response Info */
+ default: /* Reserved */
+ break;
}
return ATA_PROT_UNKNOWN;
if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN)
goto invalid_fld;
+ /*
+ * Filter TPM commands by default. These provide an
+ * essentially uncontrolled encrypted "back door" between
+ * applications and the disk. Set libata.allow_tpm=1 if you
+ * have a real reason for wanting to use them. This ensures
+ * that installed software cannot easily mess stuff up without
+ * user intent. DVR type users will probably ship with this enabled
+ * for movie content management.
+ *
+ * Note that for ATA8 we can issue a DCS change and DCS freeze lock
+ * for this and should do in future but that it is not sufficient as
+ * DCS is an optional feature set. Thus we also do the software filter
+ * so that we comply with the TC consortium stated goal that the user
+ * can turn off TC features of their system.
+ */
+ if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm)
+ goto invalid_fld;
+
/* We may not issue DMA commands if no DMA mode is set */
if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
goto invalid_fld;
case ATA_CMD_WRITE_LONG_ONCE:
if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
goto invalid_fld;
- qc->sect_size = scmd->request_bufflen;
+ qc->sect_size = scsi_bufflen(scmd);
}
/*
* TODO: find out if we need to do more here to
* cover scatter/gather case.
*/
- qc->nbytes = scmd->request_bufflen;
+ ata_qc_set_pc_nbytes(qc);
- /* request result TF */
- qc->flags |= ATA_QCFLAG_RESULT_TF;
+ /* request result TF and be quiet about device error */
+ qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET;
return 0;
xlat_func = NULL;
if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
/* relay SCSI command to ATAPI device */
- if (unlikely(scmd->cmd_len > dev->cdb_len))
+ int len = COMMAND_SIZE(scsi_op);
+ if (unlikely(len > scmd->cmd_len || len > dev->cdb_len))
goto bad_cdb_len;
xlat_func = atapi_xlat;
{
struct ata_scsi_args args;
const u8 *scsicmd = cmd->cmnd;
+ u8 tmp8;
args.dev = dev;
args.id = dev->id;
args.done = done;
switch(scsicmd[0]) {
- /* no-op's, complete with success */
- case SYNCHRONIZE_CACHE:
- case REZERO_UNIT:
- case SEEK_6:
- case SEEK_10:
- case TEST_UNIT_READY:
- case FORMAT_UNIT: /* FIXME: correct? */
- case SEND_DIAGNOSTIC: /* FIXME: correct? */
- ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
- break;
+ /* TODO: worth improving? */
+ case FORMAT_UNIT:
+ ata_scsi_invalid_field(cmd, done);
+ break;
- case INQUIRY:
- if (scsicmd[1] & 2) /* is CmdDt set? */
- ata_scsi_invalid_field(cmd, done);
- else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
- else if (scsicmd[2] == 0x00)
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
- else if (scsicmd[2] == 0x80)
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
- else if (scsicmd[2] == 0x83)
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
- else
- ata_scsi_invalid_field(cmd, done);
+ case INQUIRY:
+ if (scsicmd[1] & 2) /* is CmdDt set? */
+ ata_scsi_invalid_field(cmd, done);
+ else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
+ else switch (scsicmd[2]) {
+ case 0x00:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
break;
-
- case MODE_SENSE:
- case MODE_SENSE_10:
- ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
+ case 0x80:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
break;
-
- case MODE_SELECT: /* unconditionally return */
- case MODE_SELECT_10: /* bad-field-in-cdb */
+ case 0x83:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
+ break;
+ case 0x89:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
+ break;
+ default:
ata_scsi_invalid_field(cmd, done);
break;
+ }
+ break;
+
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
+ break;
+
+ case MODE_SELECT: /* unconditionally return */
+ case MODE_SELECT_10: /* bad-field-in-cdb */
+ ata_scsi_invalid_field(cmd, done);
+ break;
+
+ case READ_CAPACITY:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+ break;
- case READ_CAPACITY:
+ case SERVICE_ACTION_IN:
+ if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
- break;
+ else
+ ata_scsi_invalid_field(cmd, done);
+ break;
- case SERVICE_ACTION_IN:
- if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
- ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
- else
- ata_scsi_invalid_field(cmd, done);
- break;
+ case REPORT_LUNS:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
+ break;
- case REPORT_LUNS:
- ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
- break;
+ case REQUEST_SENSE:
+ ata_scsi_set_sense(cmd, 0, 0, 0);
+ cmd->result = (DRIVER_SENSE << 24);
+ done(cmd);
+ break;
- /* mandatory commands we haven't implemented yet */
- case REQUEST_SENSE:
+ /* if we reach this, then writeback caching is disabled,
+ * turning this into a no-op.
+ */
+ case SYNCHRONIZE_CACHE:
+ /* fall through */
+
+ /* no-op's, complete with success */
+ case REZERO_UNIT:
+ case SEEK_6:
+ case SEEK_10:
+ case TEST_UNIT_READY:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ break;
- /* all other commands */
- default:
- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
- /* "Invalid command operation code" */
- done(cmd);
- break;
+ case SEND_DIAGNOSTIC:
+ tmp8 = scsicmd[1] & ~(1 << 3);
+ if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
+ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ else
+ ata_scsi_invalid_field(cmd, done);
+ break;
+
+ /* all other commands */
+ default:
+ ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
+ /* "Invalid command operation code" */
+ done(cmd);
+ break;
}
}
shost->max_channel = 1;
shost->max_cmd_len = 16;
+ /* Schedule policy is determined by ->qc_defer()
+ * callback and it needs to see every deferred qc.
+ * Set host_blocked to 1 to prevent SCSI midlayer from
+ * automatically deferring requests.
+ */
+ shost->max_host_blocked = 1;
+
rc = scsi_add_host(ap->scsi_host, ap->host->dev);
if (rc)
goto err_add;
/**
* ata_scsi_media_change_notify - send media change event
- * @atadev: Pointer to the disk device with media change event
+ * @dev: Pointer to the disk device with media change event
*
* Tell the block layer to send a media change notification
* event.
*
* LOCKING:
- * interrupt context, may not sleep.
+ * spin_lock_irqsave(host lock)
*/
-void ata_scsi_media_change_notify(struct ata_device *atadev)
+void ata_scsi_media_change_notify(struct ata_device *dev)
{
-#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED
- scsi_device_event_notify(atadev->sdev, SDEV_MEDIA_CHANGE);
-#endif
+ if (dev->sdev)
+ sdev_evt_send_simple(dev->sdev, SDEV_EVT_MEDIA_CHANGE,
+ GFP_ATOMIC);
}
-EXPORT_SYMBOL_GPL(ata_scsi_media_change_notify);
/**
* ata_scsi_hotplug - SCSI part of hotplug
if (lun != SCAN_WILD_CARD && lun)
return -EINVAL;
- if (ap->nr_pmp_links == 0) {
+ if (!sata_pmp_attached(ap)) {
if (channel != SCAN_WILD_CARD && channel)
return -EINVAL;
devno = id;
ata_port_for_each_link(link, ap) {
struct ata_eh_info *ehi = &link->eh_info;
- ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1;
- ehi->action |= ATA_EH_SOFTRESET;
+ ehi->probe_mask |= ATA_ALL_DEVICES;
+ ehi->action |= ATA_EH_RESET;
}
} else {
struct ata_device *dev = ata_find_dev(ap, devno);
if (dev) {
struct ata_eh_info *ehi = &dev->link->eh_info;
ehi->probe_mask |= 1 << dev->devno;
- ehi->action |= ATA_EH_SOFTRESET;
- ehi->flags |= ATA_EHI_RESUME_LINK;
+ ehi->action |= ATA_EH_RESET;
} else
rc = -EINVAL;
}
* @ap: Port to initialize
*
* Called just after data structures for each port are
- * initialized. Allocates DMA pad.
+ * initialized.
*
* May be used as the port_start() entry in ata_port_operations.
*
*/
int ata_sas_port_start(struct ata_port *ap)
{
- return ata_pad_alloc(ap, ap->dev);
+ return 0;
}
EXPORT_SYMBOL_GPL(ata_sas_port_start);
* ata_port_stop - Undo ata_sas_port_start()
* @ap: Port to shut down
*
- * Frees the DMA pad.
- *
* May be used as the port_stop() entry in ata_port_operations.
*
* LOCKING:
void ata_sas_port_stop(struct ata_port *ap)
{
- ata_pad_free(ap, ap->dev);
}
EXPORT_SYMBOL_GPL(ata_sas_port_stop);