Module Name: src
Committed By: jakllsch
Date: Wed Jun 17 04:37:57 UTC 2009
Modified Files:
src/sys/dev/ic: siisata.c siisatareg.h siisatavar.h
src/sys/dev/pci: files.pci siisata_pci.c
Log Message:
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.3 src/sys/dev/ic/siisata.c src/sys/dev/ic/siisatareg.h \
src/sys/dev/ic/siisatavar.h
cvs rdiff -u -r1.314 -r1.315 src/sys/dev/pci/files.pci
cvs rdiff -u -r1.2 -r1.3 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.3
--- src/sys/dev/ic/siisata.c:1.2 Sun Sep 14 21:53:49 2008
+++ src/sys/dev/ic/siisata.c Wed Jun 17 04:37:57 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.2 2008/09/14 21:53:49 jakllsch Exp $ */
+/* $NetBSD: siisata.c,v 1.3 2009/06/17 04:37:57 jakllsch 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.3
--- src/sys/dev/ic/siisatareg.h:1.2 Mon Sep 8 23:36:54 2008
+++ src/sys/dev/ic/siisatareg.h Wed Jun 17 04:37:57 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: siisatareg.h,v 1.2 2008/09/08 23:36:54 gmcgarry Exp $ */
+/* $NetBSD: siisatareg.h,v 1.3 2009/06/17 04:37:57 jakllsch 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.3
--- src/sys/dev/ic/siisatavar.h:1.2 Sun Sep 14 21:53:49 2008
+++ src/sys/dev/ic/siisatavar.h Wed Jun 17 04:37:57 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.3 2009/06/17 04:37:57 jakllsch 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.314 src/sys/dev/pci/files.pci:1.315
--- src/sys/dev/pci/files.pci:1.314 Tue Apr 21 03:00:29 2009
+++ src/sys/dev/pci/files.pci Wed Jun 17 04:37:57 2009
@@ -1,4 +1,4 @@
-# $NetBSD: files.pci,v 1.314 2009/04/21 03:00:29 nonaka Exp $
+# $NetBSD: files.pci,v 1.315 2009/06/17 04:37:57 jakllsch Exp $
#
# Config file and device description for machine-independent PCI code.
# Included by ports that need it. Requires that the SCSI files be
@@ -959,7 +959,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.2 src/sys/dev/pci/siisata_pci.c:1.3
--- src/sys/dev/pci/siisata_pci.c:1.2 Tue Dec 16 02:46:47 2008
+++ src/sys/dev/pci/siisata_pci.c Wed Jun 17 04:37:57 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata_pci.c,v 1.2 2008/12/16 02:46:47 jakllsch Exp $ */
+/* $NetBSD: siisata_pci.c,v 1.3 2009/06/17 04:37:57 jakllsch 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;
+}