summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pci/ips.c1087
1 files changed, 623 insertions, 464 deletions
diff --git a/sys/dev/pci/ips.c b/sys/dev/pci/ips.c
index 04fb82268ae..59b7813d399 100644
--- a/sys/dev/pci/ips.c
+++ b/sys/dev/pci/ips.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: ips.c,v 1.16 2006/11/29 18:18:39 grange Exp $ */
+/* $OpenBSD: ips.c,v 1.17 2007/05/27 19:21:09 grange Exp $ */
/*
- * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
+ * Copyright (c) 2006, 2007 Alexander Yurchenko <grange@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,14 +17,13 @@
*/
/*
- * IBM ServeRAID controller driver.
+ * IBM (Adaptec) ServeRAID controller driver.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
-#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/timeout.h>
@@ -40,226 +39,216 @@
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
-#define IPS_DEBUG /* XXX: remove when the driver becomes stable */
+#define IPS_DEBUG /* XXX: remove when driver becomes stable */
/* Debug levels */
-#define IPS_D_ERR 0x0001
-#define IPS_D_INFO 0x0002
-#define IPS_D_XFER 0x0004
-#define IPS_D_INTR 0x0008
+#define IPS_D_ERR 0x0001 /* errors */
+#define IPS_D_INFO 0x0002 /* information */
+#define IPS_D_XFER 0x0004 /* transfers */
+#define IPS_D_INTR 0x0008 /* interrupts */
#ifdef IPS_DEBUG
-#define DPRINTF(a, b) if (ips_debug & (a)) printf b
+#define DPRINTF(a, b) do { if (ips_debug & (a)) printf b; } while (0)
int ips_debug = IPS_D_ERR;
#else
#define DPRINTF(a, b)
#endif
-/*
- * Register definitions.
- */
-#define IPS_BAR0 0x10 /* I/O space base address */
-#define IPS_BAR1 0x14 /* I/O space base address */
-
-#define IPS_MORPHEUS_OISR 0x0030 /* outbound IRQ status */
-#define IPS_MORPHEUS_OISR_CMD (1 << 3)
-#define IPS_MORPHEUS_OIMR 0x0034 /* outbound IRQ mask */
-#define IPS_MORPHEUS_IQPR 0x0040 /* inbound queue port */
-#define IPS_MORPHEUS_OQPR 0x0044 /* outbound queue port */
-#define IPS_MORPHEUS_OQPR_ID(x) (((x) >> 8) & 0xff)
-#define IPS_MORPHEUS_OQPR_ST(x) (((x) >> 16) & 0xff)
-#define IPS_MORPHEUS_OQPR_GSC(x) (((x) >> 16) & 0x0f)
-#define IPS_MORPHEUS_OQPR_EST(x) (((x) >> 24) & 0xff)
-#define IPS_MORPHEUS_GSC_NOERR 0x0
-#define IPS_MORPHEUS_GSC_RECOV 0x1
-
-/* Commands */
-#define IPS_CMD_READ 0x02
-#define IPS_CMD_WRITE 0x03
-#define IPS_CMD_ADAPTERINFO 0x05
-#define IPS_CMD_FLUSHCACHE 0x0a
-#define IPS_CMD_READ_SG 0x82
-#define IPS_CMD_WRITE_SG 0x83
-#define IPS_CMD_DRIVEINFO 0x19
-
-#define IPS_MAXCMDSZ 256 /* XXX: for now */
-#define IPS_MAXDATASZ 64 * 1024
-#define IPS_MAXSEGS 32
-
#define IPS_MAXDRIVES 8
#define IPS_MAXCHANS 4
#define IPS_MAXTARGETS 15
-#define IPS_MAXCMDS 32
#define IPS_MAXFER (64 * 1024)
-#define IPS_MAXSGS 32
+#define IPS_MAXSGS 16
+#define IPS_MAXCMDSZ (IPS_CMDSZ + IPS_MAXSGS * IPS_SGSZ)
-/* Command frames */
-struct ips_cmd_adapterinfo {
- u_int8_t command;
- u_int8_t id;
- u_int8_t reserve1;
- u_int8_t commandtype;
- u_int32_t reserve2;
- u_int32_t buffaddr;
- u_int32_t reserve3;
-} __packed;
-
-struct ips_cmd_driveinfo {
- u_int8_t command;
- u_int8_t id;
- u_int8_t drivenum;
- u_int8_t reserve1;
- u_int32_t reserve2;
- u_int32_t buffaddr;
- u_int32_t reserve3;
-} __packed;
-
-struct ips_cmd_generic {
- u_int8_t command;
- u_int8_t id;
- u_int8_t drivenum;
- u_int8_t reserve2;
- u_int32_t lba;
- u_int32_t buffaddr;
- u_int32_t reserve3;
-} __packed;
+#define IPS_CMDSZ sizeof(struct ips_cmd)
+#define IPS_SGSZ sizeof(struct ips_sg)
+#define IPS_SECSZ 512
-struct ips_cmd_io {
- u_int8_t command;
+/* Command codes */
+#define IPS_CMD_READ 0x02
+#define IPS_CMD_WRITE 0x03
+#define IPS_CMD_DCDB 0x04
+#define IPS_CMD_GETADAPTERINFO 0x05
+#define IPS_CMD_FLUSH 0x0a
+#define IPS_CMD_ERRORTABLE 0x17
+#define IPS_CMD_GETDRIVEINFO 0x19
+#define IPS_CMD_RESETCHAN 0x1a
+#define IPS_CMD_DOWNLOAD 0x20
+#define IPS_CMD_RWBIOSFW 0x22
+#define IPS_CMD_READCONF 0x38
+#define IPS_CMD_GETSUBSYS 0x40
+#define IPS_CMD_CONFIGSYNC 0x58
+#define IPS_CMD_READ_SG 0x82
+#define IPS_CMD_WRITE_SG 0x83
+#define IPS_CMD_DCDB_SG 0x84
+#define IPS_CMD_EXT_DCDB 0x95
+#define IPS_CMD_EXT_DCDB_SG 0x96
+#define IPS_CMD_RWNVRAMPAGE 0xbc
+#define IPS_CMD_GETVERINFO 0xc6
+#define IPS_CMD_FFDC 0xd7
+#define IPS_CMD_SG 0x80
+
+/* Register definitions */
+#define IPS_REG_CCSA 0x10 /* command channel system address */
+#define IPS_REG_CCC 0x14 /* command channel control */
+#define IPS_REG_CCC_SEM 0x0008 /* semaphore */
+#define IPS_REG_CCC_START 0x101a /* start command */
+#define IPS_REG_OIS 0x30 /* outbound interrupt status */
+#define IPS_REG_OIS_PEND 0x0008 /* interrupt is pending */
+#define IPS_REG_OIM 0x34 /* outbound interrupt mask */
+#define IPS_REG_OIM_DS 0x0008 /* disable interrupts */
+#define IPS_REG_IQP 0x40 /* inbound queue port */
+#define IPS_REG_OQP 0x44 /* outbound queue port */
+
+#define IPS_REG_STAT_ID(x) (((x) >> 8) & 0xff)
+
+/* Command frame */
+struct ips_cmd {
+ u_int8_t code;
u_int8_t id;
- u_int8_t drivenum;
- u_int8_t segnum;
+ u_int8_t drive;
+ u_int8_t sgcnt;
u_int32_t lba;
- u_int32_t buffaddr;
- u_int16_t length;
- u_int16_t reserve1;
-} __packed;
+ u_int32_t sgaddr;
+ u_int16_t seccnt;
+ u_int8_t seg4g;
+ u_int8_t esg;
+ u_int32_t ccsar;
+ u_int32_t cccr;
+};
+
+/* Scatter-gather array element */
+struct ips_sg {
+ u_int32_t addr;
+ u_int32_t size;
+};
/* Data frames */
struct ips_adapterinfo {
- u_int8_t drivecount;
- u_int8_t miscflags;
- u_int8_t SLTflags;
- u_int8_t BSTflags;
- u_int8_t pwr_chg_count;
- u_int8_t wrong_addr_count;
- u_int8_t unident_count;
- u_int8_t nvram_dev_chg_count;
- u_int8_t codeblock_version[8];
- u_int8_t bootblock_version[8];
- u_int32_t drive_sector_count[IPS_MAXDRIVES];
- u_int8_t max_concurrent_cmds;
- u_int8_t max_phys_devices;
- u_int16_t flash_prog_count;
- u_int8_t defunct_disks;
- u_int8_t rebuildflags;
- u_int8_t offline_drivecount;
- u_int8_t critical_drivecount;
- u_int16_t config_update_count;
- u_int8_t blockedflags;
- u_int8_t psdn_error;
- u_int16_t addr_dead_disk[IPS_MAXCHANS][IPS_MAXTARGETS];
-} __packed;
-
-struct ips_drive {
- u_int8_t drivenum;
- u_int8_t merge_id;
- u_int8_t raid_lvl;
- u_int8_t state;
- u_int32_t sector_count;
-} __packed;
+ u_int8_t drivecnt;
+ u_int8_t miscflag;
+ u_int8_t sltflag;
+ u_int8_t bstflag;
+ u_int8_t pwrchgcnt;
+ u_int8_t wrongaddrcnt;
+ u_int8_t unidentcnt;
+ u_int8_t nvramdevchgcnt;
+ u_int8_t codeblkver[8];
+ u_int8_t bootblkver[8];
+ u_int32_t drivesize[IPS_MAXDRIVES];
+ u_int8_t cmdcnt;
+ u_int8_t maxphysdevs;
+ u_int16_t flashrepgmcnt;
+ u_int8_t defunctdiskcnt;
+ u_int8_t rebuildflag;
+ u_int8_t offdrivecnt;
+ u_int8_t critdrivecnt;
+ u_int16_t confupdcnt;
+ u_int8_t blkflag;
+ u_int8_t __reserved;
+ u_int16_t deaddisk[IPS_MAXCHANS * (IPS_MAXTARGETS + 1)];
+};
struct ips_driveinfo {
- u_int8_t drivecount;
- u_int8_t reserve1;
- u_int16_t reserve2;
- struct ips_drive drives[IPS_MAXDRIVES];
-} __packed;
-
-/* I/O access helper macros */
-#define IPS_READ_4(s, r) \
- letoh32(bus_space_read_4((s)->sc_iot, (s)->sc_ioh, (r)))
-#define IPS_WRITE_4(s, r, v) \
- bus_space_write_4((s)->sc_iot, (s)->sc_ioh, (r), htole32((v)))
-
-struct ccb {
- int c_id;
- int c_flags;
-#define CCB_F_RUN 0x0001
-
- bus_dmamap_t c_dmam;
- struct scsi_xfer * c_xfer;
-
- TAILQ_ENTRY(ccb) c_link;
+ u_int8_t drivecnt;
+ u_int8_t __reserved[3];
+ struct ips_drive {
+ u_int8_t id;
+ u_int8_t __reserved;
+ u_int8_t raid;
+ u_int8_t state;
+ u_int32_t seccnt;
+ } drive[IPS_MAXDRIVES];
};
-TAILQ_HEAD(ccbq, ccb);
+/* Command control block */
+struct ips_ccb {
+ int c_id; /* command id */
+ int c_flags; /* flags */
+#define IPS_CCB_READ 0x0001
+#define IPS_CCB_WRITE 0x0002
+#define IPS_CCB_POLL 0x0004
+#define IPS_CCB_RUN 0x0008
+
+ bus_dmamap_t c_dmam; /* data buffer DMA map */
+ struct scsi_xfer * c_xfer; /* corresponding SCSI xfer */
+ TAILQ_ENTRY(ips_ccb) c_link; /* queue link */
+};
+
+/* CCB queue */
+TAILQ_HEAD(ips_ccbq, ips_ccb);
+
+/* DMA-able chunk of memory */
struct dmamem {
bus_dma_tag_t dm_tag;
bus_dmamap_t dm_map;
bus_dma_segment_t dm_seg;
bus_size_t dm_size;
- void * dm_kva;
+ void * dm_vaddr;
+#define dm_paddr dm_seg.ds_addr
};
struct ips_softc {
struct device sc_dev;
struct scsi_link sc_scsi_link;
- struct scsibus_softc * sc_scsi_bus;
-
- pci_chipset_tag_t sc_pc;
- pcitag_t sc_tag;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
- struct dmamem * sc_cmdm;
-
- struct ccb * sc_ccb;
- struct ccbq sc_ccbq;
+ const struct ips_chipset *sc_chip;
- void * sc_ih;
+ struct ips_driveinfo sc_di;
+ int sc_nunits;
- void (*sc_exec)(struct ips_softc *);
- void (*sc_inten)(struct ips_softc *);
- int (*sc_intr)(void *);
+ struct dmamem sc_cmdm;
- struct ips_adapterinfo sc_ai;
- struct ips_driveinfo sc_di;
+ struct ips_ccb * sc_ccb;
+ int sc_nccbs;
+ struct ips_ccbq sc_ccbq_free;
+ struct ips_ccbq sc_ccbq_run;
};
int ips_match(struct device *, void *, void *);
void ips_attach(struct device *, struct device *, void *);
int ips_scsi_cmd(struct scsi_xfer *);
-int ips_scsi_io(struct scsi_xfer *);
-int ips_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int,
- struct proc *);
-void ips_scsi_minphys(struct buf *);
-void ips_xfer_timeout(void *);
+int ips_cmd(struct ips_softc *, int, int, u_int32_t, void *, size_t, int,
+ struct scsi_xfer *);
+int ips_poll(struct ips_softc *, struct ips_ccb *);
+void ips_done(struct ips_softc *, struct ips_ccb *);
+int ips_intr(void *);
-void ips_flushcache(struct ips_softc *);
int ips_getadapterinfo(struct ips_softc *, struct ips_adapterinfo *);
int ips_getdriveinfo(struct ips_softc *, struct ips_driveinfo *);
+int ips_flush(struct ips_softc *);
void ips_copperhead_exec(struct ips_softc *);
-void ips_copperhead_inten(struct ips_softc *);
-int ips_copperhead_intr(void *);
+void ips_copperhead_init(struct ips_softc *);
+void ips_copperhead_intren(struct ips_softc *);
+int ips_copperhead_isintr(struct ips_softc *);
+int ips_copperhead_reset(struct ips_softc *);
+u_int32_t ips_copperhead_status(struct ips_softc *);
void ips_morpheus_exec(struct ips_softc *);
-void ips_morpheus_inten(struct ips_softc *);
-int ips_morpheus_intr(void *);
+void ips_morpheus_init(struct ips_softc *);
+void ips_morpheus_intren(struct ips_softc *);
+int ips_morpheus_isintr(struct ips_softc *);
+int ips_morpheus_reset(struct ips_softc *);
+u_int32_t ips_morpheus_status(struct ips_softc *);
-struct ccb * ips_ccb_alloc(bus_dma_tag_t, int);
-void ips_ccb_free(struct ccb *, bus_dma_tag_t, int);
+struct ips_ccb *ips_ccb_alloc(bus_dma_tag_t, int);
+void ips_ccb_free(struct ips_ccb *, bus_dma_tag_t, int);
+struct ips_ccb *ips_ccb_get(struct ips_softc *);
+void ips_ccb_put(struct ips_softc *, struct ips_ccb *);
-struct dmamem * ips_dmamem_alloc(bus_dma_tag_t, bus_size_t);
-void ips_dmamem_free(struct dmamem *);
+int ips_dmamem_alloc(struct dmamem *, bus_dma_tag_t, bus_size_t);
+void ips_dmamem_free(struct dmamem *);
struct cfattach ips_ca = {
sizeof(struct ips_softc),
@@ -271,18 +260,12 @@ struct cfdriver ips_cd = {
NULL, "ips", DV_DULL
};
-static const struct pci_matchid ips_ids[] = {
- { PCI_VENDOR_IBM, PCI_PRODUCT_IBM_SERVERAID },
- { PCI_VENDOR_IBM, PCI_PRODUCT_IBM_SERVERAID2 },
- { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_SERVERAID }
-};
-
static struct scsi_adapter ips_scsi_adapter = {
ips_scsi_cmd,
- ips_scsi_minphys,
+ minphys,
NULL,
NULL,
- ips_scsi_ioctl
+ NULL
};
static struct scsi_device ips_scsi_device = {
@@ -292,6 +275,57 @@ static struct scsi_device ips_scsi_device = {
NULL
};
+static const struct pci_matchid ips_ids[] = {
+ { PCI_VENDOR_IBM, PCI_PRODUCT_IBM_SERVERAID },
+ { PCI_VENDOR_IBM, PCI_PRODUCT_IBM_SERVERAID2 },
+ { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_SERVERAID }
+};
+
+static const struct ips_chipset {
+ const char * ic_name;
+ int ic_bar;
+
+ void (*ic_exec)(struct ips_softc *);
+ void (*ic_init)(struct ips_softc *);
+ void (*ic_intren)(struct ips_softc *);
+ int (*ic_isintr)(struct ips_softc *);
+ int (*ic_reset)(struct ips_softc *);
+ u_int32_t (*ic_status)(struct ips_softc *);
+} ips_chips[] = {
+ {
+ "Copperhead",
+ 0x14,
+ ips_copperhead_exec,
+ ips_copperhead_init,
+ ips_copperhead_intren,
+ ips_copperhead_isintr,
+ ips_copperhead_reset,
+ ips_copperhead_status
+ },
+ {
+ "Morpheus",
+ 0x10,
+ ips_morpheus_exec,
+ ips_morpheus_init,
+ ips_morpheus_intren,
+ ips_morpheus_isintr,
+ ips_morpheus_reset,
+ ips_morpheus_status
+ }
+};
+
+enum {
+ IPS_CHIP_COPPERHEAD = 0,
+ IPS_CHIP_MORPHEUS
+};
+
+#define ips_exec(s) (s)->sc_chip->ic_exec((s))
+#define ips_init(s) (s)->sc_chip->ic_init((s))
+#define ips_intren(s) (s)->sc_chip->ic_intren((s))
+#define ips_isintr(s) (s)->sc_chip->ic_isintr((s))
+#define ips_reset(s) (s)->sc_chip->ic_reset((s))
+#define ips_status(s) (s)->sc_chip->ic_status((s))
+
int
ips_match(struct device *parent, void *match, void *aux)
{
@@ -304,115 +338,143 @@ ips_attach(struct device *parent, struct device *self, void *aux)
{
struct ips_softc *sc = (struct ips_softc *)self;
struct pci_attach_args *pa = aux;
+ struct ips_ccb ccb0;
struct scsibus_attach_args saa;
- int bar;
+ struct ips_adapterinfo ai;
pcireg_t maptype;
bus_size_t iosize;
pci_intr_handle_t ih;
const char *intrstr;
- int i, maxcmds;
+ int i;
- sc->sc_pc = pa->pa_pc;
- sc->sc_tag = pa->pa_tag;
sc->sc_dmat = pa->pa_dmat;
- /* Identify the chipset */
+ /* Identify chipset */
switch (PCI_PRODUCT(pa->pa_id)) {
case PCI_PRODUCT_IBM_SERVERAID:
- printf(": Copperhead");
- sc->sc_exec = ips_copperhead_exec;
- sc->sc_inten = ips_copperhead_inten;
- sc->sc_intr = ips_copperhead_intr;
+ sc->sc_chip = &ips_chips[IPS_CHIP_COPPERHEAD];
break;
case PCI_PRODUCT_IBM_SERVERAID2:
case PCI_PRODUCT_ADP2_SERVERAID:
- printf(": Morpheus");
- sc->sc_exec = ips_morpheus_exec;
- sc->sc_inten = ips_morpheus_inten;
- sc->sc_intr = ips_morpheus_intr;
+ sc->sc_chip = &ips_chips[IPS_CHIP_MORPHEUS];
break;
+ default:
+ printf(": unsupported chipset\n");
+ return;
}
- /* Map I/O space */
- if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_IBM_SERVERAID)
- bar = IPS_BAR1;
- else
- bar = IPS_BAR0;
- maptype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, bar);
- if (pci_mapreg_map(pa, bar, maptype, 0, &sc->sc_iot, &sc->sc_ioh,
- NULL, &iosize, 0)) {
- printf(": can't map I/O space\n");
+ /* Map registers */
+ maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, sc->sc_chip->ic_bar);
+ if (pci_mapreg_map(pa, sc->sc_chip->ic_bar, maptype, 0, &sc->sc_iot,
+ &sc->sc_ioh, NULL, &iosize, 0)) {
+ printf(": can't map registers\n");
return;
}
- /* Allocate command DMA buffer */
- if ((sc->sc_cmdm = ips_dmamem_alloc(sc->sc_dmat,
- IPS_MAXCMDSZ)) == NULL) {
- printf(": can't alloc command DMA buffer\n");
+ /* Initialize hardware */
+ ips_init(sc);
+
+ /* Allocate command buffer */
+ if (ips_dmamem_alloc(&sc->sc_cmdm, sc->sc_dmat, IPS_MAXCMDSZ)) {
+ printf(": can't allocate command buffer\n");
goto fail1;
}
+ /* Bootstrap CCB queue */
+ sc->sc_nccbs = 1;
+ sc->sc_ccb = &ccb0;
+ bzero(&ccb0, sizeof(ccb0));
+ if (bus_dmamap_create(sc->sc_dmat, IPS_MAXFER, IPS_MAXSGS,
+ IPS_MAXFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+ &ccb0.c_dmam)) {
+ printf(": can't bootstrap CCB queue\n");
+ goto fail2;
+ }
+ TAILQ_INIT(&sc->sc_ccbq_free);
+ TAILQ_INIT(&sc->sc_ccbq_run);
+ TAILQ_INSERT_TAIL(&sc->sc_ccbq_free, &ccb0, c_link);
+
/* Get adapter info */
- if (ips_getadapterinfo(sc, &sc->sc_ai)) {
+ if (ips_getadapterinfo(sc, &ai)) {
printf(": can't get adapter info\n");
+ bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
goto fail2;
}
/* Get logical drives info */
if (ips_getdriveinfo(sc, &sc->sc_di)) {
- printf(": can't get drives info\n");
+ printf(": can't get logical drives info\n");
+ bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
goto fail2;
}
+ sc->sc_nunits = sc->sc_di.drivecnt;
- /* Allocate command queue */
- maxcmds = sc->sc_ai.max_concurrent_cmds;
- if ((sc->sc_ccb = ips_ccb_alloc(sc->sc_dmat, maxcmds)) == NULL) {
- printf(": can't alloc command queue\n");
+ bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
+
+ /* Initialize CCB queue */
+ sc->sc_nccbs = ai.cmdcnt;
+ if ((sc->sc_ccb = ips_ccb_alloc(sc->sc_dmat, sc->sc_nccbs)) == NULL) {
+ printf(": can't allocate CCB queue\n");
goto fail2;
}
-
- TAILQ_INIT(&sc->sc_ccbq);
- for (i = 0; i < maxcmds; i++)
- TAILQ_INSERT_TAIL(&sc->sc_ccbq, &sc->sc_ccb[i], c_link);
+ TAILQ_INIT(&sc->sc_ccbq_free);
+ TAILQ_INIT(&sc->sc_ccbq_run);
+ for (i = 0; i < sc->sc_nccbs; i++)
+ TAILQ_INSERT_TAIL(&sc->sc_ccbq_free,
+ &sc->sc_ccb[i], c_link);
/* Install interrupt handler */
if (pci_intr_map(pa, &ih)) {
printf(": can't map interrupt\n");
goto fail3;
}
- intrstr = pci_intr_string(sc->sc_pc, ih);
- if ((sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_BIO,
- sc->sc_intr, sc, sc->sc_dev.dv_xname)) == NULL) {
+ intrstr = pci_intr_string(pa->pa_pc, ih);
+ if (pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ips_intr, sc,
+ sc->sc_dev.dv_xname) == NULL) {
printf(": can't establish interrupt");
if (intrstr != NULL)
printf(" at %s", intrstr);
printf("\n");
goto fail3;
}
- printf(", %s\n", intrstr);
-
- /* Enable interrupts */
- (*sc->sc_inten)(sc);
+ printf(": %s\n", intrstr);
+
+ /* Display adapter info */
+ printf("%s", sc->sc_dev.dv_xname);
+ printf(": %s", sc->sc_chip->ic_name);
+ printf(", firmware %c%c%c%c%c%c%c",
+ ai.codeblkver[0], ai.codeblkver[1], ai.codeblkver[2],
+ ai.codeblkver[3], ai.codeblkver[4], ai.codeblkver[5],
+ ai.codeblkver[6]);
+ printf(", bootblock %c%c%c%c%c%c%c",
+ ai.bootblkver[0], ai.bootblkver[1], ai.bootblkver[2],
+ ai.bootblkver[3], ai.bootblkver[4], ai.bootblkver[5],
+ ai.bootblkver[6]);
+ printf(", %d CCBs, %d units", sc->sc_nccbs, sc->sc_nunits);
+ printf("\n");
/* Attach SCSI bus */
- sc->sc_scsi_link.openings = 1; /* XXX: for now */
- sc->sc_scsi_link.adapter_target = IPS_MAXTARGETS;
- sc->sc_scsi_link.adapter_buswidth = IPS_MAXTARGETS;
+ if (sc->sc_nunits > 0)
+ sc->sc_scsi_link.openings = sc->sc_nccbs / sc->sc_nunits;
+ sc->sc_scsi_link.openings = 1; /* XXX */
+ sc->sc_scsi_link.adapter_target = sc->sc_nunits;
+ sc->sc_scsi_link.adapter_buswidth = sc->sc_nunits;
sc->sc_scsi_link.device = &ips_scsi_device;
sc->sc_scsi_link.adapter = &ips_scsi_adapter;
sc->sc_scsi_link.adapter_softc = sc;
bzero(&saa, sizeof(saa));
saa.saa_sc_link = &sc->sc_scsi_link;
+ config_found(self, &saa, scsiprint);
- sc->sc_scsi_bus = (struct scsibus_softc *)config_found(self, &saa,
- scsiprint);
+ /* Enable interrupts */
+ ips_intren(sc);
return;
fail3:
- ips_ccb_free(sc->sc_ccb, sc->sc_dmat, maxcmds);
+ ips_ccb_free(sc->sc_ccb, sc->sc_dmat, sc->sc_nccbs);
fail2:
- ips_dmamem_free(sc->sc_cmdm);
+ ips_dmamem_free(&sc->sc_cmdm);
fail1:
bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
}
@@ -422,326 +484,412 @@ ips_scsi_cmd(struct scsi_xfer *xs)
{
struct scsi_link *link = xs->sc_link;
struct ips_softc *sc = link->adapter_softc;
- struct scsi_inquiry_data *inq;
- struct scsi_read_cap_data *cap;
- struct scsi_sense_data *sns;
+ struct ips_drive *drive;
+ struct scsi_inquiry_data *id;
+ struct scsi_read_cap_data *rcd;
+ struct scsi_sense_data *sd;
+ struct scsi_rw *rw;
+ struct scsi_rw_big *rwb;
int target = link->target;
- int s;
+ u_int32_t blkno, blkcnt;
+ int cmd, error, flags, s;
+
+ if (target >= sc->sc_nunits || link->lun != 0) {
+ DPRINTF(IPS_D_INFO, ("%s: invalid scsi command, "
+ "target %d, lun %d\n", sc->sc_dev.dv_xname,
+ target, link->lun));
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
+ }
- if (target >= sc->sc_di.drivecount || link->lun != 0)
- goto error;
+ s = splbio();
+ drive = &sc->sc_di.drive[target];
+ xs->error = XS_NOERROR;
+ /* Fake SCSI commands */
switch (xs->cmd->opcode) {
case READ_BIG:
case READ_COMMAND:
case WRITE_BIG:
case WRITE_COMMAND:
- return (ips_scsi_io(xs));
+ if (xs->cmdlen == sizeof(struct scsi_rw)) {
+ rw = (void *)xs->cmd;
+ blkno = _3btol(rw->addr) &
+ (SRW_TOPADDR << 16 | 0xffff);
+ blkcnt = rw->length ? rw->length : 0x100;
+ } else {
+ rwb = (void *)xs->cmd;
+ blkno = _4btol(rwb->addr);
+ blkcnt = _2btol(rwb->length);
+ }
+
+ if (blkno >= letoh32(drive->seccnt) || blkno + blkcnt >
+ letoh32(drive->seccnt)) {
+ DPRINTF(IPS_D_ERR, ("%s: invalid scsi command, "
+ "blkno %u, blkcnt %u\n", sc->sc_dev.dv_xname,
+ blkno, blkcnt));
+ xs->error = XS_DRIVER_STUFFUP;
+ scsi_done(xs);
+ break;
+ }
+
+ if (xs->flags & SCSI_DATA_IN) {
+ cmd = IPS_CMD_READ;
+ flags = IPS_CCB_READ;
+ } else {
+ cmd = IPS_CMD_WRITE;
+ flags = IPS_CCB_WRITE;
+ }
+ if (xs->flags & SCSI_POLL)
+ flags |= IPS_CCB_POLL;
+
+ if ((error = ips_cmd(sc, cmd, target, blkno, xs->data,
+ blkcnt * IPS_SECSZ, flags, xs))) {
+ if (error == ENOMEM) {
+ splx(s);
+ return (NO_CCB);
+ } else if (flags & IPS_CCB_POLL) {
+ splx(s);
+ return (TRY_AGAIN_LATER);
+ } else {
+ xs->error = XS_DRIVER_STUFFUP;
+ scsi_done(xs);
+ break;
+ }
+ }
+
+ splx(s);
+ if (flags & IPS_CCB_POLL)
+ return (COMPLETE);
+ else
+ return (SUCCESSFULLY_QUEUED);
case INQUIRY:
- inq = (void *)xs->data;
- bzero(inq, sizeof(*inq));
- inq->device = T_DIRECT;
- inq->version = 2;
- inq->response_format = 2;
- inq->additional_length = 32;
- strlcpy(inq->vendor, "IBM", sizeof(inq->vendor));
- snprintf(inq->product, sizeof(inq->product),
- "ServeRAID LD %02d", target);
- goto done;
+ id = (void *)xs->data;
+ bzero(id, sizeof(*id));
+ id->device = T_DIRECT;
+ id->version = 2;
+ id->response_format = 2;
+ id->additional_length = 32;
+ strlcpy(id->vendor, "IBM ", sizeof(id->vendor));
+ snprintf(id->product, sizeof(id->product),
+ "ServeRAID RAID%d #%02d", drive->raid, target);
+ strlcpy(id->revision, " ", sizeof(id->revision));
+ break;
case READ_CAPACITY:
- cap = (void *)xs->data;
- bzero(cap, sizeof(*cap));
- _lto4b(sc->sc_di.drives[target].sector_count - 1, cap->addr);
- _lto4b(512, cap->length);
- goto done;
+ rcd = (void *)xs->data;
+ bzero(rcd, sizeof(*rcd));
+ _lto4b(letoh32(drive->seccnt) - 1, rcd->addr);
+ _lto4b(IPS_SECSZ, rcd->length);
+ break;
case REQUEST_SENSE:
- sns = (void *)xs->data;
- bzero(sns, sizeof(*sns));
- sns->error_code = 0x70;
- sns->flags = SKEY_NO_SENSE;
- goto done;
+ sd = (void *)xs->data;
+ bzero(sd, sizeof(*sd));
+ sd->error_code = SSD_ERRCODE_CURRENT;
+ sd->flags = SKEY_NO_SENSE;
+ break;
case SYNCHRONIZE_CACHE:
- ips_flushcache(sc);
- goto done;
+ if (ips_flush(sc))
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
case PREVENT_ALLOW:
case START_STOP:
case TEST_UNIT_READY:
- return (COMPLETE);
+ break;
+ default:
+ DPRINTF(IPS_D_INFO, ("%s: unsupported scsi command 0x%02x\n",
+ sc->sc_dev.dv_xname, xs->cmd->opcode));
+ xs->error = XS_DRIVER_STUFFUP;
}
-
-error:
- xs->error = XS_DRIVER_STUFFUP;
-done:
- s = splbio();
- scsi_done(xs);
splx(s);
+
return (COMPLETE);
}
int
-ips_scsi_io(struct scsi_xfer *xs)
+ips_cmd(struct ips_softc *sc, int code, int drive, u_int32_t lba, void *data,
+ size_t size, int flags, struct scsi_xfer *xs)
{
- struct scsi_link *link = xs->sc_link;
- struct ips_softc *sc = link->adapter_softc;
- struct scsi_rw *rw;
- struct scsi_rw_big *rwb;
- struct ccb *ccb;
- struct ips_cmd_io *cmd;
- u_int32_t blkno, blkcnt;
- int i, s;
-
- /* Pick up the first free ccb */
- s = splbio();
- ccb = TAILQ_FIRST(&sc->sc_ccbq);
- if (ccb != NULL)
- TAILQ_REMOVE(&sc->sc_ccbq, ccb, c_link);
- splx(s);
- if (ccb == NULL) {
- DPRINTF(IPS_D_ERR, ("%s: scsi_io, no free ccb\n",
- sc->sc_dev.dv_xname));
- return (TRY_AGAIN_LATER);
+ struct ips_cmd *cmd = sc->sc_cmdm.dm_vaddr;
+ struct ips_sg *sg = (void *)(cmd + 1);
+ struct ips_ccb *ccb;
+ int nsegs, i, error = 0;
+
+ DPRINTF(IPS_D_XFER, ("%s: cmd code 0x%02x, drive %d, lba %u, "
+ "size %lu, flags 0x%02x\n", sc->sc_dev.dv_xname, code, drive, lba,
+ (u_long)size, flags));
+
+ /* Grab free CCB */
+ if ((ccb = ips_ccb_get(sc)) == NULL) {
+ DPRINTF(IPS_D_ERR, ("%s: no free CCB\n", sc->sc_dev.dv_xname));
+ return (ENOMEM);
}
- DPRINTF(IPS_D_XFER, ("%s: scsi_io, ccb id %d\n", sc->sc_dev.dv_xname,
- ccb->c_id));
- bus_dmamap_load(sc->sc_dmat, ccb->c_dmam, xs->data, xs->datalen, NULL,
- BUS_DMA_NOWAIT);
+ ccb->c_flags = flags;
ccb->c_xfer = xs;
- if (xs->cmd->opcode == READ_COMMAND ||
- xs->cmd->opcode == WRITE_COMMAND) {
- rw = (void *)xs->cmd;
- blkno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
- blkcnt = rw->length > 0 ? rw->length : 0x100;
- } else {
- rwb = (void *)xs->cmd;
- blkno = _4btol(rwb->addr);
- blkcnt = _2btol(rwb->length);
- }
-
- cmd = sc->sc_cmdm->dm_kva;
- bzero(cmd, sizeof(*cmd));
- cmd->command = (xs->flags & SCSI_DATA_IN) ? IPS_CMD_READ :
- IPS_CMD_WRITE;
+ /* Fill in command frame */
+ cmd->code = code;
cmd->id = ccb->c_id;
- cmd->drivenum = link->target;
- cmd->lba = blkno;
- cmd->length = blkcnt;
- if (ccb->c_dmam->dm_nsegs > 1) {
- cmd->command = (xs->flags & SCSI_DATA_IN) ? IPS_CMD_READ_SG :
- IPS_CMD_WRITE_SG;
- cmd->segnum = ccb->c_dmam->dm_nsegs;
-
- for (i = 0; i < ccb->c_dmam->dm_nsegs; i++) {
- *(u_int32_t *)((u_int8_t *)sc->sc_cmdm->dm_kva + 24 +
- i * 8) = ccb->c_dmam->dm_segs[i].ds_addr;
- *(u_int32_t *)((u_int8_t *)sc->sc_cmdm->dm_kva + 24 +
- i * 8 + 4) = ccb->c_dmam->dm_segs[i].ds_len;
+ cmd->drive = drive;
+ cmd->lba = htole32(lba);
+ cmd->seccnt = htole16(howmany(size, IPS_SECSZ));
+
+ if (size > 0) {
+ /* Map data buffer into DMA segments */
+ if (bus_dmamap_load(sc->sc_dmat, ccb->c_dmam, data, size,
+ NULL, BUS_DMA_NOWAIT)) {
+ printf("%s: can't load DMA map\n",
+ sc->sc_dev.dv_xname);
+ return (1); /* XXX: return code */
+ }
+ bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0, size,
+ flags & IPS_CCB_READ ? BUS_DMASYNC_PREREAD :
+ BUS_DMASYNC_PREWRITE);
+
+ if ((nsegs = ccb->c_dmam->dm_nsegs) > IPS_MAXSGS) {
+ printf("%s: too many DMA segments\n",
+ sc->sc_dev.dv_xname);
+ return (1); /* XXX: return code */
+ }
+
+ if (nsegs > 1) {
+ cmd->code |= IPS_CMD_SG;
+ cmd->sgcnt = nsegs;
+ cmd->sgaddr = htole32(sc->sc_cmdm.dm_paddr + IPS_CMDSZ);
+
+ /* Fill in scatter-gather array */
+ for (i = 0; i < nsegs; i++) {
+ sg[i].addr =
+ htole32(ccb->c_dmam->dm_segs[i].ds_addr);
+ sg[i].size =
+ htole32(ccb->c_dmam->dm_segs[i].ds_len);
+ }
+ } else {
+ cmd->sgcnt = 0;
+ cmd->sgaddr = htole32(ccb->c_dmam->dm_segs[0].ds_addr);
}
- cmd->buffaddr = sc->sc_cmdm->dm_seg.ds_addr + 24;
- } else {
- cmd->buffaddr = ccb->c_dmam->dm_segs[0].ds_addr;
}
- timeout_set(&xs->stimeout, ips_xfer_timeout, ccb);
- timeout_add(&xs->stimeout, (xs->timeout * 1000) / hz);
+ /* Pass command to hardware */
+ ccb->c_flags |= IPS_CCB_RUN;
+ TAILQ_INSERT_TAIL(&sc->sc_ccbq_run, ccb, c_link);
+ ips_exec(sc);
- s = splbio();
- (*sc->sc_exec)(sc);
- ccb->c_flags |= CCB_F_RUN;
- splx(s);
+ if (flags & IPS_CCB_POLL)
+ /* Wait for command to complete */
+ error = ips_poll(sc, ccb);
- return (SUCCESSFULLY_QUEUED);
+ return (error);
}
int
-ips_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flags,
- struct proc *p)
+ips_poll(struct ips_softc *sc, struct ips_ccb *c)
{
- return (ENOTTY);
-}
+ struct ips_ccb *ccb = NULL;
+ u_int32_t status;
+ int id, timeout;
+
+ while (ccb != c) {
+ for (timeout = 10; timeout-- > 0; delay(100)) {
+ if ((status = ips_status(sc)) == 0xffffffff)
+ continue;
+ id = IPS_REG_STAT_ID(status);
+ if (id >= sc->sc_nccbs) {
+ DPRINTF(IPS_D_ERR, ("%s: invalid command %d\n",
+ sc->sc_dev.dv_xname, id));
+ continue;
+ }
+ break;
+ }
+ if (timeout == 0) {
+ printf("%s: poll timeout\n", sc->sc_dev.dv_xname);
+ return (EBUSY);
+ }
+ ccb = &sc->sc_ccb[id];
+ ips_done(sc, ccb);
+ }
-void
-ips_scsi_minphys(struct buf *bp)
-{
- minphys(bp);
+ return (0);
}
void
-ips_xfer_timeout(void *arg)
+ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
{
- struct ccb *ccb = arg;
struct scsi_xfer *xs = ccb->c_xfer;
- struct ips_softc *sc = xs->sc_link->adapter_softc;
- int s;
+ int flags = ccb->c_flags;
+
+ if ((flags & IPS_CCB_RUN) == 0) {
+ printf("%s: command %d not run\n", sc->sc_dev.dv_xname,
+ ccb->c_id);
+ if (xs != NULL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ scsi_done(xs);
+ }
+ return;
+ }
- DPRINTF(IPS_D_ERR, ("%s: xfer timeout, ccb id %d\n",
- sc->sc_dev.dv_xname, ccb->c_id));
+ if (flags & (IPS_CCB_READ | IPS_CCB_WRITE)) {
+ bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
+ ccb->c_dmam->dm_mapsize, flags & IPS_CCB_READ ?
+ BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
+ }
- bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
- xs->error = XS_TIMEOUT;
- s = splbio();
- scsi_done(xs);
- ccb->c_flags &= ~CCB_F_RUN;
- TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, c_link);
- splx(s);
+ if (xs != NULL) {
+ xs->resid = 0;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+ }
+
+ /* Release CCB */
+ TAILQ_REMOVE(&sc->sc_ccbq_run, ccb, c_link);
+ ips_ccb_put(sc, ccb);
}
-void
-ips_flushcache(struct ips_softc *sc)
+int
+ips_intr(void *arg)
{
- struct ips_cmd_generic *cmd;
+ struct ips_softc *sc = arg;
+ struct ips_ccb *ccb;
+ u_int32_t status;
+ int id;
+
+ if (!ips_isintr(sc))
+ return (0);
- cmd = sc->sc_cmdm->dm_kva;
- cmd->command = IPS_CMD_FLUSHCACHE;
+ /* Process completed commands */
+ while ((status = ips_status(sc)) != 0xffffffff) {
+ DPRINTF(IPS_D_INTR, ("%s: intr status 0x%08x\n",
+ sc->sc_dev.dv_xname, status));
- (*sc->sc_exec)(sc);
- DELAY(1000);
+ id = IPS_REG_STAT_ID(status);
+ if (id >= sc->sc_nccbs) {
+ DPRINTF(IPS_D_ERR, ("%s: invalid command %d\n",
+ sc->sc_dev.dv_xname, id));
+ continue;
+ }
+ ccb = &sc->sc_ccb[id];
+ ips_done(sc, ccb);
+ }
+
+ return (1);
}
int
ips_getadapterinfo(struct ips_softc *sc, struct ips_adapterinfo *ai)
{
- struct dmamem *dm;
- struct ips_cmd_adapterinfo *cmd;
-
- if ((dm = ips_dmamem_alloc(sc->sc_dmat, sizeof(*ai))) == NULL)
- return (1);
-
- cmd = sc->sc_cmdm->dm_kva;
- bzero(cmd, sizeof(*cmd));
- cmd->command = IPS_CMD_ADAPTERINFO;
- cmd->buffaddr = dm->dm_seg.ds_addr;
-
- (*sc->sc_exec)(sc);
- DELAY(1000);
- bcopy(dm->dm_kva, ai, sizeof(*ai));
- ips_dmamem_free(dm);
-
- return (0);
+ return (ips_cmd(sc, IPS_CMD_GETADAPTERINFO, 0, 0, ai, sizeof(*ai),
+ IPS_CCB_READ | IPS_CCB_POLL, NULL));
}
int
ips_getdriveinfo(struct ips_softc *sc, struct ips_driveinfo *di)
{
- struct dmamem *dm;
- struct ips_cmd_driveinfo *cmd;
-
- if ((dm = ips_dmamem_alloc(sc->sc_dmat, sizeof(*di))) == NULL)
- return (1);
-
- cmd = sc->sc_cmdm->dm_kva;
- bzero(cmd, sizeof(*cmd));
- cmd->command = IPS_CMD_DRIVEINFO;
- cmd->buffaddr = dm->dm_seg.ds_addr;
-
- (*sc->sc_exec)(sc);
- DELAY(1000);
- bcopy(dm->dm_kva, di, sizeof(*di));
- ips_dmamem_free(dm);
+ return (ips_cmd(sc, IPS_CMD_GETDRIVEINFO, 0, 0, di, sizeof(*di),
+ IPS_CCB_READ | IPS_CCB_POLL, NULL));
+}
- return (0);
+int
+ips_flush(struct ips_softc *sc)
+{
+ return (ips_cmd(sc, IPS_CMD_FLUSH, 0, 0, NULL, 0, IPS_CCB_POLL, NULL));
}
void
ips_copperhead_exec(struct ips_softc *sc)
{
+ /* XXX: not implemented */
+}
+
+void
+ips_copperhead_init(struct ips_softc *sc)
+{
+ /* XXX: not implemented */
}
void
-ips_copperhead_inten(struct ips_softc *sc)
+ips_copperhead_intren(struct ips_softc *sc)
{
+ /* XXX: not implemented */
}
int
-ips_copperhead_intr(void *arg)
+ips_copperhead_isintr(struct ips_softc *sc)
{
+ /* XXX: not implemented */
+ return (0);
+}
+
+int
+ips_copperhead_reset(struct ips_softc *sc)
+{
+ /* XXX: not implemented */
+ return (0);
+}
+
+u_int32_t
+ips_copperhead_status(struct ips_softc *sc)
+{
+ /* XXX: not implemented */
return (0);
}
void
ips_morpheus_exec(struct ips_softc *sc)
{
- IPS_WRITE_4(sc, IPS_MORPHEUS_IQPR, sc->sc_cmdm->dm_seg.ds_addr);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_IQP,
+ sc->sc_cmdm.dm_paddr);
}
void
-ips_morpheus_inten(struct ips_softc *sc)
+ips_morpheus_init(struct ips_softc *sc)
+{
+ /* XXX: not implemented */
+}
+
+void
+ips_morpheus_intren(struct ips_softc *sc)
{
u_int32_t reg;
- reg = IPS_READ_4(sc, IPS_MORPHEUS_OIMR);
- reg &= ~0x08;
- IPS_WRITE_4(sc, IPS_MORPHEUS_OIMR, reg);
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM);
+ reg &= ~IPS_REG_OIM_DS;
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIM, reg);
}
int
-ips_morpheus_intr(void *arg)
+ips_morpheus_isintr(struct ips_softc *sc)
{
- struct ips_softc *sc = arg;
- struct ccb *ccb;
- struct scsi_xfer *xs;
- u_int32_t oisr, oqpr;
- int gsc, id, s, rv = 0;
-
- oisr = IPS_READ_4(sc, IPS_MORPHEUS_OISR);
- DPRINTF(IPS_D_INTR, ("%s: intr, OISR 0x%08x\n",
- sc->sc_dev.dv_xname, oisr));
-
- if (!(oisr & IPS_MORPHEUS_OISR_CMD))
- return (0);
-
- while ((oqpr = IPS_READ_4(sc, IPS_MORPHEUS_OQPR)) != 0xffffffff) {
- DPRINTF(IPS_D_INTR, ("OQPR 0x%08x\n", oqpr));
+ u_int32_t reg;
- gsc = IPS_MORPHEUS_OQPR_GSC(oqpr);
- id = IPS_MORPHEUS_OQPR_ID(oqpr);
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OIS);
+ DPRINTF(IPS_D_INTR, ("%s: isintr 0x%08x\n", sc->sc_dev.dv_xname, reg));
- if (gsc != IPS_MORPHEUS_GSC_NOERR &&
- gsc != IPS_MORPHEUS_GSC_RECOV) {
- DPRINTF(IPS_D_ERR, ("%s: intr, error 0x%x",
- sc->sc_dev.dv_xname, gsc));
- DPRINTF(IPS_D_ERR, (", OISR 0x%08x, OQPR 0x%08x\n",
- oisr, oqpr));
- }
+ return (reg & IPS_REG_OIS_PEND);
+}
- if (id >= sc->sc_ai.max_concurrent_cmds) {
- DPRINTF(IPS_D_ERR, ("%s: intr, bogus id %d",
- sc->sc_dev.dv_xname, id));
- DPRINTF(IPS_D_ERR, (", OISR 0x%08x, OQPR 0x%08x\n",
- oisr, oqpr));
- continue;
- }
+int
+ips_morpheus_reset(struct ips_softc *sc)
+{
+ /* XXX: not implemented */
+ return (0);
+}
- ccb = &sc->sc_ccb[id];
- if (!(ccb->c_flags & CCB_F_RUN)) {
- DPRINTF(IPS_D_ERR, ("%s: intr, ccb id %d not run",
- sc->sc_dev.dv_xname, id));
- DPRINTF(IPS_D_ERR, (", OISR 0x%08x, OQPR 0x%08x\n",
- oisr, oqpr));
- continue;
- }
+u_int32_t
+ips_morpheus_status(struct ips_softc *sc)
+{
+ u_int32_t reg;
- rv = 1;
- bus_dmamap_unload(sc->sc_dmat, ccb->c_dmam);
- xs = ccb->c_xfer;
- xs->resid = 0;
- xs->flags |= ITSDONE;
- timeout_del(&xs->stimeout);
- s = splbio();
- scsi_done(xs);
- ccb->c_flags &= ~CCB_F_RUN;
- TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, c_link);
- splx(s);
- }
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, IPS_REG_OQP);
+ DPRINTF(IPS_D_INTR, ("%s: status 0x%08x\n", sc->sc_dev.dv_xname, reg));
- return (rv);
+ return (reg);
}
-struct ccb *
+struct ips_ccb *
ips_ccb_alloc(bus_dma_tag_t dmat, int n)
{
- struct ccb *ccb;
+ struct ips_ccb *ccb;
int i;
if ((ccb = malloc(n * sizeof(*ccb), M_DEVBUF, M_NOWAIT)) == NULL)
@@ -765,7 +913,7 @@ fail:
}
void
-ips_ccb_free(struct ccb *ccb, bus_dma_tag_t dmat, int n)
+ips_ccb_free(struct ips_ccb *ccb, bus_dma_tag_t dmat, int n)
{
int i;
@@ -774,51 +922,62 @@ ips_ccb_free(struct ccb *ccb, bus_dma_tag_t dmat, int n)
free(ccb, M_DEVBUF);
}
-struct dmamem *
-ips_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size)
+struct ips_ccb *
+ips_ccb_get(struct ips_softc *sc)
{
- struct dmamem *dm;
- int nsegs;
+ struct ips_ccb *ccb;
- if ((dm = malloc(sizeof(*dm), M_DEVBUF, M_NOWAIT)) == NULL)
- return (NULL);
+ if ((ccb = TAILQ_FIRST(&sc->sc_ccbq_free)) != NULL)
+ TAILQ_REMOVE(&sc->sc_ccbq_free, ccb, c_link);
+
+ return (ccb);
+}
+
+void
+ips_ccb_put(struct ips_softc *sc, struct ips_ccb *ccb)
+{
+ ccb->c_flags = 0;
+ ccb->c_xfer = NULL;
+ TAILQ_INSERT_TAIL(&sc->sc_ccbq_free, ccb, c_link);
+}
+
+int
+ips_dmamem_alloc(struct dmamem *dm, bus_dma_tag_t tag, bus_size_t size)
+{
+ int nsegs;
dm->dm_tag = tag;
dm->dm_size = size;
if (bus_dmamap_create(tag, size, 1, size, 0,
BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &dm->dm_map))
- goto fail1;
+ return (1);
if (bus_dmamem_alloc(tag, size, 0, 0, &dm->dm_seg, 1, &nsegs,
BUS_DMA_NOWAIT))
+ goto fail1;
+ if (bus_dmamem_map(tag, &dm->dm_seg, 1, size, (caddr_t *)&dm->dm_vaddr,
+ BUS_DMA_NOWAIT))
goto fail2;
- if (bus_dmamem_map(tag, &dm->dm_seg, 1, size, (caddr_t *)&dm->dm_kva,
+ if (bus_dmamap_load(tag, dm->dm_map, dm->dm_vaddr, size, NULL,
BUS_DMA_NOWAIT))
goto fail3;
- bzero(dm->dm_kva, size);
- if (bus_dmamap_load(tag, dm->dm_map, dm->dm_kva, size, NULL,
- BUS_DMA_NOWAIT))
- goto fail4;
- return (dm);
+ return (0);
-fail4:
- bus_dmamem_unmap(tag, dm->dm_kva, size);
fail3:
- bus_dmamem_free(tag, &dm->dm_seg, 1);
+ bus_dmamem_unmap(tag, dm->dm_vaddr, size);
fail2:
- bus_dmamap_destroy(tag, dm->dm_map);
+ bus_dmamem_free(tag, &dm->dm_seg, 1);
fail1:
- free(dm, M_DEVBUF);
- return (NULL);
+ bus_dmamap_destroy(tag, dm->dm_map);
+ return (1);
}
void
ips_dmamem_free(struct dmamem *dm)
{
bus_dmamap_unload(dm->dm_tag, dm->dm_map);
- bus_dmamem_unmap(dm->dm_tag, dm->dm_kva, dm->dm_size);
+ bus_dmamem_unmap(dm->dm_tag, dm->dm_vaddr, dm->dm_size);
bus_dmamem_free(dm->dm_tag, &dm->dm_seg, 1);
bus_dmamap_destroy(dm->dm_tag, dm->dm_map);
- free(dm, M_DEVBUF);
}