Module Name: src Committed By: snj Date: Mon Sep 28 00:17:28 UTC 2009
Modified Files: src/sys/dev/ic [netbsd-5]: siisata.c siisatareg.h siisatavar.h src/sys/dev/pci [netbsd-5]: files.pci siisata_pci.c Log Message: Pull up following revision(s) (requested by jakllsch in ticket #1023): sys/dev/ic/siisata.c: revision 1.3 sys/dev/ic/siisatareg.h: revision 1.3 sys/dev/ic/siisatavar.h: revision 1.3 sys/dev/pci/files.pci: revision 1.315 sys/dev/pci/siisata_pci.c: revision 1.3 A few changes for siisata(4): - Support detachment. From KIYOHARA Takashi. - Add PCI detachment functionality (albeit not very interesting when the bus can not yet be rescanned). - Rework interrupt handlers to reduce near-duplicate code. Borrowed from ahcisata(4). - Attempt to make polled I/O work. Untested. - Fix formatting of some messages. - For always-polled commands, disable interrupt at slot level rather than port level. - Instead of busy-waiting indefinitely for completion of some commands move on after 31 seconds. Use cv_timedwait(9) instead of DELAY(9). - Use abstracted SATA FIS code. - Enable use of disks that don't respond with the standard signature. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.2.4.1 src/sys/dev/ic/siisata.c \ src/sys/dev/ic/siisatareg.h src/sys/dev/ic/siisatavar.h cvs rdiff -u -r1.308.2.3 -r1.308.2.4 src/sys/dev/pci/files.pci cvs rdiff -u -r1.1.14.1 -r1.1.14.2 src/sys/dev/pci/siisata_pci.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/siisata.c diff -u src/sys/dev/ic/siisata.c:1.2 src/sys/dev/ic/siisata.c:1.2.4.1 --- src/sys/dev/ic/siisata.c:1.2 Sun Sep 14 21:53:49 2008 +++ src/sys/dev/ic/siisata.c Mon Sep 28 00:17:28 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: siisata.c,v 1.2 2008/09/14 21:53:49 jakllsch Exp $ */ +/* $NetBSD: siisata.c,v 1.2.4.1 2009/09/28 00:17:28 snj Exp $ */ /* from ahcisata_core.c */ @@ -100,11 +100,14 @@ #include <uvm/uvm_extern.h> -#include <dev/ic/wdcreg.h> #include <dev/ata/atareg.h> #include <dev/ata/satavar.h> #include <dev/ata/satareg.h> +#include <dev/ata/satafisvar.h> #include <dev/ic/siisatavar.h> +#include <dev/ic/wdcreg.h> + +#include <dev/scsipi/scsi_all.h> /* for SCSI status */ #include "atapibus.h" @@ -119,8 +122,7 @@ #define ATA_DELAY 10000 /* 10s for a drive I/O */ static void siisata_attach_port(struct siisata_softc *, int); -static void siisata_intr_port(struct siisata_softc *, - struct siisata_channel *); +static void siisata_intr_port(struct siisata_channel *); void siisata_probe_drive(struct ata_channel *); void siisata_setup_channel(struct ata_channel *); @@ -159,7 +161,6 @@ int siisata_atapi_complete(struct ata_channel *, struct ata_xfer *, int); void siisata_atapi_kill_xfer(struct ata_channel *, struct ata_xfer *, int); void siisata_atapi_done(struct ata_channel *, struct ata_xfer *, int); -void siisata_atapi_reset(struct ata_channel *, struct ata_xfer *); void siisata_atapi_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t, void *); void siisata_atapi_kill_pending(struct scsipi_periph *); @@ -266,11 +267,10 @@ if (chp->ch_queue == NULL) { aprint_error_dev(sc->sc_atac.atac_dev, "port %d: can't allocate memory " - "for command queue", chp->ch_channel); + "for command queue\n", chp->ch_channel); return; } - dmasize = SIISATA_CMD_SIZE * SIISATA_MAX_SLOTS; SIISATA_DEBUG_PRINT(("%s: %s: dmasize: %d\n", SIISATANAME(sc), @@ -366,6 +366,48 @@ return; } +int +siisata_detach(struct siisata_softc *sc, int flags) +{ + struct atac_softc *atac = &sc->sc_atac; + struct scsipi_adapter *adapt = &atac->atac_atapi_adapter._generic; + struct siisata_channel *schp; + struct ata_channel *chp; + bus_dmamap_t dmam; + int i, j, error; + + for (i = 0; i < sc->sc_atac.atac_nchannels; i++) { + schp = &sc->sc_channels[i]; + chp = sc->sc_chanarray[i]; + + if (chp->atabus == NULL) + continue; + if ((error = config_detach(chp->atabus, flags)) != 0) + return error; + + for (j = 0; j < SIISATA_MAX_SLOTS; j++) + bus_dmamap_destroy(sc->sc_dmat, schp->sch_datad[j]); + + dmam = schp->sch_prbd; + bus_dmamap_unload(sc->sc_dmat, dmam); + bus_dmamap_destroy(sc->sc_dmat, dmam); + bus_dmamem_unmap(sc->sc_dmat, schp->sch_prb[0], + dmam->dm_mapsize); + bus_dmamem_free(sc->sc_dmat, dmam->dm_segs, dmam->dm_nsegs); + + free(chp->ch_queue, M_DEVBUF); + chp->atabus = NULL; + } + + if (adapt->adapt_refcnt != 0) + return EBUSY; + + /* leave the chip in reset */ + GRWRITE(sc, GR_GC, GR_GC_GLBLRST); + + return 0; +} + void siisata_resume(struct siisata_softc *sc) { @@ -392,27 +434,69 @@ r = 1; for (i = 0; i < sc->sc_atac.atac_nchannels; i++) if (is & GR_GIS_PXIS(i)) - siisata_intr_port(sc, &sc->sc_channels[i]); + siisata_intr_port(&sc->sc_channels[i]); } return r; } static void -siisata_intr_port(struct siisata_softc *sc, struct siisata_channel *schp) +siisata_intr_port(struct siisata_channel *schp) { - struct ata_channel *chp = &schp->ata_channel; - struct ata_xfer *xfer = chp->ch_queue->active_xfer; - int slot = SIISATA_NON_NCQ_SLOT; + struct siisata_softc *sc; + struct ata_channel *chp; + struct ata_xfer *xfer; + int slot; + uint32_t pss, pis; + uint32_t prbfis; + + sc = (struct siisata_softc *)schp->ata_channel.ch_atac; + chp = &schp->ata_channel; + xfer = chp->ch_queue->active_xfer; + slot = SIISATA_NON_NCQ_SLOT; SIISATA_DEBUG_PRINT(("%s: %s port %d\n", SIISATANAME(sc), __func__, chp->ch_channel), DEBUG_INTR); - if ((xfer != NULL) && (xfer->c_intr != NULL)) - xfer->c_intr(chp, xfer, slot); -#ifdef DIAGNOSTIC - else - log(LOG_WARNING, "%s: unable to handle interrupt\n", __func__); -#endif + pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS)); + + if (pis & PR_PIS_CMDCMPL) { + /* get slot status, clearing completion interrupt */ + pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)); + /* is this expected? */ + /* XXX improve */ + if ((schp->sch_active_slots & __BIT(slot)) == 0) { + log(LOG_WARNING, "%s: unexpected command " + "completion on port %d\n", + SIISATANAME(sc), chp->ch_channel); + return; + } + } else if (pis & PR_PIS_CMDERRR) { + uint32_t ec; + + /* emulate a CRC error by default */ + chp->ch_status = WDCS_ERR; + chp->ch_error = WDCE_CRC; + + ec = PRREAD(sc, PRX(chp->ch_channel, PRO_PCE)); + if (ec <= PR_PCE_DATAFISERROR) { + if (ec != PR_PCE_DATAFISERROR) { + /* read in specific information about error */ + prbfis = bus_space_read_stream_4( + sc->sc_prt, sc->sc_prh, + PRSX(chp->ch_channel, slot, PRSO_FIS)); + /* set ch_status and ch_error */ + satafis_sdb_parse(chp, (uint8_t *)&prbfis); + } + siisata_reinit_port(chp); + } else { + /* okay, we have a "Fatal Error" */ + siisata_device_reset(chp); + } + } + + KASSERT(xfer != NULL); + KASSERT(xfer->c_intr != NULL); + xfer->c_intr(chp, xfer, slot); /* clear some (ok, all) ints */ PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), 0xffffffff); @@ -427,7 +511,17 @@ struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac; struct siisata_channel *schp = (struct siisata_channel *)chp; struct siisata_prb *prb; + kmutex_t mtx; + kcondvar_t cv; int slot = SIISATA_NON_NCQ_SLOT; + int i; + int wait; + + mutex_init(&mtx, MUTEX_DEFAULT, IPL_NONE); + cv_init(&cv, "siipd"); + + wait = mstohz(10); + wait = wait ? wait : 1; /* wait for ready */ while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PCS)) & PR_PS_PORT_READY)) @@ -440,9 +534,13 @@ siisata_activate_prb(schp, slot); - /* wait for completion */ - while (PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) & PR_PXSS(slot)) - DELAY(10); + for(i = 0; i < (31000/(1000/(wait*hz))); i++) { + if (PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) & + PR_PXSS(slot)) + break; + else + cv_timedwait(&cv, &mtx, wait); + } siisata_deactivate_prb(schp, slot); @@ -472,6 +570,10 @@ chp->ch_status = 0; chp->ch_error = 0; #endif + + cv_destroy(&cv); + mutex_destroy(&mtx); + return; } @@ -490,6 +592,7 @@ SIISATANAME(sc), chp->ch_channel); /* XXX and then ? */ } + /* wait for ready */ while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PCS)) & PR_PS_PORT_READY)) DELAY(10); PRWRITE(sc, PRX(chp->ch_channel, PRO_SERROR), @@ -530,8 +633,9 @@ uint32_t sig; int slot = SIISATA_NON_NCQ_SLOT; struct siisata_prb *prb; - - DELAY(chp->ch_channel * 2048 + 1023); /* XXX */ + kmutex_t mtx; + kcondvar_t cv; + int wait; SIISATA_DEBUG_PRINT(("%s: %s: port %d start\n", SIISATANAME(sc), __func__, chp->ch_channel), DEBUG_FUNCS); @@ -542,6 +646,12 @@ chp->ch_drive[i].drive = i; } + mutex_init(&mtx, MUTEX_DEFAULT, IPL_NONE); + cv_init(&cv, "siipd"); + + wait = mstohz(10); + wait = wait ? wait : 1; + switch (sata_reset_interface(chp, sc->sc_prt, schp->sch_scontrol, schp->sch_sstatus)) { case SStatus_DET_DEV: @@ -557,10 +667,13 @@ siisata_activate_prb(schp, slot); - /* wait for completion */ - while (PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) - & PR_PXSS(slot)) - DELAY(10); + for(i = 0; i < (31000/(1000/(wait*hz))); i++) { + if (PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) & + PR_PXSS(slot)) + break; + else + cv_timedwait(&cv, &mtx, wait); + } siisata_deactivate_prb(schp, slot); @@ -589,15 +702,21 @@ chp->ch_drive[0].drive_flags |= DRIVE_ATA; break; default: - aprint_error_dev(sc->sc_atac.atac_dev, - "%s: unknown device signature 0x%08x\n", - __func__, sig); + chp->ch_drive[0].drive_flags |= DRIVE_ATA; + aprint_verbose_dev(sc->sc_atac.atac_dev, + "Unrecognized signature 0x%08x on port %d. " + "Assuming it's a disk.\n", sig, chp->ch_channel); + break; } splx(s); break; default: break; } + + cv_destroy(&cv); + mutex_destroy(&mtx); + SIISATA_DEBUG_PRINT(("%s: %s: port %d done\n", SIISATANAME(sc), __func__, chp->ch_channel), DEBUG_PROBE); return; @@ -674,7 +793,6 @@ struct ata_command *ata_c = xfer->c_cmd; int slot = SIISATA_NON_NCQ_SLOT; struct siisata_prb *prb; - uint8_t *fis; int i; SIISATA_DEBUG_PRINT(("%s: %s port %d, slot %d\n", @@ -682,19 +800,8 @@ prb = schp->sch_prb[slot]; memset(prb, 0, sizeof(struct siisata_prb)); - fis = prb->prb_fis; - /* XXX probably needs to be some common FIS-related code */ - fis[0] = 0x27; /* host to device */ - fis[1] = 0x80; /* command FIS (also, PMP) */ - fis[2] = ata_c->r_command; - fis[3] = ata_c->r_features; - fis[4] = ata_c->r_sector; - fis[5] = ata_c->r_cyl & 0xff; - fis[6] = (ata_c->r_cyl >> 8) & 0xff; - fis[7] = ata_c->r_head & 0x0f; - fis[12] = ata_c->r_count; - fis[15] = WDCTL_4BIT; + satafis_rhd_construct_cmd(ata_c, prb->prb_fis); memset(prb->prb_atapi, 0, sizeof(prb->prb_atapi)); @@ -709,8 +816,7 @@ if (xfer->c_flags & C_POLL) { /* polled command, disable interrupts */ - GRWRITE(sc, GR_GC, - GRREAD(sc, GR_GC) & ~(GR_GC_PXIE(chp->ch_channel))); + prb->prb_control = htole16(PRB_CF_INTERRUPT_MASK); } /* go for it */ @@ -723,14 +829,14 @@ goto out; } + /* + * polled command + */ for (i = 0; i < ata_c->timeout / 10; i++) { if (ata_c->flags & AT_DONE) break; - siisata_intr_port(sc, schp); - if (ata_c->flags & AT_WAIT) - tsleep(&xfer, PRIBIO, "siipl", mstohz(10)); - else - DELAY(10000); + siisata_intr_port(schp); + DELAY(10000); } if ((ata_c->flags & AT_DONE) == 0) { @@ -771,60 +877,11 @@ siisata_cmd_complete(struct ata_channel *chp, struct ata_xfer *xfer, int slot) { struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac; - struct siisata_channel *schp = (struct siisata_channel *)chp; struct ata_command *ata_c = xfer->c_cmd; - uint32_t pss, pis; - uint8_t fis[4]; - uint32_t *prbfis = (void *)fis; SIISATA_DEBUG_PRINT( ("%s: %s\n", SIISATANAME(sc), __func__), DEBUG_FUNCS); - pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS)); - - if ((xfer->c_flags & C_TIMEOU) != 0) - goto command_done; - - if (pis & PR_PIS_CMDCMPL) { - /* get slot status, clearing completion interrupt */ - pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)); - /* is this expected? */ - if ((schp->sch_active_slots & __BIT(slot)) == 0) { - log(LOG_WARNING, "%s: unexpected command " - "completion on port %d slot %d\n", - SIISATANAME(sc), chp->ch_channel, slot); - return 0; - } else - goto command_done; - } - - if (pis & PR_PIS_CMDERRR) { - uint32_t ec; - - /* emulate a CRC error by default */ - chp->ch_status = WDCS_ERR; - chp->ch_error = WDCE_CRC; - - ec = PRREAD(sc, PRX(chp->ch_channel, PRO_PCE)); - if (ec <= PR_PCE_DATAFISERROR) { - if (ec != PR_PCE_DATAFISERROR) { - /* read in specific information about error */ - *prbfis = bus_space_read_stream_4( - sc->sc_prt, sc->sc_prh, - PRSX(chp->ch_channel, slot, PRSO_FIS)); - chp->ch_status = fis[2]; - chp->ch_error = fis[3]; - } - siisata_reinit_port(chp); - } else { - /* okay, we have a "Fatal Error" */ - siisata_device_reset(chp); - } - goto command_done; - } - return 0; - -command_done: chp->ch_flags &= ~ATACH_IRQ_WAIT; if (xfer->c_flags & C_TIMEOU) ata_c->flags |= AT_TIMEOU; @@ -841,7 +898,7 @@ chp->ch_queue->active_xfer = NULL; - if (pis) { + { ata_c->r_head = 0; ata_c->r_count = 0; ata_c->r_sector = 0; @@ -937,8 +994,7 @@ struct siisata_prb *prb; struct ata_bio *ata_bio = xfer->c_cmd; int slot = SIISATA_NON_NCQ_SLOT; - int nblks, i; - uint8_t *fis; + int i; SIISATA_DEBUG_PRINT( ("%s: %s port %d, slot %d\n", @@ -947,37 +1003,11 @@ prb = schp->sch_prb[slot]; memset(prb, 0, sizeof(struct siisata_prb)); - fis = prb->prb_fis; - nblks = xfer->c_bcount / ata_bio->lp->d_secsize; - - /* XXX probably needs to be some common FIS-related code */ - fis[0] = 0x27; /* host to device */ - fis[1] = 0x80; /* command FIS (also, PMP) */ - if (ata_bio->flags & ATA_LBA48) { - fis[2] = (ata_bio->flags & ATA_READ) ? - WDCC_READDMA_EXT : WDCC_WRITEDMA_EXT; - } else { - fis[2] = - (ata_bio->flags & ATA_READ) ? WDCC_READDMA : WDCC_WRITEDMA; - } - fis[4] = ata_bio->blkno & 0xff; - fis[5] = (ata_bio->blkno >> 8) & 0xff; - fis[6] = (ata_bio->blkno >> 16) & 0xff; - if (ata_bio->flags & ATA_LBA48) { - fis[7] = WDSD_LBA; - fis[8] = (ata_bio->blkno >> 24) & 0xff; - fis[9] = (ata_bio->blkno >> 32) & 0xff; - fis[10] = (ata_bio->blkno >> 40) & 0xff; - } else { - fis[7] = ((ata_bio->blkno >> 24) & 0x0f) | WDSD_LBA; - } - fis[12] = nblks & 0xff; - fis[13] = (ata_bio->flags & ATA_LBA48) ? - ((nblks >> 8) & 0xff) : 0; - fis[15] = WDCTL_4BIT; + satafis_rhd_construct_bio(xfer, prb->prb_fis); memset(prb->prb_atapi, 0, sizeof(prb->prb_atapi)); + if (siisata_dma_setup(chp, slot, ata_bio->databuf, ata_bio->bcount, (ata_bio->flags & ATA_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)) { ata_bio->error = ERR_DMA; @@ -988,27 +1018,26 @@ if (xfer->c_flags & C_POLL) { /* polled command, disable interrupts */ - GRWRITE(sc, GR_GC, - GRREAD(sc, GR_GC) & ~(GR_GC_PXIE(chp->ch_channel))); + prb->prb_control = htole16(PRB_CF_INTERRUPT_MASK); } siisata_activate_prb(schp, slot); - if ((xfer->c_flags & C_POLL) == 0) { + if ((ata_bio->flags & ATA_POLL) == 0) { chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */ callout_reset(&chp->ch_callout, mstohz(ATA_DELAY), siisata_timeout, chp); goto out; } + /* + * polled command + */ for (i = 0; i < ATA_DELAY / 10; i++) { if (ata_bio->flags & ATA_ITSDONE) break; - siisata_intr_port(sc, schp); - if (ata_bio->flags & ATA_NOSLEEP) - DELAY(10000); - else - tsleep(&xfer, PRIBIO, "siipl", mstohz(10)); + siisata_intr_port(schp); + DELAY(10000); } GRWRITE(sc, GR_GC, GRREAD(sc, GR_GC) | GR_GC_PXIE(chp->ch_channel)); @@ -1057,66 +1086,15 @@ struct siisata_channel *schp = (struct siisata_channel *)chp; struct ata_bio *ata_bio = xfer->c_cmd; int drive = xfer->c_drive; - uint32_t pss, pis; - uint8_t fis[4]; - uint32_t *prbfis = (void *)fis; - - pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS)); - - if (pis & PR_PIS_CMDCMPL) { - /* get slot status, clearing completion interrupt */ - pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)); - /* is this expected? */ - if ((schp->sch_active_slots & __BIT(slot)) == 0) { - log(LOG_WARNING, "%s: unexpected command " - "completion on port %d slot %d\n", - SIISATANAME(sc), chp->ch_channel, slot); - return 0; - } else { - if (ata_bio->flags & ATA_READ) - ata_bio->bcount -= PRREAD(sc, - PRSX(chp->ch_channel, slot, PRSO_RTC)); - else - ata_bio->bcount = 0; - /* XXX is reseting these right? */ - chp->ch_status = 0; - chp->ch_error = 0; - ata_bio->error = 0; - goto command_done; - } - } - - if (pis & PR_PIS_CMDERRR) { - uint32_t ec; - - /* emulate a CRC error by default */ - chp->ch_status = WDCS_ERR; - chp->ch_error = WDCE_CRC; - - ec = PRREAD(sc, PRX(chp->ch_channel, PRO_PCE)); - if (ec <= PR_PCE_DATAFISERROR) { - if (ec != PR_PCE_DATAFISERROR) { - /* read in specific information about error */ - *prbfis = bus_space_read_stream_4( - sc->sc_prt, sc->sc_prh, - PRSX(chp->ch_channel, slot, PRSO_FIS)); - chp->ch_status = fis[2]; - chp->ch_error = fis[3]; - } - siisata_reinit_port(chp); - } else { - /* okay, we have a "Fatal Error" */ - siisata_device_reset(chp); - } - goto command_done; - } - return 0; - -command_done: schp->sch_active_slots &= ~__BIT(slot); chp->ch_flags &= ~ATACH_IRQ_WAIT; - callout_stop(&chp->ch_callout); + if (xfer->c_flags & C_TIMEOU) { + ata_bio->error = TIMEOUT; + } else { + callout_stop(&chp->ch_callout); + ata_bio->error = NOERROR; + } chp->ch_queue->active_xfer = NULL; @@ -1142,11 +1120,15 @@ } else if (chp->ch_status & WDCS_CORR) ata_bio->flags |= ATA_CORR; - SIISATA_DEBUG_PRINT(("%s: %s bcount: %ld\n", SIISATANAME(sc), + SIISATA_DEBUG_PRINT(("%s: %s bcount: %ld", SIISATANAME(sc), __func__, ata_bio->bcount), DEBUG_XFERS); - + if ((ata_bio->flags & ATA_READ) || (ata_bio->error == NOERROR)) + ata_bio->bcount -= PRREAD(sc, + PRSX(chp->ch_channel, slot, PRSO_RTC)); + SIISATA_DEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS); + if (ata_bio->flags & ATA_POLL) + return 1; (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc); - atastart(chp); return 0; } @@ -1410,7 +1392,7 @@ if (periph == NULL) { aprint_error_dev(sc->sc_dev, "%s: unable to allocate periph for " - "channel %d drive %d", __func__, + "channel %d drive %d\n", __func__, chp->ch_channel, target); return; } @@ -1556,7 +1538,6 @@ int slot = SIISATA_NON_NCQ_SLOT; int i; - uint8_t *fis; SIISATA_DEBUG_PRINT( ("%s: %s:%d:%d, scsi flags 0x%x\n", __func__, SIISATANAME(sc), chp->ch_channel, @@ -1565,7 +1546,7 @@ prbp = schp->sch_prb[slot]; memset(prbp, 0, sizeof(struct siisata_prb)); - fis = prbp->prb_fis; + /* fill in direction for ATAPI command */ if ((sc_xfer->xs_control & XS_CTL_DATA_IN)) @@ -1573,13 +1554,7 @@ if ((sc_xfer->xs_control & XS_CTL_DATA_OUT)) prbp->prb_control |= htole16(PRB_CF_PACKET_WRITE); - /* XXX probably needs to be some common FIS-related code */ - fis[0] = 0x27; /* host to device */ - fis[1] = 0x80; /* command FIS (and PMP) */ - fis[2] = ATAPI_PKT_CMD; - fis[3] = (xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 0; - fis[7] = WDSD_IBM; - fis[15] = WDCTL_4BIT; + satafis_rhd_construct_atapi(xfer, prbp->prb_fis); /* copy over ATAPI command */ memcpy(prbp->prb_atapi, sc_xfer->cmd, sc_xfer->cmdlen); @@ -1595,8 +1570,7 @@ if (xfer->c_flags & C_POLL) { /* polled command, disable interrupts */ - GRWRITE(sc, GR_GC, - GRREAD(sc, GR_GC) & ~(GR_GC_PXIE(chp->ch_channel))); + prbp->prb_control = htole16(PRB_CF_INTERRUPT_MASK); } siisata_activate_prb(schp, slot); @@ -1607,13 +1581,14 @@ siisata_timeout, chp); goto out; } + /* * polled command */ for (i = 0; i < ATA_DELAY / 10; i++) { if (sc_xfer->xs_status & XS_STS_DONE) break; - siisata_intr_port(sc, schp); + siisata_intr_port(schp); DELAY(10000); } if ((sc_xfer->xs_status & XS_STS_DONE) == 0) { @@ -1635,128 +1610,55 @@ struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac; struct siisata_channel *schp = (struct siisata_channel *)chp; struct scsipi_xfer *sc_xfer = xfer->c_cmd; - uint8_t fis[4]; - uint32_t *prbfis = (void *)fis; - uint32_t pss, pis; SIISATA_DEBUG_PRINT( ("%s: %s()\n", SIISATANAME(sc), __func__), DEBUG_INTR); - if ((xfer->c_flags & C_TIMEOU) != 0) { - sc_xfer->error = XS_TIMEOUT; - siisata_atapi_reset(chp, xfer); - return 1; - } - - pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS)); - - if (pis & PR_PIS_CMDCMPL) { - /* get slot status, clearing completion interrupt */ - pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)); - /* is this expected? */ - if ((schp->sch_active_slots & __BIT(slot)) == 0) { - log(LOG_WARNING, "%s: unexpected command " - "completion on port %d slot %d\n", - SIISATANAME(sc), chp->ch_channel, slot); - return 0; - } - } - - if (pis & PR_PIS_CMDERRR) { - uint32_t ec; - - ec = PRREAD(sc, PRX(chp->ch_channel, PRO_PCE)); - if (ec <= PR_PCE_DATAFISERROR) { - if (ec != PR_PCE_DATAFISERROR) { - /* read in specific information about error */ - *prbfis = bus_space_read_stream_4( - sc->sc_prt, sc->sc_prh, - PRSX(chp->ch_channel, slot, PRSO_FIS)); - if (ec == PR_PCE_DEVICEERROR) { - /* error code 1 implies * - * WDCS_ERR in fis[2] */ - sc_xfer->error = XS_SHORTSENSE; - sc_xfer->sense.atapi_sense = fis[3]; - } - } - siisata_reinit_port(chp); - } else { - /* okay, we have a "Fatal Error" */ - siisata_device_reset(chp); - } - } - - chp->ch_flags &= ~ATACH_IRQ_WAIT; - siisata_atapi_done(chp, xfer, slot); - return 1; -} - -void -siisata_atapi_done(struct ata_channel *chp, struct ata_xfer *xfer, int slot) -{ - struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac; - struct siisata_channel *schp = (struct siisata_channel *)chp; - struct scsipi_xfer *sc_xfer = xfer->c_cmd; - - SIISATA_DEBUG_PRINT(("%s: %s:%d:%d: flags 0x%x\n", __func__, - device_xname(chp->ch_atac->atac_dev), - chp->ch_channel, xfer->c_drive, - (unsigned int)xfer->c_flags), DEBUG_XFERS); - /* this comamnd is not active any more */ schp->sch_active_slots &= ~__BIT(slot); - - if (sc_xfer->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { - bus_dmamap_sync(sc->sc_dmat, schp->sch_datad[slot], 0, - schp->sch_datad[slot]->dm_mapsize, - (sc_xfer->xs_control & XS_CTL_DATA_IN) ? - BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sc_dmat, schp->sch_datad[slot]); - } - - xfer->c_bcount -= sc_xfer->datalen; - sc_xfer->resid = xfer->c_bcount; - - if (xfer->c_bcount != 0) { - SIISATA_DEBUG_PRINT(("%s: bcount value is " - "%d after io\n", __func__, xfer->c_bcount), DEBUG_XFERS); - } -#ifdef DIAGNOSTIC - if (xfer->c_bcount < 0) { - log(LOG_WARNING, "%s(): bcount value " - "is %d after io\n", __func__, xfer->c_bcount); + chp->ch_flags &= ~ATACH_IRQ_WAIT; + if (xfer->c_flags & C_TIMEOU) { + sc_xfer->error = XS_TIMEOUT; + } else { + callout_stop(&chp->ch_callout); + sc_xfer->error = XS_NOERROR; } -#endif + bus_dmamap_sync(sc->sc_dmat, schp->sch_datad[slot], 0, + schp->sch_datad[slot]->dm_mapsize, + (sc_xfer->xs_control & XS_CTL_DATA_IN) ? + BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, schp->sch_datad[slot]); if (chp->ch_drive[xfer->c_drive].drive_flags & DRIVE_WAITDRAIN) { siisata_atapi_kill_xfer(chp, xfer, KILL_GONE); chp->ch_drive[xfer->c_drive].drive_flags &= ~DRIVE_WAITDRAIN; wakeup(&chp->ch_queue->active_xfer); - return; + return 0; /* XXX verify */ } - /* vvv is this in the right order? ^^^ */ - - callout_stop(&chp->ch_callout); chp->ch_queue->active_xfer = NULL; ata_free_xfer(chp, xfer); - SIISATA_DEBUG_PRINT(("%s: scsipi_done\n", __func__), DEBUG_XFERS); + sc_xfer->resid = sc_xfer->datalen; + sc_xfer->resid -= PRREAD(sc, PRSX(chp->ch_channel, slot, PRSO_RTC)); + SIISATA_DEBUG_PRINT(("%s: %s datalen %d resid %d\n", SIISATANAME(sc), + __func__, sc_xfer->datalen, sc_xfer->resid), DEBUG_XFERS); + if ((chp->ch_status & WDCS_ERR) && + ((sc_xfer->xs_control & XS_CTL_REQSENSE) == 0 || + sc_xfer->resid == sc_xfer->datalen)) { + sc_xfer->error = XS_SHORTSENSE; + sc_xfer->sense.atapi_sense = chp->ch_error; + if ((sc_xfer->xs_periph->periph_quirks & + PQUIRK_NOSENSE) == 0) { + /* request sense */ + sc_xfer->error = XS_BUSY; + sc_xfer->status = SCSI_CHECK; + } + } scsipi_done(sc_xfer); - SIISATA_DEBUG_PRINT(("atastart from %s, flags 0x%x\n", __func__, - chp->ch_flags), DEBUG_XFERS); atastart(chp); - return; + return 0; /* XXX verify */ } -void -siisata_atapi_reset(struct ata_channel *chp, struct ata_xfer *xfer) -{ - struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive]; - drvp->state = 0; - chp->ch_flags &= ~ATACH_IRQ_WAIT; - siisata_atapi_done(chp, xfer, SIISATA_NON_NCQ_SLOT); - return; -} #endif /* NATAPIBUS */ Index: src/sys/dev/ic/siisatareg.h diff -u src/sys/dev/ic/siisatareg.h:1.2 src/sys/dev/ic/siisatareg.h:1.2.4.1 --- src/sys/dev/ic/siisatareg.h:1.2 Mon Sep 8 23:36:54 2008 +++ src/sys/dev/ic/siisatareg.h Mon Sep 28 00:17:28 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: siisatareg.h,v 1.2 2008/09/08 23:36:54 gmcgarry Exp $ */ +/* $NetBSD: siisatareg.h,v 1.2.4.1 2009/09/28 00:17:28 snj Exp $ */ /* Id: siisatareg.h,v 1.10 2008/05/21 15:51:36 jakllsch Exp */ /*- @@ -33,7 +33,7 @@ /* the SiI3124 has 4 ports, all others so far have less */ #define SIISATA_MAX_PORTS 4 -/* the so far all parts have a full complement of slots */ +/* all parts have a full complement of slots (so far) */ #define SIISATA_MAX_SLOTS 31 /* structures */ Index: src/sys/dev/ic/siisatavar.h diff -u src/sys/dev/ic/siisatavar.h:1.2 src/sys/dev/ic/siisatavar.h:1.2.4.1 --- src/sys/dev/ic/siisatavar.h:1.2 Sun Sep 14 21:53:49 2008 +++ src/sys/dev/ic/siisatavar.h Mon Sep 28 00:17:28 2009 @@ -1,5 +1,4 @@ -/* $NetBSD: siisatavar.h,v 1.2 2008/09/14 21:53:49 jakllsch Exp $ */ -/* Id: siisatavar.h,v 1.15 2008/05/22 13:48:54 jakllsch Exp */ +/* $NetBSD: siisatavar.h,v 1.2.4.1 2009/09/28 00:17:28 snj Exp $ */ /* from ahcisatavar.h */ @@ -84,8 +83,10 @@ struct atac_softc sc_atac; bus_space_tag_t sc_grt; bus_space_handle_t sc_grh; + bus_size_t sc_grs; bus_space_tag_t sc_prt; bus_space_handle_t sc_prh; + bus_size_t sc_prs; bus_dma_tag_t sc_dmat; struct ata_channel *sc_chanarray[SIISATA_MAX_PORTS]; @@ -121,9 +122,9 @@ #define SIISATA_NON_NCQ_SLOT 27 -void siisata_attach(struct siisata_softc *); -int siisata_intr(void *); - +void siisata_attach(struct siisata_softc *); +int siisata_detach(struct siisata_softc *, int); void siisata_resume(struct siisata_softc *); +int siisata_intr(void *); #endif /* !_IC_SIISATAVAR_H_ */ Index: src/sys/dev/pci/files.pci diff -u src/sys/dev/pci/files.pci:1.308.2.3 src/sys/dev/pci/files.pci:1.308.2.4 --- src/sys/dev/pci/files.pci:1.308.2.3 Sat Sep 26 19:52:09 2009 +++ src/sys/dev/pci/files.pci Mon Sep 28 00:17:28 2009 @@ -1,4 +1,4 @@ -# $NetBSD: files.pci,v 1.308.2.3 2009/09/26 19:52:09 snj Exp $ +# $NetBSD: files.pci,v 1.308.2.4 2009/09/28 00:17:28 snj Exp $ # # Config file and device description for machine-independent PCI code. # Included by ports that need it. Requires that the SCSI files be @@ -955,7 +955,7 @@ # Silicon Image SteelVine SATA-II controllers define siisata file dev/ic/siisata.c atapibus & atabus & siisata -device siisata: ata, ata_dma, ata_udma, sata, siisata +device siisata: ata, ata_dma, ata_udma, sata, sata_fis, siisata attach siisata at pci with siisata_pci file dev/pci/siisata_pci.c siisata_pci Index: src/sys/dev/pci/siisata_pci.c diff -u src/sys/dev/pci/siisata_pci.c:1.1.14.1 src/sys/dev/pci/siisata_pci.c:1.1.14.2 --- src/sys/dev/pci/siisata_pci.c:1.1.14.1 Fri Jan 9 03:40:44 2009 +++ src/sys/dev/pci/siisata_pci.c Mon Sep 28 00:17:28 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: siisata_pci.c,v 1.1.14.1 2009/01/09 03:40:44 snj Exp $ */ +/* $NetBSD: siisata_pci.c,v 1.1.14.2 2009/09/28 00:17:28 snj Exp $ */ /* Id: siisata_pci.c,v 1.11 2008/05/21 16:20:11 jakllsch Exp */ /* @@ -76,10 +76,12 @@ struct siisata_softc si_sc; pci_chipset_tag_t sc_pc; pcitag_t sc_pcitag; + void * sc_ih; }; static int siisata_pci_match(device_t, cfdata_t, void *); static void siisata_pci_attach(device_t, device_t, void *); +static int siisata_pci_detach(device_t, int); static bool siisata_pci_resume(device_t PMF_FN_PROTO); static const struct siisata_pci_product { @@ -108,7 +110,7 @@ }; CFATTACH_DECL_NEW(siisata_pci, sizeof(struct siisata_pci_softc), - siisata_pci_match, siisata_pci_attach, NULL, NULL); + siisata_pci_match, siisata_pci_attach, siisata_pci_detach, NULL); static const struct siisata_pci_product * siisata_pci_lookup(const struct pci_attach_args * pa) @@ -134,20 +136,6 @@ return 0; } -static bool -siisata_pci_resume(device_t dv PMF_FN_ARGS) -{ - struct siisata_pci_softc *psc = device_private(dv); - struct siisata_softc *sc = &psc->si_sc; - int s; - - s = splbio(); - siisata_resume(sc); - splx(s); - - return true; -} - static void siisata_pci_attach(device_t parent, device_t self, void *aux) { @@ -156,10 +144,9 @@ struct siisata_softc *sc = &psc->si_sc; char devinfo[256]; const char *intrstr; - pci_intr_handle_t intrhandle; pcireg_t csr, memtype; const struct siisata_pci_product *spp; - void *ih; + pci_intr_handle_t intrhandle; bus_space_tag_t memt; bus_space_handle_t memh; uint32_t gcreg; @@ -193,6 +180,7 @@ if (memh_valid) { sc->sc_grt = memt; sc->sc_grh = memh; + sc->sc_grs = grsize; } else { aprint_error("%s: unable to map device global registers\n", SIISATANAME(sc)); @@ -217,6 +205,7 @@ if (memh_valid) { sc->sc_prt = memt; sc->sc_prh = memh; + sc->sc_prs = prsize; } else { bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize); aprint_error("%s: unable to map device port registers\n", @@ -241,9 +230,9 @@ return; } intrstr = pci_intr_string(pa->pa_pc, intrhandle); - ih = pci_intr_establish(pa->pa_pc, intrhandle, + psc->sc_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO, siisata_intr, sc); - if (ih == NULL) { + if (psc->sc_ih == NULL) { bus_space_unmap(sc->sc_grt, sc->sc_grh, grsize); bus_space_unmap(sc->sc_prt, sc->sc_prh, prsize); aprint_error("%s: couldn't establish interrupt" @@ -305,3 +294,37 @@ aprint_error_dev(self, "couldn't establish power handler\n"); } +static int +siisata_pci_detach(device_t dv, int flags) +{ + struct siisata_pci_softc *psc = device_private(dv); + struct siisata_softc *sc = &psc->si_sc; + int rv; + + rv = siisata_detach(sc, flags); + if (rv) + return rv; + + if (psc->sc_ih != NULL) { + pci_intr_disestablish(psc->sc_pc, psc->sc_ih); + } + + bus_space_unmap(sc->sc_prt, sc->sc_prh, sc->sc_prs); + bus_space_unmap(sc->sc_grt, sc->sc_grh, sc->sc_grs); + + return 0; +} + +static bool +siisata_pci_resume(device_t dv PMF_FN_ARGS) +{ + struct siisata_pci_softc *psc = device_private(dv); + struct siisata_softc *sc = &psc->si_sc; + int s; + + s = splbio(); + siisata_resume(sc); + splx(s); + + return true; +}