|
@@ -1263,7 +1263,7 @@ retry:
|
|
|
}
|
|
|
|
|
|
/* ATAPI-specific feature tests */
|
|
|
- else {
|
|
|
+ else if (dev->class == ATA_DEV_ATAPI) {
|
|
|
if (ata_id_is_ata(dev->id)) /* sanity check */
|
|
|
goto err_out_nosup;
|
|
|
|
|
@@ -2399,7 +2399,7 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
|
|
|
if (qc->flags & ATA_QCFLAG_SINGLE)
|
|
|
assert(qc->n_elem == 1);
|
|
|
|
|
|
- DPRINTK("unmapping %u sg elements\n", qc->n_elem);
|
|
|
+ VPRINTK("unmapping %u sg elements\n", qc->n_elem);
|
|
|
|
|
|
/* if we padded the buffer out to 32-bit bound, and data
|
|
|
* xfer direction is from-device, we must copy from the
|
|
@@ -2409,7 +2409,8 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
|
|
|
pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
|
|
|
|
|
|
if (qc->flags & ATA_QCFLAG_SG) {
|
|
|
- dma_unmap_sg(ap->host_set->dev, sg, qc->n_elem, dir);
|
|
|
+ if (qc->n_elem)
|
|
|
+ dma_unmap_sg(ap->host_set->dev, sg, qc->n_elem, dir);
|
|
|
/* restore last sg */
|
|
|
sg[qc->orig_n_elem - 1].length += qc->pad_len;
|
|
|
if (pad_buf) {
|
|
@@ -2419,8 +2420,10 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
|
|
|
kunmap_atomic(psg->page, KM_IRQ0);
|
|
|
}
|
|
|
} else {
|
|
|
- dma_unmap_single(ap->host_set->dev, sg_dma_address(&sg[0]),
|
|
|
- sg_dma_len(&sg[0]), dir);
|
|
|
+ if (sg_dma_len(&sg[0]) > 0)
|
|
|
+ dma_unmap_single(ap->host_set->dev,
|
|
|
+ sg_dma_address(&sg[0]), sg_dma_len(&sg[0]),
|
|
|
+ dir);
|
|
|
/* restore sg */
|
|
|
sg->length += qc->pad_len;
|
|
|
if (pad_buf)
|
|
@@ -2619,6 +2622,11 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
|
|
|
sg->length, qc->pad_len);
|
|
|
}
|
|
|
|
|
|
+ if (!sg->length) {
|
|
|
+ sg_dma_address(sg) = 0;
|
|
|
+ goto skip_map;
|
|
|
+ }
|
|
|
+
|
|
|
dma_address = dma_map_single(ap->host_set->dev, qc->buf_virt,
|
|
|
sg->length, dir);
|
|
|
if (dma_mapping_error(dma_address)) {
|
|
@@ -2628,6 +2636,7 @@ static int ata_sg_setup_one(struct ata_queued_cmd *qc)
|
|
|
}
|
|
|
|
|
|
sg_dma_address(sg) = dma_address;
|
|
|
+skip_map:
|
|
|
sg_dma_len(sg) = sg->length;
|
|
|
|
|
|
DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
|
|
@@ -2655,7 +2664,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
|
|
|
struct ata_port *ap = qc->ap;
|
|
|
struct scatterlist *sg = qc->__sg;
|
|
|
struct scatterlist *lsg = &sg[qc->n_elem - 1];
|
|
|
- int n_elem, dir;
|
|
|
+ int n_elem, pre_n_elem, dir, trim_sg = 0;
|
|
|
|
|
|
VPRINTK("ENTER, ata%u\n", ap->id);
|
|
|
assert(qc->flags & ATA_QCFLAG_SG);
|
|
@@ -2689,13 +2698,24 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
|
|
|
sg_dma_len(psg) = ATA_DMA_PAD_SZ;
|
|
|
/* trim last sg */
|
|
|
lsg->length -= qc->pad_len;
|
|
|
+ if (lsg->length == 0)
|
|
|
+ trim_sg = 1;
|
|
|
|
|
|
DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n",
|
|
|
qc->n_elem - 1, lsg->length, qc->pad_len);
|
|
|
}
|
|
|
|
|
|
+ pre_n_elem = qc->n_elem;
|
|
|
+ if (trim_sg && pre_n_elem)
|
|
|
+ pre_n_elem--;
|
|
|
+
|
|
|
+ if (!pre_n_elem) {
|
|
|
+ n_elem = 0;
|
|
|
+ goto skip_map;
|
|
|
+ }
|
|
|
+
|
|
|
dir = qc->dma_dir;
|
|
|
- n_elem = dma_map_sg(ap->host_set->dev, sg, qc->n_elem, dir);
|
|
|
+ n_elem = dma_map_sg(ap->host_set->dev, sg, pre_n_elem, dir);
|
|
|
if (n_elem < 1) {
|
|
|
/* restore last sg */
|
|
|
lsg->length += qc->pad_len;
|
|
@@ -2704,6 +2724,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
|
|
|
|
|
|
DPRINTK("%d sg elements mapped\n", n_elem);
|
|
|
|
|
|
+skip_map:
|
|
|
qc->n_elem = n_elem;
|
|
|
|
|
|
return 0;
|
|
@@ -3263,32 +3284,11 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
|
|
|
{
|
|
|
struct ata_port *ap = qc->ap;
|
|
|
struct ata_host_set *host_set = ap->host_set;
|
|
|
- struct ata_device *dev = qc->dev;
|
|
|
u8 host_stat = 0, drv_stat;
|
|
|
unsigned long flags;
|
|
|
|
|
|
DPRINTK("ENTER\n");
|
|
|
|
|
|
- /* FIXME: doesn't this conflict with timeout handling? */
|
|
|
- if (qc->dev->class == ATA_DEV_ATAPI && qc->scsicmd) {
|
|
|
- struct scsi_cmnd *cmd = qc->scsicmd;
|
|
|
-
|
|
|
- if (!(cmd->eh_eflags & SCSI_EH_CANCEL_CMD)) {
|
|
|
-
|
|
|
- /* finish completing original command */
|
|
|
- spin_lock_irqsave(&host_set->lock, flags);
|
|
|
- __ata_qc_complete(qc);
|
|
|
- spin_unlock_irqrestore(&host_set->lock, flags);
|
|
|
-
|
|
|
- atapi_request_sense(ap, dev, cmd);
|
|
|
-
|
|
|
- cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
|
|
|
- scsi_finish_command(cmd);
|
|
|
-
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
spin_lock_irqsave(&host_set->lock, flags);
|
|
|
|
|
|
/* hack alert! We cannot use the supplied completion
|
|
@@ -3327,7 +3327,6 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
|
|
|
|
|
|
spin_unlock_irqrestore(&host_set->lock, flags);
|
|
|
|
|
|
-out:
|
|
|
DPRINTK("EXIT\n");
|
|
|
}
|
|
|
|
|
@@ -3411,16 +3410,11 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
|
|
|
|
|
|
qc = ata_qc_new(ap);
|
|
|
if (qc) {
|
|
|
- qc->__sg = NULL;
|
|
|
- qc->flags = 0;
|
|
|
qc->scsicmd = NULL;
|
|
|
qc->ap = ap;
|
|
|
qc->dev = dev;
|
|
|
- qc->cursect = qc->cursg = qc->cursg_ofs = 0;
|
|
|
- qc->nsect = 0;
|
|
|
- qc->nbytes = qc->curbytes = 0;
|
|
|
|
|
|
- ata_tf_init(ap, &qc->tf, dev->devno);
|
|
|
+ ata_qc_reinit(qc);
|
|
|
}
|
|
|
|
|
|
return qc;
|