summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-11-16 15:12:58 -0500
committerJeff Garzik <jgarzik@pobox.com>2005-11-16 15:12:58 -0500
commit3be4bb06b53df2c0a760eeaa5f53448faddedfca (patch)
tree67dc02f39e48a8a37d8f3e4a38422d86f5164820 /drivers/scsi
parent85d6162d6cea9220e483989817eac0cebc03070e (diff)
parent7bdd720869ff75700b48b132ee71852615b55808 (diff)
downloadop-kernel-dev-3be4bb06b53df2c0a760eeaa5f53448faddedfca.zip
op-kernel-dev-3be4bb06b53df2c0a760eeaa5f53448faddedfca.tar.gz
Merge branch 'upstream-fixes'
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/ahci.c39
-rw-r--r--drivers/scsi/ata_piix.c2
-rw-r--r--drivers/scsi/libata-core.c70
-rw-r--r--drivers/scsi/libata-scsi.c77
-rw-r--r--drivers/scsi/libata.h4
-rw-r--r--drivers/scsi/sata_promise.c2
-rw-r--r--drivers/scsi/sata_qstor.c2
-rw-r--r--drivers/scsi/sata_sil24.c21
-rw-r--r--drivers/scsi/sata_svw.c2
-rw-r--r--drivers/scsi/sata_sx4.c2
-rw-r--r--drivers/scsi/sata_vsc.c2
11 files changed, 133 insertions, 90 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 4e96ec5..83467a0 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -48,7 +48,7 @@
#include <asm/io.h>
#define DRV_NAME "ahci"
-#define DRV_VERSION "1.01"
+#define DRV_VERSION "1.2"
enum {
@@ -558,13 +558,26 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
pp->cmd_slot[0].opts |= cpu_to_le32(n_elem << 16);
}
-static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
+static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
{
void __iomem *mmio = ap->host_set->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
u32 tmp;
int work;
+ if ((ap->device[0].class != ATA_DEV_ATAPI) ||
+ ((irq_stat & PORT_IRQ_TF_ERR) == 0))
+ printk(KERN_WARNING "ata%u: port reset, "
+ "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n",
+ ap->id,
+ irq_stat,
+ readl(mmio + HOST_IRQ_STAT),
+ readl(port_mmio + PORT_IRQ_STAT),
+ readl(port_mmio + PORT_CMD),
+ readl(port_mmio + PORT_TFDATA),
+ readl(port_mmio + PORT_SCR_STAT),
+ readl(port_mmio + PORT_SCR_ERR));
+
/* stop DMA */
tmp = readl(port_mmio + PORT_CMD);
tmp &= ~PORT_CMD_START;
@@ -602,8 +615,6 @@ static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
tmp |= PORT_CMD_START;
writel(tmp, port_mmio + PORT_CMD);
readl(port_mmio + PORT_CMD); /* flush */
-
- printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->id);
}
static void ahci_eng_timeout(struct ata_port *ap)
@@ -614,17 +625,17 @@ static void ahci_eng_timeout(struct ata_port *ap)
struct ata_queued_cmd *qc;
unsigned long flags;
- DPRINTK("ENTER\n");
+ printk(KERN_WARNING "ata%u: handling error/timeout\n", ap->id);
spin_lock_irqsave(&host_set->lock, flags);
- ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT));
-
qc = ata_qc_from_tag(ap, ap->active_tag);
if (!qc) {
printk(KERN_ERR "ata%u: BUG: timeout without command\n",
ap->id);
} else {
+ ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
+
/* hack alert! We cannot use the supplied completion
* function from inside the ->eh_strategy_handler() thread.
* libata is the only user of ->eh_strategy_handler() in
@@ -659,9 +670,19 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
}
if (status & PORT_IRQ_FATAL) {
- ahci_intr_error(ap, status);
+ unsigned int err_mask;
+ if (status & PORT_IRQ_TF_ERR)
+ err_mask = AC_ERR_DEV;
+ else if (status & PORT_IRQ_IF_ERR)
+ err_mask = AC_ERR_ATA_BUS;
+ else
+ err_mask = AC_ERR_HOST_BUS;
+
+ /* command processing has stopped due to error; restart */
+ ahci_restart_port(ap, status);
+
if (qc)
- ata_qc_complete(qc, AC_ERR_OTHER);
+ ata_qc_complete(qc, err_mask);
}
return 1;
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 855428f..333d69d 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -50,7 +50,7 @@
#include <linux/libata.h>
#define DRV_NAME "ata_piix"
-#define DRV_VERSION "1.04"
+#define DRV_VERSION "1.05"
enum {
PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index d81db3a..bb604df 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -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;
@@ -1570,11 +1570,13 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
/*
* Find the mode.
- */
+ */
if (!(s = ata_timing_find_mode(speed)))
return -EINVAL;
+ memcpy(t, s, sizeof(*s));
+
/*
* If the drive is an EIDE drive, it can tell us it needs extended
* PIO/MW_DMA cycle timing.
@@ -1595,7 +1597,7 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
* Convert the timing to bus clock counts.
*/
- ata_timing_quantize(s, t, T, UT);
+ ata_timing_quantize(t, t, T, UT);
/*
* Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T
@@ -2399,7 +2401,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 +2411,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 +2422,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 +2624,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 +2638,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 +2666,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 +2700,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 +2726,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 +3286,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 +3329,6 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
spin_unlock_irqrestore(&host_set->lock, flags);
-out:
DPRINTK("EXIT\n");
}
@@ -3411,16 +3412,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;
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 0df4b68..3b4ca55a 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1955,22 +1955,44 @@ void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8
done(cmd);
}
-void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
- struct scsi_cmnd *cmd)
+static int atapi_sense_complete(struct ata_queued_cmd *qc,unsigned int err_mask)
{
- DECLARE_COMPLETION(wait);
- struct ata_queued_cmd *qc;
- unsigned long flags;
- int rc;
+ if (err_mask && ((err_mask & AC_ERR_DEV) == 0))
+ /* 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
+ */
+ ata_gen_ata_desc_sense(qc);
- DPRINTK("ATAPI request sense\n");
+ qc->scsidone(qc->scsicmd);
+ return 0;
+}
- qc = ata_qc_new_init(ap, dev);
- BUG_ON(qc == NULL);
+/* is it pointless to prefer PIO for "safety reasons"? */
+static inline int ata_pio_use_silly(struct ata_port *ap)
+{
+ return (ap->flags & ATA_FLAG_PIO_DMA);
+}
+
+static void atapi_request_sense(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scsi_cmnd *cmd = qc->scsicmd;
+
+ DPRINTK("ATAPI request sense\n");
/* FIXME: is this needed? */
memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+ ap->ops->tf_read(ap, &qc->tf);
+
+ /* fill these in, for the case where they are -not- overwritten */
+ cmd->sense_buffer[0] = 0x70;
+ cmd->sense_buffer[2] = qc->tf.feature >> 4;
+
+ ata_qc_reinit(qc);
+
ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
qc->dma_dir = DMA_FROM_DEVICE;
@@ -1981,22 +2003,20 @@ void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
qc->tf.command = ATA_CMD_PACKET;
- qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
+ if (ata_pio_use_silly(ap)) {
+ qc->tf.protocol = ATA_PROT_ATAPI_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->nbytes = SCSI_SENSE_BUFFERSIZE;
- qc->waiting = &wait;
- qc->complete_fn = ata_qc_complete_noop;
+ qc->complete_fn = atapi_sense_complete;
- spin_lock_irqsave(&ap->host_set->lock, flags);
- rc = ata_qc_issue(qc);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
- if (rc)
- ata_port_disable(ap);
- else
- wait_for_completion(&wait);
+ if (ata_qc_issue(qc))
+ ata_qc_complete(qc, AC_ERR_OTHER);
DPRINTK("EXIT\n");
}
@@ -2008,19 +2028,8 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask)
VPRINTK("ENTER, err_mask 0x%X\n", err_mask);
if (unlikely(err_mask & AC_ERR_DEV)) {
- DPRINTK("request check condition\n");
-
- /* FIXME: command completion with check condition
- * but no sense causes the error handler to run,
- * which then issues REQUEST SENSE, fills in the sense
- * buffer, and completes the command (for the second
- * time). We need to issue REQUEST SENSE some other
- * way, to avoid completing the command twice.
- */
cmd->result = SAM_STAT_CHECK_CONDITION;
-
- qc->scsidone(cmd);
-
+ atapi_request_sense(qc);
return 1;
}
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index fad051c..8ebaa69 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -29,7 +29,7 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
-#define DRV_VERSION "1.12" /* must be exactly four chars */
+#define DRV_VERSION "1.20" /* must be exactly four chars */
struct ata_scsi_args {
u16 *id;
@@ -54,8 +54,6 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
/* libata-scsi.c */
-extern void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
- struct scsi_cmnd *cmd);
extern void ata_scsi_scan_host(struct ata_port *ap);
extern int ata_scsi_error(struct Scsi_Host *host);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index 242d906..8a8e3e3 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -46,7 +46,7 @@
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "1.02"
+#define DRV_VERSION "1.03"
enum {
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index 4a6d306..a8987f5 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -41,7 +41,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_qstor"
-#define DRV_VERSION "0.04"
+#define DRV_VERSION "0.05"
enum {
QS_PORTS = 4,
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index 55e744d..cb1933a 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -139,6 +139,7 @@ enum {
PORT_CS_DEV_RST = (1 << 1), /* device reset */
PORT_CS_INIT = (1 << 2), /* port initialize */
PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */
+ PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */
PORT_CS_RESUME = (1 << 6), /* port resume */
PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */
PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */
@@ -188,11 +189,29 @@ enum {
PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */
PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */
+ /* bits of PRB control field */
+ PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */
+ PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */
+ PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */
+ PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */
+ PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */
+
+ /* PRB protocol field */
+ PRB_PROT_PACKET = (1 << 0),
+ PRB_PROT_TCQ = (1 << 1),
+ PRB_PROT_NCQ = (1 << 2),
+ PRB_PROT_READ = (1 << 3),
+ PRB_PROT_WRITE = (1 << 4),
+ PRB_PROT_TRANSPARENT = (1 << 5),
+
/*
* Other constants
*/
SGE_TRM = (1 << 31), /* Last SGE in chain */
- PRB_SOFT_RST = (1 << 7), /* Soft reset request (ign BSY?) */
+ SGE_LNK = (1 << 30), /* linked list
+ Points to SGT, not SGE */
+ SGE_DRD = (1 << 29), /* discard data read (/dev/null)
+ data address ignored */
/* board id */
BID_SIL3124 = 0,
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
index 57e5a9d..6e7f7c8 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/scsi/sata_svw.c
@@ -54,7 +54,7 @@
#endif /* CONFIG_PPC_OF */
#define DRV_NAME "sata_svw"
-#define DRV_VERSION "1.06"
+#define DRV_VERSION "1.07"
/* Taskfile registers offsets */
#define K2_SATA_TF_CMD_OFFSET 0x00
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
index b4bbe48..dcc3ad9 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/scsi/sata_sx4.c
@@ -46,7 +46,7 @@
#include "sata_promise.h"
#define DRV_NAME "sata_sx4"
-#define DRV_VERSION "0.7"
+#define DRV_VERSION "0.8"
enum {
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
index 77a6e4b9..fcfa486 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/scsi/sata_vsc.c
@@ -47,7 +47,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_vsc"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
/* Interrupt register offsets (from chip base address) */
#define VSC_SATA_INT_STAT_OFFSET 0x00
OpenPOWER on IntegriCloud