diff options
author | Alexander Yurchenko <grange@cvs.openbsd.org> | 2009-03-09 20:21:51 +0000 |
---|---|---|
committer | Alexander Yurchenko <grange@cvs.openbsd.org> | 2009-03-09 20:21:51 +0000 |
commit | 0dae8a405b3fba6239032a94e113bceed3ade950 (patch) | |
tree | 4e86af6dda4ed0571a36badf835b52d95703a405 /sys/dev | |
parent | ba73cc1b579e9c6eeaa67ca0b258f3a800af6cdc (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.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/ips.c | 560 |
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); } |