return NULL;
}
-static ssize_t ata_scsi_lpm_put(struct class_device *class_dev,
- const char *buf, size_t count)
+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(class_dev);
+ struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
enum link_pm policy = 0;
int i;
}
static ssize_t
-ata_scsi_lpm_show(struct class_device *class_dev, char *buf)
+ata_scsi_lpm_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct Scsi_Host *shost = class_to_shost(class_dev);
+ 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);
return snprintf(buf, 23, "%s\n", policy);
}
-CLASS_DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
+DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
ata_scsi_lpm_show, ata_scsi_lpm_put);
-EXPORT_SYMBOL_GPL(class_device_attr_link_power_management_policy);
+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 *))
qc->scsicmd = cmd;
qc->scsidone = done;
- qc->__sg = scsi_sglist(cmd);
+ qc->sg = scsi_sglist(cmd);
qc->n_elem = scsi_sg_count(cmd);
} else {
cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
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->max_device_blocked = 1;
}
-static void ata_scsi_dev_config(struct scsi_device *sdev,
- struct ata_device *dev)
+/**
+ * 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 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)
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);
- 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;
}
/**
* 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;
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
{
u8 pbuf[60];
struct ata_taskfile tf;
* 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;
/* 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.protocol = ATAPI_PROT_PIO;
qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;
qc->tf.lbah = 0;
}
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;
}
qc->tf.command = ATA_CMD_PACKET;
- qc->nbytes = scsi_bufflen(scmd);
+ ata_qc_set_pc_nbytes(qc);
/* check whether ATAPI DMA is safe */
if (!using_pio && ata_check_atapi_dma(qc))
* want to set it properly, and for DMA where it is
* effectively meaningless.
*/
- nbytes = min(qc->nbytes, (unsigned int)63 * 1024);
+ 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
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.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;
}
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 {
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;
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;
* TODO: find out if we need to do more here to
* cover scatter/gather case.
*/
- qc->nbytes = scsi_bufflen(scmd);
+ ata_qc_set_pc_nbytes(qc);
/* request result TF and be quiet about device error */
qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET;
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);