|
@@ -826,17 +826,56 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
|
|
|
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
|
|
|
+ * @request: 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);
|
|
|
|
|
|
- if (dev->class == ATA_DEV_ATAPI)
|
|
|
+ if (dev->class == ATA_DEV_ATAPI) {
|
|
|
+ struct request_queue *q = sdev->request_queue;
|
|
|
+ void *buf;
|
|
|
+
|
|
|
/* set the min alignment */
|
|
|
blk_queue_update_dma_alignment(sdev->request_queue,
|
|
|
ATA_DMA_PAD_SZ - 1);
|
|
|
- else {
|
|
|
+
|
|
|
+ /* 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);
|
|
@@ -853,6 +892,8 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
|
|
|
depth = min(ATA_MAX_QUEUE - 1, depth);
|
|
|
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
|
|
|
}
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -871,13 +912,14 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
|
|
|
{
|
|
|
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);
|
|
|
|
|
|
if (dev)
|
|
|
- ata_scsi_dev_config(sdev, dev);
|
|
|
+ rc = ata_scsi_dev_config(sdev, dev);
|
|
|
|
|
|
- return 0;
|
|
|
+ return rc;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -897,6 +939,7 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
|
|
|
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;
|
|
|
|
|
@@ -912,6 +955,10 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
/**
|