summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ic/ami.c623
-rw-r--r--sys/dev/ic/amivar.h13
-rw-r--r--sys/dev/pci/ami_pci.c3
3 files changed, 365 insertions, 274 deletions
diff --git a/sys/dev/ic/ami.c b/sys/dev/ic/ami.c
index b188766fc6e..54a838853d3 100644
--- a/sys/dev/ic/ami.c
+++ b/sys/dev/ic/ami.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ami.c,v 1.187 2008/04/10 06:39:00 dlg Exp $ */
+/* $OpenBSD: ami.c,v 1.188 2008/10/28 11:43:10 marco Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -66,15 +66,10 @@
#include <scsi/scsi_disk.h>
#include <scsi/scsiconf.h>
+#include <dev/biovar.h>
#include <dev/ic/amireg.h>
#include <dev/ic/amivar.h>
-
-#if NBIO > 0
-#include <dev/biovar.h>
-#include <sys/sensors.h>
-#endif
-
#ifdef AMI_DEBUG
#define AMI_DPRINTF(m,a) do { if (ami_debug & (m)) printf a; } while (0)
#define AMI_D_CMD 0x0001
@@ -83,9 +78,9 @@
#define AMI_D_DMA 0x0008
#define AMI_D_IOCTL 0x0010
int ami_debug = 0
- | AMI_D_CMD
- | AMI_D_INTR
- | AMI_D_MISC
+/* | AMI_D_CMD */
+/* | AMI_D_INTR */
+/* | AMI_D_MISC */
/* | AMI_D_DMA */
/* | AMI_D_IOCTL */
;
@@ -119,6 +114,8 @@ struct scsi_device ami_raw_dev = {
NULL, NULL, NULL, NULL
};
+void ami_remove_runq(struct ami_ccb *);
+void ami_insert_runq(struct ami_ccb *);
struct ami_ccb *ami_get_ccb(struct ami_softc *);
void ami_put_ccb(struct ami_ccb *);
@@ -146,6 +143,7 @@ void ami_done_flush(struct ami_softc *, struct ami_ccb *);
void ami_done_sysflush(struct ami_softc *, struct ami_ccb *);
void ami_stimeout(void *);
+void ami_done_dummy(struct ami_softc *, struct ami_ccb *);
void ami_done_ioctl(struct ami_softc *, struct ami_ccb *);
void ami_done_init(struct ami_softc *, struct ami_ccb *);
@@ -157,6 +155,10 @@ int ami_load_ptmem(struct ami_softc*, struct ami_ccb *,
#if NBIO > 0
int ami_mgmt(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t,
u_int8_t, size_t, void *);
+int ami_drv_pt(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t *,
+ int, int, void *);
+int ami_drv_readcap(struct ami_softc *, u_int8_t, u_int8_t,
+ daddr64_t *);
int ami_drv_inq(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t,
void *);
int ami_ioctl(struct device *, u_long, caddr_t);
@@ -178,11 +180,34 @@ void ami_refresh_sensors(void *);
#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
+void
+ami_remove_runq(struct ami_ccb *ccb)
+{
+ splassert(IPL_BIO);
+
+ TAILQ_REMOVE(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link);
+ if (TAILQ_EMPTY(&ccb->ccb_sc->sc_ccb_runq)) {
+ ccb->ccb_sc->sc_drained = 1;
+ wakeup(ccb->ccb_sc);
+ }
+}
+
+void
+ami_insert_runq(struct ami_ccb *ccb)
+{
+ splassert(IPL_BIO);
+
+ ccb->ccb_sc->sc_drained = 0;
+ TAILQ_INSERT_TAIL(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link);
+}
+
struct ami_ccb *
ami_get_ccb(struct ami_softc *sc)
{
struct ami_ccb *ccb;
+ splassert(IPL_BIO);
+
ccb = TAILQ_FIRST(&sc->sc_ccb_freeq);
if (ccb) {
TAILQ_REMOVE(&sc->sc_ccb_freeq, ccb, ccb_link);
@@ -197,6 +222,8 @@ ami_put_ccb(struct ami_ccb *ccb)
{
struct ami_softc *sc = ccb->ccb_sc;
+ splassert(IPL_BIO);
+
ccb->ccb_state = AMI_CCB_FREE;
ccb->ccb_xs = NULL;
ccb->ccb_flags = 0;
@@ -346,7 +373,12 @@ ami_alloc_ccbs(struct ami_softc *sc, int nccbs)
ccb->ccb_sglistpa = htole32(AMIMEM_DVA(sc->sc_ccbmem_am) +
ccb->ccb_offset + sizeof(struct ami_passthrough));
- ami_put_ccb(ccb);
+ /* override last command for management */
+ if (i == nccbs - 1) {
+ ccb->ccb_cmd.acc_id = 0xfe;
+ sc->sc_mgmtccb = ccb;
+ } else
+ ami_put_ccb(ccb);
}
return (0);
@@ -370,6 +402,9 @@ ami_attach(struct ami_softc *sc)
struct ami_ccb iccb;
struct ami_iocmd *cmd;
struct ami_mem *am;
+ struct ami_inquiry *inq;
+ struct ami_fc_einquiry *einq;
+ struct ami_fc_prodinfo *pi;
const char *p;
paddr_t pa;
int s;
@@ -407,10 +442,11 @@ ami_attach(struct ami_softc *sc)
cmd->acc_io.aio_param = AMI_FC_EINQ3_SOLICITED_FULL;
cmd->acc_io.aio_data = pa;
if (ami_poll(sc, &iccb) == 0) {
- struct ami_fc_einquiry *einq = AMIMEM_KVA(am);
- struct ami_fc_prodinfo *pi = AMIMEM_KVA(am);
+ einq = AMIMEM_KVA(am);
+ pi = AMIMEM_KVA(am);
sc->sc_nunits = einq->ain_nlogdrv;
+ sc->sc_drvinscnt = einq->ain_drvinscnt + 1; /* force scan */
ami_copyhds(sc, einq->ain_ldsize, einq->ain_ldprop,
einq->ain_ldstat);
@@ -434,7 +470,7 @@ ami_attach(struct ami_softc *sc)
}
if (sc->sc_maxunits == 0) {
- struct ami_inquiry *inq = AMIMEM_KVA(am);
+ inq = AMIMEM_KVA(am);
cmd->acc_cmd = AMI_EINQUIRY;
cmd->acc_io.aio_channel = 0;
@@ -465,6 +501,7 @@ ami_attach(struct ami_softc *sc)
sc->sc_targets = inq->ain_targets;
sc->sc_memory = inq->ain_ramsize;
sc->sc_maxcmds = inq->ain_maxcmd;
+ sc->sc_drvinscnt = inq->ain_drvinscnt + 1; /* force scan */
p = "target";
}
@@ -495,10 +532,11 @@ ami_attach(struct ami_softc *sc)
ami_freemem(sc, am);
- if (ami_alloc_ccbs(sc, AMI_MAXCMDS) != 0) {
+ if (ami_alloc_ccbs(sc, AMI_MAXCMDS + 1) != 0) {
/* error already printed */
goto free_mbox;
}
+ sc->sc_drained = 1;
/* hack for hp netraid version encoding */
if ('A' <= sc->sc_fwver[2] && sc->sc_fwver[2] <= 'Z' &&
@@ -703,8 +741,10 @@ ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd)
u_int32_t i;
u_int8_t status;
+ splassert(IPL_BIO);
+
if (sc->sc_dis_poll)
- return (1); /* fail */
+ return (-1); /* fail */
i = 0;
while (sc->sc_mbox->acc_busy && (i < AMI_MAX_BUSYWAIT)) {
@@ -713,7 +753,7 @@ ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd)
}
if (sc->sc_mbox->acc_busy) {
AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
- return (EBUSY);
+ return (-1);
}
memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16);
@@ -724,13 +764,13 @@ ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd)
sc->sc_mbox->acc_busy = 1;
sc->sc_mbox->acc_poll = 0;
sc->sc_mbox->acc_ack = 0;
-
sc->sc_mbox->acc_nstat = 0xff;
sc->sc_mbox->acc_status = 0xff;
/* send command to firmware */
ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC));
+ i = 0;
while ((sc->sc_mbox->acc_nstat == 0xff) && (i < AMI_MAX_POLLWAIT)) {
delay(1);
i++;
@@ -739,24 +779,11 @@ ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd)
printf("%s: command not accepted, polling disabled\n",
DEVNAME(sc));
sc->sc_dis_poll = 1;
- return (1);
+ return (-1);
}
- sc->sc_mbox->acc_nstat = 0xff;
-
- while ((sc->sc_mbox->acc_status == 0xff) && (i < AMI_MAX_POLLWAIT)) {
- delay(1);
- i++;
- }
- if (i >= AMI_MAX_POLLWAIT) {
- printf("%s: bad status, polling disabled\n", DEVNAME(sc));
- sc->sc_dis_poll = 1;
- return (1);
- }
- status = sc->sc_mbox->acc_status;
- sc->sc_mbox->acc_status = 0xff;
-
/* poll firmware */
+ i = 0;
while ((sc->sc_mbox->acc_poll != 0x77) && (i < AMI_MAX_POLLWAIT)) {
delay(1);
i++;
@@ -765,15 +792,13 @@ ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd)
printf("%s: firmware didn't reply, polling disabled\n",
DEVNAME(sc));
sc->sc_dis_poll = 1;
- return 1;
+ return (-1);
}
- sc->sc_mbox->acc_poll = 0;
- sc->sc_mbox->acc_ack = 0x77;
-
/* ack */
ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_ACK));
+ i = 0;
while((ami_read(sc, AMI_QIDB) & AMI_QIDB_ACK) &&
(i < AMI_MAX_POLLWAIT)) {
delay(1);
@@ -783,9 +808,15 @@ ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd)
printf("%s: firmware didn't ack the ack, polling disabled\n",
DEVNAME(sc));
sc->sc_dis_poll = 1;
- return (1);
+ return (-1);
}
+ sc->sc_mbox->acc_poll = 0;
+ sc->sc_mbox->acc_ack = 0x77;
+ status = sc->sc_mbox->acc_status;
+ sc->sc_mbox->acc_nstat = 0xff;
+ sc->sc_mbox->acc_status = 0xff;
+
for (i = 0; i < AMI_MAXSTATACK; i++)
sc->sc_mbox->acc_cmplidl[i] = 0xff;
@@ -863,8 +894,10 @@ ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox)
u_int32_t i;
int rv;
+ splassert(IPL_BIO);
+
if (sc->sc_dis_poll)
- return (1); /* fail */
+ return (-1); /* fail */
for (i = 0; i < AMI_MAX_POLLWAIT; i++) {
if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) &
@@ -874,7 +907,7 @@ ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox)
}
if (i >= AMI_MAX_POLLWAIT) {
AMI_DPRINTF(AMI_D_CMD, ("mbox_busy "));
- return (EBUSY);
+ return (-1);
}
memcpy((struct ami_iocmd *)sc->sc_mbox, mbox, 16);
@@ -898,7 +931,7 @@ ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox)
printf("%s: command not accepted, polling disabled\n",
DEVNAME(sc));
sc->sc_dis_poll = 1;
- return (1); /* fail */
+ return (-1);
}
/* wait for interrupt bit */
@@ -912,7 +945,7 @@ ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox)
printf("%s: interrupt didn't arrive, polling disabled\n",
DEVNAME(sc));
sc->sc_dis_poll = 1;
- return (1); /* fail */
+ return (-1);
}
/* write ststus back to firmware */
@@ -939,7 +972,8 @@ ami_start_xs(struct ami_softc *sc, struct ami_ccb *ccb, struct scsi_xfer *xs)
ami_complete(sc, ccb, xs->timeout);
return (COMPLETE);
}
-
+
+ /* XXX way wrong, this timeout needs to be set later */
timeout_add(&xs->stimeout, 61 * hz);
ami_start(sc, ccb);
@@ -974,6 +1008,11 @@ ami_runqueue(struct ami_softc *sc)
{
struct ami_ccb *ccb;
+ splassert(IPL_BIO);
+
+ if (sc->sc_drainio)
+ return;
+
while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) {
if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) {
/* this is now raceable too with other incomming io */
@@ -983,7 +1022,7 @@ ami_runqueue(struct ami_softc *sc)
TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link);
ccb->ccb_state = AMI_CCB_QUEUED;
- TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link);
+ ami_insert_runq(ccb);
}
}
@@ -993,14 +1032,9 @@ ami_poll(struct ami_softc *sc, struct ami_ccb *ccb)
int error;
int s;
- /* XXX this is broken, shall drain IO or consider this
- * a normal completion which can complete async and
- * polled commands until the polled commands completes
- */
-
s = splbio();
error = sc->sc_poll(sc, &ccb->ccb_cmd);
- if (error)
+ if (error == -1)
ccb->ccb_flags |= AMI_CCB_F_ERR;
ccb->ccb_done(sc, ccb);
@@ -1014,7 +1048,7 @@ ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout)
{
struct ami_iocmd mbox;
int i = 0, j, done = 0;
- int s;
+ int s, ready;
s = splbio();
@@ -1025,21 +1059,27 @@ ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout)
while (i < AMI_MAX_BUSYWAIT) {
if (sc->sc_exec(sc, &ccb->ccb_cmd) == 0) {
ccb->ccb_state = AMI_CCB_QUEUED;
- TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link);
+ ami_insert_runq(ccb);
break;
}
-
DELAY(1000);
i++;
}
if (ccb->ccb_state != AMI_CCB_QUEUED)
goto err;
+ /*
+ * Override timeout for PERC3. The first command triggers a chip
+ * reset on the QL12160 chip which causes the firmware to reload.
+ * 30000 is slightly less than double of how long it takes for the
+ * firmware to be up again. After the first two commands the
+ * timeouts are as expected.
+ */
i = 0;
- while (i < timeout) {
+ while (i < 30000 /* timeout */) {
if (sc->sc_done(sc, &mbox) != 0) {
for (j = 0; j < mbox.acc_nstat; j++) {
- int ready = mbox.acc_cmplidl[j];
+ ready = mbox.acc_cmplidl[j];
ami_done(sc, ready, mbox.acc_status);
if (ready == ccb->ccb_cmd.acc_id)
done = 1;
@@ -1054,7 +1094,7 @@ ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout)
if (!done) {
printf("%s: timeout ccb %d\n", DEVNAME(sc),
ccb->ccb_cmd.acc_id);
- TAILQ_REMOVE(&sc->sc_ccb_runq, ccb, ccb_link);
+ ami_remove_runq(ccb);
goto err;
}
@@ -1121,7 +1161,7 @@ ami_done(struct ami_softc *sc, int idx, int status)
ccb->ccb_state = AMI_CCB_READY;
ccb->ccb_status = status;
- TAILQ_REMOVE(&sc->sc_ccb_runq, ccb, ccb_link);
+ ami_remove_runq(ccb);
ccb->ccb_done(sc, ccb);
@@ -1239,6 +1279,11 @@ ami_done_sysflush(struct ami_softc *sc, struct ami_ccb *ccb)
}
void
+ami_done_dummy(struct ami_softc *sc, struct ami_ccb *ccb)
+{
+}
+
+void
ami_done_ioctl(struct ami_softc *sc, struct ami_ccb *ccb)
{
wakeup(ccb);
@@ -1619,7 +1664,9 @@ ami_intr(void *v)
{
struct ami_softc *sc = v;
struct ami_iocmd mbox;
- int i, rv = 0;
+ int i, rv = 0, ready;
+
+ splassert(IPL_BIO);
if (TAILQ_EMPTY(&sc->sc_ccb_runq))
return (0);
@@ -1629,10 +1676,8 @@ ami_intr(void *v)
while ((sc->sc_done)(sc, &mbox)) {
AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat));
for (i = 0; i < mbox.acc_nstat; i++ ) {
- int ready = mbox.acc_cmplidl[i];
-
+ ready = mbox.acc_cmplidl[i];
AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready));
-
if (!ami_done(sc, ready, mbox.acc_status))
rv |= 1;
}
@@ -1706,12 +1751,11 @@ ami_ioctl(struct device *dev, u_long cmd, caddr_t addr)
}
int
-ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page,
- void *inqbuf)
+ami_drv_pt(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t *cmd,
+ int clen, int blen, void *buf)
{
struct ami_ccb *ccb;
struct ami_passthrough *pt;
- struct scsi_inquiry_data *inq = inqbuf;
int error = 0;
int s;
@@ -1731,28 +1775,17 @@ ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page,
ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa;
pt = ccb->ccb_pt;
- memset(pt, 0, sizeof(struct ami_passthrough));
+ memset(pt, 0, sizeof *pt);
pt->apt_channel = ch;
pt->apt_target = tg;
- pt->apt_ncdb = sizeof(struct scsi_inquiry);
+ pt->apt_ncdb = clen;
pt->apt_nsense = sizeof(struct scsi_sense_data);
- pt->apt_datalen = sizeof(struct scsi_inquiry_data);
+ pt->apt_datalen = blen;
pt->apt_data = 0;
- pt->apt_cdb[0] = INQUIRY;
- pt->apt_cdb[1] = 0;
- pt->apt_cdb[2] = 0;
- pt->apt_cdb[3] = 0;
- pt->apt_cdb[4] = sizeof(struct scsi_inquiry_data); /* INQUIRY length */
- pt->apt_cdb[5] = 0;
+ bcopy(cmd, pt->apt_cdb, clen);
- if (page != 0) {
- pt->apt_cdb[1] = SI_EVPD;
- pt->apt_cdb[2] = page;
- }
-
- if (ami_load_ptmem(sc, ccb, inqbuf, sizeof(struct scsi_inquiry_data),
- 1, 0) != 0) {
+ if (ami_load_ptmem(sc, ccb, buf, blen, 1, 0) != 0) {
error = ENOMEM;
goto ptmemerr;
}
@@ -1760,7 +1793,7 @@ ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page,
ami_start(sc, ccb);
while (ccb->ccb_state != AMI_CCB_READY)
- tsleep(ccb, PRIBIO, "ami_drv_inq", 0);
+ tsleep(ccb, PRIBIO, "ami_drv_pt", 0);
bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
@@ -1773,8 +1806,6 @@ ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page,
error = EIO;
else if (pt->apt_scsistat != 0x00)
error = EIO;
- else if ((inq->device & SID_TYPE) != T_DIRECT)
- error = EINVAL;
ptmemerr:
s = splbio();
@@ -1787,6 +1818,78 @@ err:
}
int
+ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page,
+ void *inqbuf)
+{
+ struct scsi_inquiry_data *inq = inqbuf;
+ u_int8_t cdb[6];
+ int error = 0;
+
+ bzero(&cdb, sizeof cdb);
+
+ cdb[0] = INQUIRY;
+ cdb[1] = 0;
+ cdb[2] = 0;
+ cdb[3] = 0;
+ cdb[4] = sizeof(struct scsi_inquiry_data);
+ cdb[5] = 0;
+ if (page != 0) {
+ cdb[1] = SI_EVPD;
+ cdb[2] = page;
+ }
+
+ error = ami_drv_pt(sc, ch, tg, cdb, 6, sizeof *inq, inqbuf);
+ if (error)
+ return (error);
+
+ if ((inq->device & SID_TYPE) != T_DIRECT)
+ error = EINVAL;
+
+ return (error);
+}
+
+int
+ami_drv_readcap(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, daddr64_t *sz)
+{
+ struct scsi_read_cap_data rcd;
+ struct scsi_read_cap_data_16 rcd16;
+ u_int8_t cdb[16];
+ u_int32_t blksz;
+ daddr64_t noblk;
+ int error = 0;
+
+ bzero(&rcd, sizeof rcd);
+ bzero(&cdb, sizeof cdb);
+ cdb[0] = READ_CAPACITY;
+
+ error = ami_drv_pt(sc, ch, tg, cdb, 10, sizeof rcd, &rcd);
+ if (error)
+ return (error);
+
+ noblk = _4btol(rcd.addr);
+ if (noblk == 0xffffffffllu) {
+ /* huge disk */
+ bzero(&rcd16, sizeof rcd16);
+ bzero(&cdb, sizeof cdb);
+ cdb[0] = READ_CAPACITY_16;
+
+ error = ami_drv_pt(sc, ch, tg, cdb, 16, sizeof rcd16, &rcd16);
+ if (error)
+ return (error);
+
+ noblk = _8btol(rcd16.addr);
+ blksz = _4btol(rcd16.length);
+ } else
+ blksz = _4btol(rcd.length);
+
+ if (blksz == 0)
+ blksz = 512;
+ *sz = noblk * blksz;
+
+ return (error);
+}
+
+int
ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
u_int8_t par3, size_t size, void *buffer)
{
@@ -1794,17 +1897,22 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
struct ami_iocmd *cmd;
struct ami_mem *am = NULL;
char *idata = NULL;
- int error = 0;
- int s;
+ int s, error = 0;
rw_enter_write(&sc->sc_lock);
- s = splbio();
- ccb = ami_get_ccb(sc);
- splx(s);
- if (ccb == NULL) {
- error = ENOMEM;
- goto err;
+ if (opcode != AMI_CHSTATE) {
+ s = splbio();
+ ccb = ami_get_ccb(sc);
+ splx(s);
+ if (ccb == NULL) {
+ error = ENOMEM;
+ goto err;
+ }
+ ccb->ccb_done = ami_done_ioctl;
+ } else {
+ ccb = sc->sc_mgmtccb;
+ ccb->ccb_done = ami_done_dummy;
}
if (size) {
@@ -1815,9 +1923,7 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
idata = AMIMEM_KVA(am);
}
- ccb->ccb_done = ami_done_ioctl;
cmd = &ccb->ccb_cmd;
-
cmd->acc_cmd = opcode;
/*
@@ -1837,9 +1943,28 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
cmd->acc_io.aio_data = am ? htole32(AMIMEM_DVA(am)) : 0;
- ami_start(sc, ccb);
- while (ccb->ccb_state != AMI_CCB_READY)
- tsleep(ccb, PRIBIO,"ami_mgmt", 0);
+ if (opcode != AMI_CHSTATE) {
+ ami_start(sc, ccb);
+ while (ccb->ccb_state != AMI_CCB_READY)
+ tsleep(ccb, PRIBIO,"ami_mgmt", 0);
+ } else {
+ /* change state must be run with id 0xfe and MUST be polled */
+ sc->sc_drainio = 1;
+ while (sc->sc_drained != 1)
+ if (tsleep(sc, PRIBIO, "ami_mgmt_drain", hz * 60) ==
+ EWOULDBLOCK) {
+ printf("%s: drain io timeout\n");
+ ccb->ccb_flags |= AMI_CCB_F_ERR;
+ goto restartio;
+ }
+ ami_poll(sc, ccb);
+restartio:
+ /* restart io */
+ s = splbio();
+ sc->sc_drainio = 0;
+ ami_runqueue(sc);
+ splx(s);
+ }
if (ccb->ccb_flags & AMI_CCB_F_ERR)
error = EIO;
@@ -1848,11 +1973,16 @@ ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2,
if (am)
ami_freemem(sc, am);
-
memerr:
- s = splbio();
- ami_put_ccb(ccb);
- splx(s);
+ if (opcode != AMI_CHSTATE) {
+ s = splbio();
+ ami_put_ccb(ccb);
+ splx(s);
+ } else {
+ ccb->ccb_flags = 0;
+ ccb->ccb_state = AMI_CCB_FREE;
+ ccb->ccb_done = NULL;
+ }
err:
rw_exit_write(&sc->sc_lock);
@@ -1863,33 +1993,55 @@ int
ami_ioctl_inq(struct ami_softc *sc, struct bioc_inq *bi)
{
struct ami_big_diskarray *p; /* struct too large for stack */
- char *plist;
- int i, s, t;
- int off;
- int error = 0;
struct scsi_inquiry_data inqbuf;
- u_int8_t ch, tg;
+ struct ami_fc_einquiry einq;
+ int ch, tg;
+ int i, s, t, off;
+ int error = 0, changes = 0;
+
+ if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_EINQ3,
+ AMI_FC_EINQ3_SOLICITED_FULL, 0, sizeof einq, &einq)))
+ return (EINVAL);
+
+ if (einq.ain_drvinscnt == sc->sc_drvinscnt) {
+ /* poke existing known drives to make sure they aren't gone */
+ for(i = 0; i < sc->sc_channels * 16; i++) {
+ if (sc->sc_plist[i] == 0)
+ continue;
+
+ ch = (i & 0xf0) >> 4;
+ tg = i & 0x0f;
+ if (ami_drv_inq(sc, ch, tg, 0, &inqbuf)) {
+ /* drive is gone, force rescan */
+ changes = 1;
+ break;
+ }
+ }
+ if (changes == 0) {
+ bcopy(&sc->sc_bi, bi, sizeof *bi);
+ return (0);
+ }
+ }
+
+ sc->sc_drvinscnt = einq.ain_drvinscnt;
p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT);
if (!p)
return (ENOMEM);
- plist = malloc(AMI_BIG_MAX_PDRIVES, M_DEVBUF, M_NOWAIT|M_ZERO);
- if (!plist) {
- error = ENOMEM;
+ if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p,
+ p))) {
+ error = EINVAL;
goto bail;
}
- if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p,
- p)))
- goto bail2;
+ bzero(sc->sc_plist, sizeof sc->sc_plist);
bi->bi_novol = p->ada_nld;
bi->bi_nodisk = 0;
-
strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev));
- /* do we actually care how many disks we have at this point? */
+ /* count used disks, including failed ones */
for (i = 0; i < p->ada_nld; i++)
for (s = 0; s < p->ald[i].adl_spandepth; s++)
for (t = 0; t < p->ald[i].adl_nstripes; t++) {
@@ -1897,117 +2049,79 @@ ami_ioctl_inq(struct ami_softc *sc, struct bioc_inq *bi)
AMI_MAX_TARGET +
p->ald[i].asp[s].adv[t].add_target;
- if (!plist[off]) {
- plist[off] = 1;
+ /* account for multi raid vol on same disk */
+ if (!sc->sc_plist[off]) {
+ sc->sc_plist[off] = 1;
bi->bi_nodisk++;
}
}
- /*
- * hack warning!
- * Megaraid cards sometimes return a size in the PD structure
- * even though there is no disk in that slot. Work around
- * that by issuing an INQUIRY to determine if there is
- * an actual disk in the slot.
- */
- for(i = 0; i < ((sc->sc_flags & AMI_QUARTZ) ?
- AMI_BIG_MAX_PDRIVES : AMI_MAX_PDRIVES); i++) {
- /* skip claimed drives */
- if (plist[i])
- continue;
+ /* count unsued disks */
+ for(i = 0; i < sc->sc_channels * 16; i++) {
+ if (sc->sc_plist[i])
+ continue; /* skip claimed drives */
- /*
- * poke drive to make sure its there. If it is it is either
- * unused or a hot spare; at this point we dont care which it is
+ /*
+ * hack to invalidate device type, needed for initiator id
+ * on an unconnected channel.
+ * XXX find out if we can determine this differently
*/
- if (p->apd[i].adp_size) {
- ch = (i & 0xf0) >> 4;
- tg = i & 0x0f;
+ memset(&inqbuf, 0xff, sizeof inqbuf);
- if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) {
- bi->bi_novol++;
- bi->bi_nodisk++;
- plist[i] = 1;
- }
- }
+ ch = (i & 0xf0) >> 4;
+ tg = i & 0x0f;
+ if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) {
+ if ((inqbuf.device & SID_TYPE) != T_DIRECT)
+ continue;
+ bi->bi_novol++;
+ bi->bi_nodisk++;
+ sc->sc_plist[i] = 2;
+ } else
+ sc->sc_plist[i] = 0;
}
-bail2:
- free(plist, M_DEVBUF);
+ bcopy(bi, &sc->sc_bi, sizeof sc->sc_bi);
+ error = 0;
bail:
free(p, M_DEVBUF);
-
return (error);
}
int
ami_vol(struct ami_softc *sc, struct bioc_vol *bv, struct ami_big_diskarray *p)
{
- struct scsi_inquiry_data inqbuf;
- char *plist;
- int i, s, t, off;
- int ld = p->ada_nld, error = EINVAL;
- u_int8_t ch, tg;
+ int i, ld = p->ada_nld, error = EINVAL;
- plist = malloc(AMI_BIG_MAX_PDRIVES, M_DEVBUF, M_NOWAIT|M_ZERO);
- if (!plist)
- return (ENOMEM);
-
- /* setup plist */
- for (i = 0; i < p->ada_nld; i++)
- for (s = 0; s < p->ald[i].adl_spandepth; s++)
- for (t = 0; t < p->ald[i].adl_nstripes; t++) {
- off = p->ald[i].asp[s].adv[t].add_channel *
- AMI_MAX_TARGET +
- p->ald[i].asp[s].adv[t].add_target;
-
- if (!plist[off])
- plist[off] = 1;
- }
-
- for(i = 0; i < ((sc->sc_flags & AMI_QUARTZ) ?
- AMI_BIG_MAX_PDRIVES : AMI_MAX_PDRIVES); i++) {
- /* skip claimed drives */
- if (plist[i])
+ for(i = 0; i < sc->sc_channels * 16; i++) {
+ /* skip claimed/unused drives */
+ if (sc->sc_plist[i] != 2)
continue;
- /*
- * poke drive to make sure its there. If it is it is either
- * unused or a hot spare; at this point we dont care which it is
- */
- if (p->apd[i].adp_size) {
- ch = (i & 0xf0) >> 4;
- tg = i & 0x0f;
+ /* are we it? */
+ if (ld != bv->bv_volid) {
+ ld++;
+ continue;
+ }
- if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) {
- if (ld != bv->bv_volid) {
- ld++;
- continue;
- }
+ bv->bv_status = BIOC_SVONLINE;
+ bv->bv_size = (u_quad_t)p->apd[i].adp_size *
+ (u_quad_t)512;
+ bv->bv_nodisk = 1;
+ strlcpy(bv->bv_dev,
+ sc->sc_hdr[bv->bv_volid].dev,
+ sizeof(bv->bv_dev));
+
+ if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE
+ && p->apd[i].adp_type == 0)
+ bv->bv_level = -1;
+ else
+ bv->bv_level = -2;
- bv->bv_status = BIOC_SVONLINE;
- bv->bv_size = (u_quad_t)p->apd[i].adp_size *
- (u_quad_t)512;
- bv->bv_nodisk = 1;
- strlcpy(bv->bv_dev,
- sc->sc_hdr[bv->bv_volid].dev,
- sizeof(bv->bv_dev));
-
- if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE
- && p->apd[i].adp_type == 0)
- bv->bv_level = -1;
- else
- bv->bv_level = -2;
-
- error = 0;
- goto bail;
- }
- }
+ error = 0;
+ goto bail;
}
bail:
- free(plist, M_DEVBUF);
-
return (error);
}
@@ -2015,75 +2129,48 @@ int
ami_disk(struct ami_softc *sc, struct bioc_disk *bd,
struct ami_big_diskarray *p)
{
+ char vend[8+16+4+1];
+ char ser[32 + 1];
struct scsi_inquiry_data inqbuf;
struct scsi_vpd_serial vpdbuf;
- char *plist;
- int i, s, t, off;
- int ld = p->ada_nld, error = EINVAL;
+ int i, ld = p->ada_nld, error = EINVAL;
u_int8_t ch, tg;
+ daddr64_t sz = 0;
- plist = malloc(AMI_BIG_MAX_PDRIVES, M_DEVBUF, M_NOWAIT|M_ZERO);
- if (!plist)
- return (ENOMEM);
-
- /* setup plist */
- for (i = 0; i < p->ada_nld; i++)
- for (s = 0; s < p->ald[i].adl_spandepth; s++)
- for (t = 0; t < p->ald[i].adl_nstripes; t++) {
- off = p->ald[i].asp[s].adv[t].add_channel *
- AMI_MAX_TARGET +
- p->ald[i].asp[s].adv[t].add_target;
-
- if (!plist[off])
- plist[off] = 1;
- }
-
- for(i = 0; i < ((sc->sc_flags & AMI_QUARTZ) ?
- AMI_BIG_MAX_PDRIVES : AMI_MAX_PDRIVES); i++) {
- char vend[8+16+4+1];
-
- /* skip claimed drives */
- if (plist[i])
+ for(i = 0; i < sc->sc_channels * 16; i++) {
+ /* skip claimed/unused drives */
+ if (sc->sc_plist[i] != 2)
continue;
- /* no size no disk, most of the times */
- if (!p->apd[i].adp_size)
+ /* are we it? */
+ if (ld != bd->bd_volid) {
+ ld++;
continue;
+ }
ch = (i & 0xf0) >> 4;
tg = i & 0x0f;
-
- /*
- * poke drive to make sure its there. If it is it is either
- * unused or a hot spare; at this point we dont care which it is
- */
if (ami_drv_inq(sc, ch, tg, 0, &inqbuf))
- continue;
+ goto bail;
- if (ld != bd->bd_volid) {
- ld++;
- continue;
- }
-
bcopy(inqbuf.vendor, vend, sizeof vend - 1);
vend[sizeof vend - 1] = '\0';
strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
if (!ami_drv_inq(sc, ch, tg, 0x80, &vpdbuf)) {
- char ser[32 + 1];
-
bcopy(vpdbuf.serial, ser, sizeof ser - 1);
-
ser[sizeof ser - 1] = '\0';
if (vpdbuf.hdr.page_length < sizeof ser)
ser[vpdbuf.hdr.page_length] = '\0';
-
strlcpy(bd->bd_serial, ser, sizeof(bd->bd_serial));
}
- bd->bd_size = (u_quad_t)p->apd[i].adp_size * (u_quad_t)512;
+ error = ami_drv_readcap(sc, ch, tg, &sz);
+ if (error)
+ goto bail;
+ bd->bd_size = sz;
bd->bd_channel = ch;
bd->bd_target = tg;
@@ -2106,8 +2193,6 @@ ami_disk(struct ami_softc *sc, struct bioc_disk *bd,
}
bail:
- free(plist, M_DEVBUF);
-
return (error);
}
@@ -2177,7 +2262,7 @@ ami_ioctl_vol(struct ami_softc *sc, struct bioc_vol *bv)
if (p->apd[off].adp_ostatus != AMI_PD_RBLD)
continue;
- /* get rebuild progress here */
+ /* get rebuild progress from pd 0 */
bv->bv_status = BIOC_SVREBUILD;
if (ami_mgmt(sc, AMI_GRBLDPROGR,
p->ald[i].asp[s].adv[t].add_channel,
@@ -2187,10 +2272,6 @@ ami_ioctl_vol(struct ami_softc *sc, struct bioc_vol *bv)
else
bv->bv_percent = perc.apr_progress >= 100 ? -1 :
perc.apr_progress;
-
- /* XXX fix this, we should either use lowest percentage
- * of all disks in rebuild state or an average
- */
break;
}
@@ -2240,8 +2321,10 @@ ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd)
struct ami_big_diskarray *p; /* struct too large for stack */
int i, s, t, d;
int off;
- int error = 0;
+ int error = EINVAL;
u_int16_t ch, tg;
+ char vend[8+16+4+1];
+ char ser[32 + 1];
p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT);
if (!p)
@@ -2256,8 +2339,6 @@ ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd)
}
i = bd->bd_volid;
- error = EINVAL;
-
for (s = 0, d = 0; s < p->ald[i].adl_spandepth; s++)
for (t = 0; t < p->ald[i].adl_nstripes; t++) {
if (d != bd->bd_diskid) {
@@ -2269,6 +2350,9 @@ ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd)
AMI_MAX_TARGET +
p->ald[i].asp[s].adv[t].add_target;
+ bd->bd_size = (u_quad_t)p->apd[off].adp_size *
+ (u_quad_t)512;
+
switch (p->apd[off].adp_ostatus) {
case AMI_PD_UNCNF:
bd->bd_status = BIOC_SDUNUSED;
@@ -2280,6 +2364,7 @@ ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd)
case AMI_PD_FAILED:
bd->bd_status = BIOC_SDFAILED;
+ bd->bd_size = 0;
break;
case AMI_PD_RBLD:
@@ -2292,47 +2377,45 @@ ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd)
default:
bd->bd_status = BIOC_SDINVALID;
+ bd->bd_size = 0;
}
- bd->bd_size = (u_quad_t)p->apd[off].adp_size *
- (u_quad_t)512;
ch = p->ald[i].asp[s].adv[t].add_target >> 4;
tg = p->ald[i].asp[s].adv[t].add_target & 0x0f;
- if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) {
- char vend[8+16+4+1];
+ bd->bd_channel = ch;
+ bd->bd_target = tg;
+ strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev,
+ sizeof(bd->bd_procdev));
- bcopy(inqbuf.vendor, vend, sizeof vend - 1);
+ /* if we are failed don't query drive */
+ if (bd->bd_size == 0) {
+ bzero(&bd->bd_vendor, sizeof(bd->bd_vendor));
+ bzero(&bd->bd_serial, sizeof(bd->bd_serial));
+ goto done;
+ }
+ if (!ami_drv_inq(sc, ch, tg, 0, &inqbuf)) {
+ bcopy(inqbuf.vendor, vend, sizeof vend - 1);
vend[sizeof vend - 1] = '\0';
strlcpy(bd->bd_vendor, vend,
sizeof(bd->bd_vendor));
}
if (!ami_drv_inq(sc, ch, tg, 0x80, &vpdbuf)) {
- char ser[32 + 1];
-
bcopy(vpdbuf.serial, ser, sizeof ser - 1);
-
ser[sizeof ser - 1] = '\0';
if (vpdbuf.hdr.page_length < sizeof ser)
ser[vpdbuf.hdr.page_length] = '\0';
strlcpy(bd->bd_serial, ser,
sizeof(bd->bd_serial));
}
-
- bd->bd_channel = ch;
- bd->bd_target = tg;
-
- strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev,
- sizeof(bd->bd_procdev));
-
- error = 0;
- goto bail;
+ goto done;
}
- /* XXX if we reach this do dedicated hotspare magic*/
+done:
+ error = 0;
bail:
free(p, M_DEVBUF);
diff --git a/sys/dev/ic/amivar.h b/sys/dev/ic/amivar.h
index b448c7d14ad..787f5b1b39f 100644
--- a/sys/dev/ic/amivar.h
+++ b/sys/dev/ic/amivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: amivar.h,v 1.53 2008/04/10 06:39:00 dlg Exp $ */
+/* $OpenBSD: amivar.h,v 1.54 2008/10/28 11:43:10 marco Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -27,8 +27,6 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/sensors.h>
-
struct ami_mem {
bus_dmamap_t am_map;
bus_dma_segment_t am_seg;
@@ -145,6 +143,15 @@ struct ami_softc {
struct ksensor *sc_sensors;
struct ksensordev sc_sensordev;
struct ami_big_diskarray *sc_bd;
+
+ /* bio stuff */
+ struct bioc_inq sc_bi;
+ char sc_plist[AMI_BIG_MAX_PDRIVES];
+
+ struct ami_ccb *sc_mgmtccb;
+ int sc_drained;
+ int sc_drainio;
+ u_int8_t sc_drvinscnt;
};
int ami_attach(struct ami_softc *sc);
diff --git a/sys/dev/pci/ami_pci.c b/sys/dev/pci/ami_pci.c
index 42200717b80..95570b0ad20 100644
--- a/sys/dev/pci/ami_pci.c
+++ b/sys/dev/pci/ami_pci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ami_pci.c,v 1.42 2007/01/27 05:09:51 dlg Exp $ */
+/* $OpenBSD: ami_pci.c,v 1.43 2008/10/28 11:43:10 marco Exp $ */
/*
* Copyright (c) 2001 Michael Shalayeff
@@ -42,6 +42,7 @@
#include <scsi/scsi_disk.h>
#include <scsi/scsiconf.h>
+#include <dev/biovar.h>
#include <dev/ic/amireg.h>
#include <dev/ic/amivar.h>