summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Yurchenko <grange@cvs.openbsd.org>2009-03-09 20:21:51 +0000
committerAlexander Yurchenko <grange@cvs.openbsd.org>2009-03-09 20:21:51 +0000
commit0dae8a405b3fba6239032a94e113bceed3ade950 (patch)
tree4e86af6dda4ed0571a36badf835b52d95703a405
parentba73cc1b579e9c6eeaa67ca0b258f3a800af6cdc (diff)
Completely rework command processing:
- use separate callbacks to finish scsi and raid management commands; - for raid management commands use dedicated dma-safe buffer; - remove unused run queue; The main goal of these changes is to fix a bug showing up on the lpinto's machine where READCONF command fails because it needs more than 1-page buffer and the buffer was not contiguos and controller doesn't support scatter-gather for raid management commands.
-rw-r--r--sys/dev/pci/ips.c560
1 files changed, 342 insertions, 218 deletions
diff --git a/sys/dev/pci/ips.c b/sys/dev/pci/ips.c
index 013ccf9a623..09dc169f84c 100644
--- a/sys/dev/pci/ips.c
+++ b/sys/dev/pci/ips.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ips.c,v 1.51 2009/03/01 19:54:23 grange Exp $ */
+/* $OpenBSD: ips.c,v 1.52 2009/03/09 20:21:50 grange Exp $ */
/*
* Copyright (c) 2006, 2007, 2009 Alexander Yurchenko <grange@openbsd.org>
@@ -17,7 +17,7 @@
*/
/*
- * IBM (Adaptec) ServeRAID controller driver.
+ * IBM (Adaptec) ServeRAID controllers driver.
*/
#include "bio.h"
@@ -192,21 +192,6 @@ struct ips_driveinfo {
} drive[IPS_MAXDRIVES];
};
-struct ips_pg5 {
- u_int32_t signature;
- u_int8_t __reserved1;
- u_int8_t slot;
- u_int16_t type;
- u_int8_t bioshi[4];
- u_int8_t bioslo[4];
- u_int16_t __reserved2;
- u_int8_t __reserved3;
- u_int8_t os;
- u_int8_t driverhi[4];
- u_int8_t driverlo[4];
- u_int8_t __reserved4[100];
-};
-
struct ips_conf {
u_int8_t ldcnt;
u_int8_t day;
@@ -266,7 +251,30 @@ struct ips_conf {
u_int8_t reserved[512];
};
+struct ips_pg5 {
+ u_int32_t signature;
+ u_int8_t __reserved1;
+ u_int8_t slot;
+ u_int16_t type;
+ u_int8_t bioshi[4];
+ u_int8_t bioslo[4];
+ u_int16_t __reserved2;
+ u_int8_t __reserved3;
+ u_int8_t os;
+ u_int8_t driverhi[4];
+ u_int8_t driverlo[4];
+ u_int8_t __reserved4[100];
+};
+
+struct ips_info {
+ struct ips_adapterinfo adapter;
+ struct ips_driveinfo drive;
+ struct ips_conf conf;
+ struct ips_pg5 pg5;
+};
+
/* Command control block */
+struct ips_softc;
struct ips_ccb {
int c_id; /* command id */
int c_flags; /* flags */
@@ -282,6 +290,9 @@ struct ips_ccb {
int c_stat; /* status word copy */
int c_estat; /* ext status word copy */
+ void (*c_done)(struct ips_softc *, /* cmd done */
+ struct ips_ccb *); /* callback */
+
TAILQ_ENTRY(ips_ccb) c_link; /* queue link */
};
@@ -313,8 +324,9 @@ struct ips_softc {
const struct ips_chipset *sc_chip;
- struct ips_conf sc_conf;
- struct ips_driveinfo sc_di;
+ struct ips_info * sc_info;
+ struct dmamem sc_infom;
+
int sc_nunits;
struct dmamem sc_cmdm;
@@ -322,7 +334,6 @@ struct ips_softc {
struct ips_ccb * sc_ccb;
int sc_nccbs;
struct ips_ccbq sc_ccbq_free;
- struct ips_ccbq sc_ccbq_run;
struct dmamem sc_sqm;
paddr_t sc_sqtail;
@@ -344,18 +355,19 @@ int ips_ioctl_disk(struct ips_softc *, struct bioc_disk *);
void ips_sensors(void *);
-int ips_cmd(struct ips_softc *, int, int, u_int32_t, void *, size_t, int,
- struct scsi_xfer *);
+int ips_load(struct ips_softc *, struct ips_ccb *, struct scsi_xfer *);
+int ips_cmd(struct ips_softc *, struct ips_ccb *);
int ips_poll(struct ips_softc *, struct ips_ccb *);
-void ips_done(struct ips_softc *, struct ips_ccb *);
+void ips_done_xs(struct ips_softc *, struct ips_ccb *);
+void ips_done_mgmt(struct ips_softc *, struct ips_ccb *);
int ips_intr(void *);
void ips_timeout(void *);
-int ips_getadapterinfo(struct ips_softc *, struct ips_adapterinfo *);
-int ips_getconf(struct ips_softc *, struct ips_conf *);
-int ips_getdriveinfo(struct ips_softc *, struct ips_driveinfo *);
+int ips_getadapterinfo(struct ips_softc *);
+int ips_getdriveinfo(struct ips_softc *);
+int ips_getconf(struct ips_softc *);
+int ips_getpg5(struct ips_softc *);
int ips_flush(struct ips_softc *);
-int ips_readnvram(struct ips_softc *, void *, int);
void ips_copperhead_exec(struct ips_softc *, struct ips_ccb *);
void ips_copperhead_init(struct ips_softc *);
@@ -490,8 +502,9 @@ ips_attach(struct device *parent, struct device *self, void *aux)
struct pci_attach_args *pa = aux;
struct ips_ccb ccb0;
struct scsibus_attach_args saa;
- struct ips_adapterinfo ai;
- struct ips_pg5 pg5;
+ struct ips_adapterinfo *ai;
+ struct ips_driveinfo *di;
+ struct ips_pg5 *pg5;
pcireg_t maptype;
bus_size_t iosize;
pci_intr_handle_t ih;
@@ -524,11 +537,22 @@ ips_attach(struct device *parent, struct device *self, void *aux)
goto fail1;
}
+ /* Allocate info buffer */
+ if (ips_dmamem_alloc(&sc->sc_infom, sc->sc_dmat,
+ sizeof(struct ips_info))) {
+ printf(": can't alloc info buffer\n");
+ goto fail2;
+ }
+ sc->sc_info = sc->sc_infom.dm_vaddr;
+ ai = &sc->sc_info->adapter;
+ di = &sc->sc_info->drive;
+ pg5 = &sc->sc_info->pg5;
+
/* Allocate status queue for the Copperhead chipset */
if (sc->sc_chip->ic_id == IPS_CHIP_COPPERHEAD) {
if (ips_dmamem_alloc(&sc->sc_sqm, sc->sc_dmat, IPS_SQSZ)) {
printf(": can't alloc status queue\n");
- goto fail2;
+ goto fail3;
}
sc->sc_sqtail = sc->sc_sqm.dm_paddr;
sc->sc_sqbuf = sc->sc_sqm.dm_vaddr;
@@ -549,52 +573,38 @@ ips_attach(struct device *parent, struct device *self, void *aux)
bzero(&ccb0, sizeof(ccb0));
ccb0.c_cmdva = sc->sc_cmdm.dm_vaddr;
ccb0.c_cmdpa = sc->sc_cmdm.dm_paddr;
- 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 fail3;
- }
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, &ai)) {
+ if (ips_getadapterinfo(sc)) {
printf(": can't get adapter info\n");
- bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
- goto fail3;
- }
-
- /* Get configuration */
- if (ips_getconf(sc, &sc->sc_conf)) {
- printf(": can't get config\n");
- bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
- goto fail3;
+ goto fail4;
}
/* Get logical drives info */
- if (ips_getdriveinfo(sc, &sc->sc_di)) {
+ if (ips_getdriveinfo(sc)) {
printf(": can't get ld info\n");
- bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
- goto fail3;
+ goto fail4;
}
- sc->sc_nunits = sc->sc_di.drivecnt;
+ sc->sc_nunits = di->drivecnt;
- /* Read NVRAM page 5 for additional info */
- bzero(&pg5, sizeof(pg5));
- ips_readnvram(sc, &pg5, 5);
+ /* Get configuration */
+ if (ips_getconf(sc)) {
+ printf(": can't get config\n");
+ goto fail4;
+ }
- bus_dmamap_destroy(sc->sc_dmat, ccb0.c_dmam);
+ /* Read NVRAM page 5 for additional info */
+ (void)ips_getpg5(sc);
/* Initialize CCB queue */
- sc->sc_nccbs = ai.cmdcnt;
+ sc->sc_nccbs = ai->cmdcnt;
if ((sc->sc_ccb = ips_ccb_alloc(sc, sc->sc_nccbs)) == NULL) {
printf(": can't alloc ccb queue\n");
- goto fail3;
+ goto fail4;
}
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);
@@ -602,7 +612,7 @@ ips_attach(struct device *parent, struct device *self, void *aux)
/* Install interrupt handler */
if (pci_intr_map(pa, &ih)) {
printf(": can't map interrupt\n");
- goto fail4;
+ goto fail5;
}
intrstr = pci_intr_string(pa->pa_pc, ih);
if (pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ips_intr, sc,
@@ -611,20 +621,20 @@ ips_attach(struct device *parent, struct device *self, void *aux)
if (intrstr != NULL)
printf(" at %s", intrstr);
printf("\n");
- goto fail4;
+ goto fail5;
}
printf(": %s\n", intrstr);
/* Display adapter info */
printf("%s: ServeRAID", sc->sc_dev.dv_xname);
- type = letoh16(pg5.type);
+ type = letoh16(pg5->type);
if (type < sizeof(ips_names) / sizeof(ips_names[0]) && ips_names[type])
printf(" %s", ips_names[type]);
- printf(", FW %c%c%c%c%c%c%c", ai.firmware[0], ai.firmware[1],
- ai.firmware[2], ai.firmware[3], ai.firmware[4], ai.firmware[5],
- ai.firmware[6]);
- printf(", BIOS %c%c%c%c%c%c%c", ai.bios[0], ai.bios[1], ai.bios[2],
- ai.bios[3], ai.bios[4], ai.bios[5], ai.bios[6]);
+ printf(", FW %c%c%c%c%c%c%c", ai->firmware[0], ai->firmware[1],
+ ai->firmware[2], ai->firmware[3], ai->firmware[4], ai->firmware[5],
+ ai->firmware[6]);
+ printf(", BIOS %c%c%c%c%c%c%c", ai->bios[0], ai->bios[1], ai->bios[2],
+ ai->bios[3], ai->bios[4], ai->bios[5], ai->bios[6]);
printf(", %d cmds, %d LD%s", sc->sc_nccbs, sc->sc_nunits,
(sc->sc_nunits == 1 ? "" : "s"));
printf("\n");
@@ -678,11 +688,13 @@ ips_attach(struct device *parent, struct device *self, void *aux)
#endif /* !SMALL_KERNEL */
return;
-fail4:
+fail5:
ips_ccb_free(sc, sc->sc_ccb, sc->sc_nccbs);
-fail3:
+fail4:
if (sc->sc_chip->ic_id == IPS_CHIP_COPPERHEAD)
ips_dmamem_free(&sc->sc_sqm);
+fail3:
+ ips_dmamem_free(&sc->sc_infom);
fail2:
ips_dmamem_free(&sc->sc_cmdm);
fail1:
@@ -694,15 +706,18 @@ ips_scsi_cmd(struct scsi_xfer *xs)
{
struct scsi_link *link = xs->sc_link;
struct ips_softc *sc = link->adapter_softc;
+ struct ips_driveinfo *di = &sc->sc_info->drive;
struct ips_drive *drive;
struct scsi_inquiry_data inq;
struct scsi_read_cap_data rcd;
struct scsi_sense_data sd;
struct scsi_rw *rw;
struct scsi_rw_big *rwb;
+ struct ips_ccb *ccb;
+ struct ips_cmd *cmd;
int target = link->target;
u_int32_t blkno, blkcnt;
- int cmd, error, flags, s;
+ int code, error, flags, s;
if (target >= sc->sc_nunits || link->lun != 0) {
DPRINTF(IPS_D_INFO, ("%s: invalid scsi command, "
@@ -715,8 +730,7 @@ ips_scsi_cmd(struct scsi_xfer *xs)
return (COMPLETE);
}
- s = splbio();
- drive = &sc->sc_di.drive[target];
+ drive = &di->drive[target];
xs->error = XS_NOERROR;
/* Fake SCSI commands */
@@ -742,36 +756,65 @@ ips_scsi_cmd(struct scsi_xfer *xs)
"blkno %u, blkcnt %u\n", sc->sc_dev.dv_xname,
blkno, blkcnt));
xs->error = XS_DRIVER_STUFFUP;
+ s = splbio();
scsi_done(xs);
+ splx(s);
break;
}
if (xs->flags & SCSI_DATA_IN) {
- cmd = IPS_CMD_READ;
+ code = IPS_CMD_READ;
flags = IPS_CCB_READ;
} else {
- cmd = IPS_CMD_WRITE;
+ code = 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 {
+ s = splbio();
+ ccb = ips_ccb_get(sc);
+ splx(s);
+ if (ccb == NULL)
+ return (NO_CCB);
+
+ ccb->c_flags = flags;
+ ccb->c_xfer = xs;
+ ccb->c_done = ips_done_xs;
+
+ cmd = ccb->c_cmdva;
+ cmd->code = code;
+ cmd->drive = target;
+ cmd->lba = htole32(blkno);
+ cmd->seccnt = htole16(blkcnt);
+
+ if (ips_load(sc, ccb, xs)) {
+ s = splbio();
+ ips_ccb_put(sc, ccb);
+ xs->error = XS_DRIVER_STUFFUP;
+ scsi_done(xs);
+ splx(s);
+ return (COMPLETE);
+ }
+
+ if (cmd->sgcnt > 0)
+ cmd->code |= IPS_CMD_SG;
+
+ timeout_set(&xs->stimeout, ips_timeout, ccb);
+ timeout_add_sec(&xs->stimeout, IPS_TIMEOUT);
+
+ if ((error = ips_cmd(sc, ccb))) {
+ if (error == ETIMEDOUT)
+ xs->error = XS_TIMEOUT;
+ else
xs->error = XS_DRIVER_STUFFUP;
- scsi_done(xs);
- break;
- }
+
+ s = splbio();
+ scsi_done(xs);
+ splx(s);
+ return (COMPLETE);
}
- splx(s);
if (flags & IPS_CCB_POLL)
return (COMPLETE);
else
@@ -813,6 +856,8 @@ ips_scsi_cmd(struct scsi_xfer *xs)
sc->sc_dev.dv_xname, xs->cmd->opcode));
xs->error = XS_DRIVER_STUFFUP;
}
+
+ s = splbio();
scsi_done(xs);
splx(s);
@@ -849,14 +894,13 @@ ips_ioctl(struct device *dev, u_long cmd, caddr_t addr)
int
ips_ioctl_inq(struct ips_softc *sc, struct bioc_inq *bi)
{
- struct ips_adapterinfo ai;
-
- if (ips_getadapterinfo(sc, &ai))
- return (ENOTTY);
+ struct ips_conf *conf = &sc->sc_info->conf;
+ int i;
strlcpy(bi->bi_dev, sc->sc_dev.dv_xname, sizeof(bi->bi_dev));
bi->bi_novol = sc->sc_nunits;
- bi->bi_nodisk = ai.drivecnt;
+ for (i = 0, bi->bi_nodisk = 0; i < sc->sc_nunits; i++)
+ bi->bi_nodisk += conf->ld[i].chunkcnt;
return (0);
}
@@ -864,19 +908,17 @@ ips_ioctl_inq(struct ips_softc *sc, struct bioc_inq *bi)
int
ips_ioctl_vol(struct ips_softc *sc, struct bioc_vol *bv)
{
- struct ips_driveinfo di;
- struct ips_drive *drive;
+ struct ips_driveinfo *di = &sc->sc_info->drive;
+ struct ips_conf *conf = &sc->sc_info->conf;
+ struct ips_ld *ld;
int vid = bv->bv_volid;
struct device *dev;
if (vid >= sc->sc_nunits)
return (EINVAL);
+ ld = &conf->ld[vid];
- if (ips_getdriveinfo(sc, &di))
- return (ENOTTY);
- drive = &di.drive[vid];
-
- switch (drive->state) {
+ switch (ld->state) {
case IPS_DS_ONLINE:
bv->bv_status = BIOC_SVONLINE;
break;
@@ -890,9 +932,9 @@ ips_ioctl_vol(struct ips_softc *sc, struct bioc_vol *bv)
bv->bv_status = BIOC_SVINVALID;
}
- bv->bv_size = (u_quad_t)letoh32(drive->seccnt) * IPS_SECSZ;
- bv->bv_level = drive->raid;
- bv->bv_nodisk = sc->sc_conf.ld[vid].chunkcnt;
+ bv->bv_size = (u_quad_t)letoh32(ld->size) * IPS_SECSZ;
+ bv->bv_level = di->drive[vid].raid;
+ bv->bv_nodisk = ld->chunkcnt;
dev = sc->sc_scsibus->sc_link[vid][0]->device_softc;
strlcpy(bv->bv_dev, dev->dv_xname, sizeof(bv->bv_dev));
@@ -904,25 +946,23 @@ ips_ioctl_vol(struct ips_softc *sc, struct bioc_vol *bv)
int
ips_ioctl_disk(struct ips_softc *sc, struct bioc_disk *bd)
{
- int vid = bd->bd_volid, did = bd->bd_diskid;
+ struct ips_conf *conf = &sc->sc_info->conf;
struct ips_ld *ld;
struct ips_chunk *chunk;
struct ips_dev *dev;
+ int vid = bd->bd_volid, did = bd->bd_diskid;
if (vid >= sc->sc_nunits)
return (EINVAL);
- ld = &sc->sc_conf.ld[vid];
+ ld = &conf->ld[vid];
if (did >= ld->chunkcnt)
return (EINVAL);
chunk = &ld->chunk[did];
if (chunk->channel >= IPS_MAXCHANS || chunk->target >= IPS_MAXTARGETS)
- return (ENOTTY);
- dev = &sc->sc_conf.dev[chunk->channel][chunk->target];
-
- if (ips_getconf(sc, &sc->sc_conf))
- return (ENOTTY);
+ return (EINVAL);
+ dev = &conf->dev[chunk->channel][chunk->target];
bd->bd_channel = chunk->channel;
bd->bd_target = chunk->target;
@@ -953,10 +993,11 @@ void
ips_sensors(void *arg)
{
struct ips_softc *sc = arg;
- struct ips_drive *drive;
+ struct ips_conf *conf = &sc->sc_info->conf;
+ struct ips_ld *ld;
int i;
- if (ips_getdriveinfo(sc, &sc->sc_di)) {
+ if (ips_getconf(sc)) {
for (i = 0; i < sc->sc_nunits; i++) {
sc->sc_sensors[i].value = 0;
sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
@@ -965,8 +1006,8 @@ ips_sensors(void *arg)
}
for (i = 0; i < sc->sc_nunits; i++) {
- drive = &sc->sc_di.drive[i];
- switch (drive->state) {
+ ld = &conf->ld[i];
+ switch (ld->state) {
case IPS_DS_ONLINE:
sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
sc->sc_sensors[i].status = SENSOR_S_OK;
@@ -988,92 +1029,67 @@ ips_sensors(void *arg)
#endif
int
-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)
+ips_load(struct ips_softc *sc, struct ips_ccb *ccb, struct scsi_xfer *xs)
{
- struct ips_cmd *cmd;
+ struct ips_cmd *cmd = ccb->c_cmdva;
struct ips_sg *sg;
- struct ips_ccb *ccb;
- int nsegs, i, s, error = 0;
+ int nsegs, i;
- 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));
+ if (xs->datalen == 0)
+ return (0);
- /* 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);
- }
+ /* Map data buffer into DMA segments */
+ if (bus_dmamap_load(sc->sc_dmat, ccb->c_dmam, xs->data, xs->datalen,
+ NULL, (xs->flags & SCSI_NOSLEEP ? BUS_DMA_NOWAIT : 0)))
+ return (1);
+ bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,ccb->c_dmam->dm_mapsize,
+ xs->flags & SCSI_DATA_IN ? BUS_DMASYNC_PREREAD :
+ BUS_DMASYNC_PREWRITE);
- ccb->c_flags = flags;
- ccb->c_xfer = xs;
+ if ((nsegs = ccb->c_dmam->dm_nsegs) > IPS_MAXSGS)
+ return (1);
- /* Fill in command frame */
- cmd = ccb->c_cmdva;
- bzero(cmd, sizeof(*cmd));
- cmd->code = code;
- cmd->id = ccb->c_id;
- 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,
- ccb->c_dmam->dm_mapsize,
- flags & IPS_CCB_READ ? BUS_DMASYNC_PREREAD :
- BUS_DMASYNC_PREWRITE);
-
- if ((nsegs = ccb->c_dmam->dm_nsegs) > IPS_MAXSGS) {
- printf("%s: too many dma segs\n",
- sc->sc_dev.dv_xname);
- return (1); /* XXX: return code */
- }
+ if (nsegs > 1) {
+ cmd->sgcnt = nsegs;
+ cmd->sgaddr = htole32(ccb->c_cmdpa + IPS_CMDSZ);
- if (nsegs > 1) {
- cmd->code |= IPS_CMD_SG;
- cmd->sgcnt = nsegs;
- cmd->sgaddr = htole32(ccb->c_cmdpa + IPS_CMDSZ);
-
- /* Fill in scatter-gather array */
- sg = (void *)(cmd + 1);
- 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);
+ /* Fill in scatter-gather array */
+ sg = (void *)(cmd + 1);
+ 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);
}
+ return (0);
+}
+
+int
+ips_cmd(struct ips_softc *sc, struct ips_ccb *ccb)
+{
+ struct ips_cmd *cmd = ccb->c_cmdva;
+ int s, error = 0;
+
+ DPRINTF(IPS_D_XFER, ("%s: cmd id %d, flags 0x%02x, code 0x%02x, "
+ "drive %d, sgcnt %d, lba %d, sgaddr 0x%08x, seccnt %d\n",
+ sc->sc_dev.dv_xname, ccb->c_id, ccb->c_flags, cmd->code,
+ cmd->drive, cmd->sgcnt, cmd->lba, cmd->sgaddr, cmd->seccnt));
+
/* Pass command to hardware */
- DPRINTF(IPS_D_XFER, ("%s: run command 0x%02x\n", sc->sc_dev.dv_xname,
- ccb->c_id));
+ cmd->id = ccb->c_id;
ccb->c_flags |= IPS_CCB_RUN;
- TAILQ_INSERT_TAIL(&sc->sc_ccbq_run, ccb, c_link);
+ s = splbio();
ips_exec(sc, ccb);
+ splx(s);
- if (flags & IPS_CCB_POLL) {
+ if (ccb->c_flags & IPS_CCB_POLL) {
/* Wait for command to complete */
s = splbio();
error = ips_poll(sc, ccb);
splx(s);
- } else {
- /* Set watchdog timer */
- if (xs != NULL) {
- timeout_set(&xs->stimeout, ips_timeout, ccb);
- timeout_add_sec(&xs->stimeout, IPS_TIMEOUT);
- }
}
return (error);
@@ -1100,19 +1116,19 @@ ips_poll(struct ips_softc *sc, struct ips_ccb *c)
}
if (timeout < 0) {
printf("%s: poll timeout\n", sc->sc_dev.dv_xname);
- return (EBUSY);
+ return (ETIMEDOUT);
}
ccb = &sc->sc_ccb[id];
ccb->c_stat = IPS_REG_STAT_GSC(status);
ccb->c_estat = IPS_REG_STAT_EXT(status);
- ips_done(sc, ccb);
+ ccb->c_done(sc, ccb);
}
return (0);
}
void
-ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
+ips_done_xs(struct ips_softc *sc, struct ips_ccb *ccb)
{
struct scsi_xfer *xs = ccb->c_xfer;
int flags = ccb->c_flags;
@@ -1121,15 +1137,10 @@ ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
if ((flags & IPS_CCB_RUN) == 0) {
printf("%s: cmd 0x%02x not run\n", sc->sc_dev.dv_xname,
ccb->c_id);
- if (xs != NULL) {
- xs->error = XS_DRIVER_STUFFUP;
- scsi_done(xs);
- }
return;
}
- if (xs != NULL)
- timeout_del(&xs->stimeout);
+ timeout_del(&xs->stimeout);
if (flags & (IPS_CCB_READ | IPS_CCB_WRITE)) {
bus_dmamap_sync(sc->sc_dmat, ccb->c_dmam, 0,
@@ -1139,10 +1150,7 @@ ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
}
if (ccb->c_stat) {
- if (xs != NULL)
- sc_print_addr(xs->sc_link);
- else
- printf("%s: ", sc->sc_dev.dv_xname);
+ sc_print_addr(xs->sc_link);
if (ccb->c_stat == 1) {
printf("recovered error\n");
} else {
@@ -1152,17 +1160,45 @@ ips_done(struct ips_softc *sc, struct ips_ccb *ccb)
}
/* Release CCB */
- TAILQ_REMOVE(&sc->sc_ccbq_run, ccb, c_link);
ips_ccb_put(sc, ccb);
- if (xs != NULL) {
- if (error)
- xs->error = XS_DRIVER_STUFFUP;
- else
- xs->resid = 0;
- xs->flags |= ITSDONE;
- scsi_done(xs);
+ if (error)
+ xs->error = XS_DRIVER_STUFFUP;
+ else
+ xs->resid = 0;
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+}
+
+void
+ips_done_mgmt(struct ips_softc *sc, struct ips_ccb *ccb)
+{
+ int flags = ccb->c_flags;
+ int error = 0;
+
+ if ((flags & IPS_CCB_RUN) == 0) {
+ printf("%s: cmd 0x%02x not run\n", sc->sc_dev.dv_xname,
+ ccb->c_id);
+ return;
}
+
+ if (flags & (IPS_CCB_READ | IPS_CCB_WRITE))
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_infom.dm_map, 0,
+ sc->sc_infom.dm_map->dm_mapsize, flags & IPS_CCB_READ ?
+ BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+
+ if (ccb->c_stat) {
+ printf("%s: ", sc->sc_dev.dv_xname);
+ if (ccb->c_stat == 1) {
+ printf("recovered error\n");
+ } else {
+ printf("error\n");
+ error = 1;
+ }
+ }
+
+ /* Release CCB */
+ ips_ccb_put(sc, ccb);
}
int
@@ -1190,7 +1226,7 @@ ips_intr(void *arg)
ccb = &sc->sc_ccb[id];
ccb->c_stat = IPS_REG_STAT_GSC(status);
ccb->c_estat = IPS_REG_STAT_EXT(status);
- ips_done(sc, ccb);
+ ccb->c_done(sc, ccb);
}
return (1);
@@ -1213,7 +1249,6 @@ ips_timeout(void *arg)
DPRINTF(IPS_D_ERR, (", command 0x%02x", ccb->c_id));
printf("\n");
- TAILQ_REMOVE(&sc->sc_ccbq_run, ccb, c_link);
ips_ccb_put(sc, ccb);
xs->error = XS_TIMEOUT;
@@ -1225,37 +1260,122 @@ ips_timeout(void *arg)
}
int
-ips_getadapterinfo(struct ips_softc *sc, struct ips_adapterinfo *ai)
+ips_getadapterinfo(struct ips_softc *sc)
{
- return (ips_cmd(sc, IPS_CMD_GETADAPTERINFO, 0, 0, ai, sizeof(*ai),
- IPS_CCB_READ | IPS_CCB_POLL, NULL));
+ struct ips_ccb *ccb;
+ struct ips_cmd *cmd;
+ int s;
+
+ s = splbio();
+ ccb = ips_ccb_get(sc);
+ splx(s);
+ if (ccb == NULL)
+ return (1);
+
+ ccb->c_flags = IPS_CCB_READ | IPS_CCB_POLL;
+ ccb->c_done = ips_done_mgmt;
+
+ cmd = ccb->c_cmdva;
+ cmd->code = IPS_CMD_GETADAPTERINFO;
+ cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
+ adapter));
+
+ return (ips_cmd(sc, ccb));
}
int
-ips_getconf(struct ips_softc *sc, struct ips_conf *conf)
+ips_getdriveinfo(struct ips_softc *sc)
{
- return (ips_cmd(sc, IPS_CMD_READCONF, 0, 0, conf, sizeof(*conf),
- IPS_CCB_READ | IPS_CCB_POLL, NULL));
+ struct ips_ccb *ccb;
+ struct ips_cmd *cmd;
+ int s;
+
+ s = splbio();
+ ccb = ips_ccb_get(sc);
+ splx(s);
+ if (ccb == NULL)
+ return (1);
+
+ ccb->c_flags = IPS_CCB_READ | IPS_CCB_POLL;
+ ccb->c_done = ips_done_mgmt;
+
+ cmd = ccb->c_cmdva;
+ cmd->code = IPS_CMD_GETDRIVEINFO;
+ cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
+ drive));
+
+ return (ips_cmd(sc, ccb));
}
int
-ips_getdriveinfo(struct ips_softc *sc, struct ips_driveinfo *di)
+ips_getconf(struct ips_softc *sc)
{
- return (ips_cmd(sc, IPS_CMD_GETDRIVEINFO, 0, 0, di, sizeof(*di),
- IPS_CCB_READ | IPS_CCB_POLL, NULL));
+ struct ips_ccb *ccb;
+ struct ips_cmd *cmd;
+ int s;
+
+ s = splbio();
+ ccb = ips_ccb_get(sc);
+ splx(s);
+ if (ccb == NULL)
+ return (1);
+
+ ccb->c_flags = IPS_CCB_READ | IPS_CCB_POLL;
+ ccb->c_done = ips_done_mgmt;
+
+ cmd = ccb->c_cmdva;
+ cmd->code = IPS_CMD_READCONF;
+ cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
+ conf));
+
+ return (ips_cmd(sc, ccb));
}
int
-ips_flush(struct ips_softc *sc)
+ips_getpg5(struct ips_softc *sc)
{
- return (ips_cmd(sc, IPS_CMD_FLUSH, 0, 0, NULL, 0, IPS_CCB_POLL, NULL));
+ struct ips_ccb *ccb;
+ struct ips_cmd *cmd;
+ int s;
+
+ s = splbio();
+ ccb = ips_ccb_get(sc);
+ splx(s);
+ if (ccb == NULL)
+ return (1);
+
+ ccb->c_flags = IPS_CCB_READ | IPS_CCB_POLL;
+ ccb->c_done = ips_done_mgmt;
+
+ cmd = ccb->c_cmdva;
+ cmd->code = IPS_CMD_RWNVRAM;
+ cmd->drive = 5;
+ cmd->sgaddr = htole32(sc->sc_infom.dm_paddr + offsetof(struct ips_info,
+ pg5));
+
+ return (ips_cmd(sc, ccb));
}
int
-ips_readnvram(struct ips_softc *sc, void *buf, int page)
+ips_flush(struct ips_softc *sc)
{
- return (ips_cmd(sc, IPS_CMD_RWNVRAM, page, 0, buf, IPS_NVRAMPGSZ,
- IPS_CCB_READ | IPS_CCB_POLL, NULL));
+ struct ips_ccb *ccb;
+ struct ips_cmd *cmd;
+ int s;
+
+ s = splbio();
+ ccb = ips_ccb_get(sc);
+ splx(s);
+ if (ccb == NULL)
+ return (1);
+
+ ccb->c_flags = IPS_CCB_POLL;
+ ccb->c_done = ips_done_mgmt;
+
+ cmd = ccb->c_cmdva;
+ cmd->code = IPS_CMD_FLUSH;
+
+ return (ips_cmd(sc, ccb));
}
void
@@ -1429,8 +1549,12 @@ ips_ccb_get(struct ips_softc *sc)
{
struct ips_ccb *ccb;
- if ((ccb = TAILQ_FIRST(&sc->sc_ccbq_free)) != NULL)
+ if ((ccb = TAILQ_FIRST(&sc->sc_ccbq_free)) != NULL) {
TAILQ_REMOVE(&sc->sc_ccbq_free, ccb, c_link);
+ ccb->c_flags = 0;
+ ccb->c_xfer = NULL;
+ bzero(ccb->c_cmdva, sizeof(struct ips_cmd));
+ }
return (ccb);
}