summaryrefslogtreecommitdiffstats
path: root/sys/dev/ic/qla.c
diff options
context:
space:
mode:
authorjmatthew <jmatthew@openbsd.org>2014-02-02 07:53:33 +0000
committerjmatthew <jmatthew@openbsd.org>2014-02-02 07:53:33 +0000
commitaa14606a90c7bd66f3ab89c65f7a71fc129fc192 (patch)
treec156e803f5e3d10babb39d5b6436f28975814ec1 /sys/dev/ic/qla.c
parentRearrange interrupt register processing for 2200s. The mailbox semaphore (diff)
downloadwireguard-openbsd-aa14606a90c7bd66f3ab89c65f7a71fc129fc192.tar.xz
wireguard-openbsd-aa14606a90c7bd66f3ab89c65f7a71fc129fc192.zip
carve up qla_attach() into bits we can use to process loop and fabric changes
later on.
Diffstat (limited to 'sys/dev/ic/qla.c')
-rw-r--r--sys/dev/ic/qla.c618
1 files changed, 346 insertions, 272 deletions
diff --git a/sys/dev/ic/qla.c b/sys/dev/ic/qla.c
index 8628cedad02..9ce91ddbd94 100644
--- a/sys/dev/ic/qla.c
+++ b/sys/dev/ic/qla.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: qla.c,v 1.13 2014/02/02 06:28:18 jmatthew Exp $ */
+/* $OpenBSD: qla.c,v 1.14 2014/02/02 07:53:33 jmatthew Exp $ */
/*
* Copyright (c) 2011 David Gwynne <dlg@openbsd.org>
@@ -52,8 +52,6 @@ void qla_scsi_cmd(struct scsi_xfer *);
struct qla_ccb *qla_scsi_cmd_poll(struct qla_softc *);
int qla_scsi_probe(struct scsi_link *);
-void qla_handle_intr(struct qla_softc *, u_int16_t, u_int16_t);
-
u_int16_t qla_read(struct qla_softc *, int);
void qla_write(struct qla_softc *, int, u_int16_t);
void qla_host_cmd(struct qla_softc *sc, u_int16_t);
@@ -63,15 +61,17 @@ int qla_sns_req(struct qla_softc *, struct qla_dmamem *, int);
void qla_mbox_putaddr(u_int16_t *, struct qla_dmamem *);
u_int16_t qla_read_mbox(struct qla_softc *, int);
void qla_write_mbox(struct qla_softc *, int, u_int16_t);
+
+void qla_handle_intr(struct qla_softc *, u_int16_t, u_int16_t);
void qla_set_ints(struct qla_softc *, int);
int qla_read_isr(struct qla_softc *, u_int16_t *, u_int16_t *);
void qla_clear_isr(struct qla_softc *, u_int16_t);
+
int qla_queue_reg(struct qla_softc *, enum qla_qptr);
u_int16_t qla_read_queue_ptr(struct qla_softc *, enum qla_qptr);
void qla_write_queue_ptr(struct qla_softc *, enum qla_qptr,
u_int16_t);
void qla_update(struct qla_softc *, int);
-int qla_async(struct qla_softc *, u_int16_t);
void qla_put_marker(struct qla_softc *, void *);
void qla_put_cmd(struct qla_softc *, void *, struct scsi_xfer *,
struct qla_ccb *);
@@ -82,6 +82,23 @@ void qla_put_cmd_cont(struct qla_softc *, void *,
struct qla_ccb *qla_handle_resp(struct qla_softc *, u_int16_t);
void qla_put_data_seg(struct qla_iocb_seg *, bus_dmamap_t, int);
+struct qla_fc_port *qla_next_fabric_port(struct qla_softc *, u_int32_t *,
+ u_int32_t *);
+int qla_add_port(struct qla_softc *, u_int16_t, u_int32_t,
+ u_int32_t);
+int qla_classify_port(struct qla_softc *, u_int32_t, u_int64_t,
+ u_int64_t);
+int qla_get_loop_id(struct qla_softc *sc);
+void qla_clear_port_lists(struct qla_softc *);
+int qla_softreset(struct qla_softc *);
+void qla_update_topology(struct qla_softc *);
+int qla_update_fabric(struct qla_softc *);
+int qla_fabric_plogi(struct qla_softc *, struct qla_fc_port *);
+void qla_fabric_plogo(struct qla_softc *, struct qla_fc_port *);
+
+void qla_update_start(struct qla_softc *, int);
+int qla_async(struct qla_softc *, u_int16_t);
+
int qla_load_firmware_2200(struct qla_softc *);
int qla_load_fwchunk_2300(struct qla_softc *,
struct qla_dmamem *, const u_int16_t *, u_int32_t);
@@ -91,12 +108,6 @@ int qla_read_nvram(struct qla_softc *);
struct qla_dmamem *qla_dmamem_alloc(struct qla_softc *, size_t);
void qla_dmamem_free(struct qla_softc *, struct qla_dmamem *);
-int qla_add_port(struct qla_softc *, u_int16_t, u_int32_t,
- u_int32_t);
-int qla_classify_port(struct qla_softc *, u_int32_t, u_int64_t,
- u_int64_t);
-int qla_get_loop_id(struct qla_softc *sc);
-
int qla_alloc_ccbs(struct qla_softc *);
void qla_free_ccbs(struct qla_softc *);
void *qla_get_ccb(void *);
@@ -187,6 +198,9 @@ qla_add_port(struct qla_softc *sc, u_int16_t loopid, u_int32_t portid,
} else {
sc->sc_mbox[1] = loopid << 8;
}
+ pdb = QLA_DMA_KVA(sc->sc_scratch);
+ memset(pdb, 0, sizeof(*pdb));
+
qla_mbox_putaddr(sc->sc_mbox, sc->sc_scratch);
bus_dmamap_sync(sc->sc_dmat, QLA_DMA_MAP(sc->sc_scratch), 0,
sizeof(struct qla_get_port_db), BUS_DMASYNC_PREREAD);
@@ -197,11 +211,8 @@ qla_add_port(struct qla_softc *sc, u_int16_t loopid, u_int32_t portid,
return (1);
}
- bus_dmamap_sync(sc->sc_dmat,
- QLA_DMA_MAP(sc->sc_scratch), 0,
- sizeof(struct qla_get_port_db),
- BUS_DMASYNC_POSTREAD);
- pdb = QLA_DMA_KVA(sc->sc_scratch);
+ bus_dmamap_sync(sc->sc_dmat, QLA_DMA_MAP(sc->sc_scratch), 0,
+ sizeof(*pdb), BUS_DMASYNC_POSTREAD);
/* could also check that the port/node names match what we thought we
* logged in to?
@@ -241,7 +252,6 @@ qla_attach(struct qla_softc *sc)
{
struct scsibus_attach_args saa;
struct qla_init_cb *icb;
- int scan_limit, scan;
int i, rv;
TAILQ_INIT(&sc->sc_ports);
@@ -275,53 +285,8 @@ qla_attach(struct qla_softc *sc)
}
qla_host_cmd(sc, QLA_HOST_CMD_PAUSE);
- qla_set_ints(sc, 0);
-
- /* reset */
- qla_write(sc, QLA_CTRL_STATUS, QLA_CTRL_RESET);
- delay(100);
- /* clear data and control dma engines? */
-
- /* wait for soft reset to clear */
- for (i = 0; i < 1000; i++) {
- if ((qla_read(sc, QLA_CTRL_STATUS) & QLA_CTRL_RESET) == 0)
- break;
-
- delay(100);
- }
-
- if (i == 1000) {
- printf("reset didn't clear\n");
- qla_set_ints(sc, 0);
- return (ENXIO);
- }
-
- /* reset FPM */
- qla_write(sc, QLA_CTRL_STATUS, QLA_CTRL_FPM0_REGS);
- qla_write(sc, QLA_FPM_DIAG, QLA_FPM_RESET);
- qla_write(sc, QLA_FPM_DIAG, 0); /* isp(4) doesn't do this? */
- qla_write(sc, QLA_CTRL_STATUS, QLA_CTRL_RISC_REGS);
-
- /* reset risc processor */
- qla_host_cmd(sc, QLA_HOST_CMD_RESET);
- delay(100);
- qla_write(sc, QLA_SEMA, 0);
- qla_host_cmd(sc, QLA_HOST_CMD_MASK_PARITY); /* from isp(4) */
- qla_host_cmd(sc, QLA_HOST_CMD_RELEASE);
-
- /* reset queue pointers */
- qla_write_queue_ptr(sc, QLA_REQ_QUEUE_IN, 0);
- qla_write_queue_ptr(sc, QLA_REQ_QUEUE_OUT, 0);
- qla_write_queue_ptr(sc, QLA_RESP_QUEUE_IN, 0);
- qla_write_queue_ptr(sc, QLA_RESP_QUEUE_OUT, 0);
-
- qla_set_ints(sc, 1);
- /* isp(4) sends QLA_HOST_CMD_BIOS here.. not documented? */
-
- /* do a basic mailbox operation to check we're alive */
- sc->sc_mbox[0] = QLA_MBOX_NOP;
- if (qla_mbox(sc, 0x0001, 0x0001)) {
- printf("ISP not responding after reset\n");
+ if (qla_softreset(sc) != 0) {
+ printf("softreset failed\n");
return (ENXIO);
}
@@ -505,220 +470,43 @@ qla_attach(struct qla_softc *sc)
break;
}
- if (sc->sc_loop_up == 0) {
- printf("%s: loop still down, giving up\n", DEVNAME(sc));
- return (0);
- }
-
- /* connection topology tells us what to scan */
- sc->sc_mbox[0] = QLA_MBOX_GET_LOOP_ID;
- if (qla_mbox(sc, 0x0001, QLA_MBOX_GET_LOOP_ID_OUT)) {
- printf("%s: unable to get loop id\n", DEVNAME(sc));
- sc->sc_topology = QLA_TOPO_N_PORT_NO_TARGET;
- } else {
- sc->sc_topology = sc->sc_mbox[6];
- sc->sc_loop_id = sc->sc_mbox[1];
-
- switch (sc->sc_topology) {
- case QLA_TOPO_NL_PORT:
- case QLA_TOPO_N_PORT:
- printf("%s: loop id %d\n", DEVNAME(sc),
- sc->sc_loop_id);
- break;
-
- case QLA_TOPO_FL_PORT:
- case QLA_TOPO_F_PORT:
- sc->sc_port_id = sc->sc_mbox[2] |
- (sc->sc_mbox[3] << 16);
- printf("%s: fabric port id %06x\n", DEVNAME(sc),
- sc->sc_port_id);
- break;
-
- case QLA_TOPO_N_PORT_NO_TARGET:
- default:
- printf("%s: not useful\n", DEVNAME(sc));
- break;
- }
- }
-
- /* scan loop */
- switch (sc->sc_topology) {
- case QLA_TOPO_NL_PORT:
- case QLA_TOPO_FL_PORT:
- scan_limit = 126;
- break;
-
- case QLA_TOPO_N_PORT:
- scan_limit = 2;
- break;
-
- default:
- scan_limit = 0;
- break;
- }
-
- for (scan = 0; scan < scan_limit; scan++) {
- if (scan == sc->sc_loop_id)
- continue;
-
- qla_add_port(sc, scan, 0, QLA_LOCATION_LOOP_ID(scan));
- }
-
- /* scan fabric, if there is one */
- if (sc->sc_fabric && (sc->sc_topology == QLA_TOPO_F_PORT ||
- sc->sc_topology == QLA_TOPO_FL_PORT)) {
- struct qla_sns_rft_id *rft;
- struct qla_sns_ga_nxt *ga;
- struct qla_sns_ga_nxt_resp *gar;
- struct qla_fc_port *fport;
- u_int32_t lastport, firstport;
- TAILQ_HEAD(, qla_fc_port) found;
-
- /* get the name server's port db entry */
- sc->sc_mbox[0] = QLA_MBOX_GET_PORT_DB;
- if (sc->sc_2k_logins) {
- sc->sc_mbox[1] = QLA_F_PORT_HANDLE;
- } else {
- sc->sc_mbox[1] = QLA_F_PORT_HANDLE << 8;
- }
- qla_mbox_putaddr(sc->sc_mbox, sc->sc_scratch);
- bus_dmamap_sync(sc->sc_dmat, QLA_DMA_MAP(sc->sc_scratch), 0,
- sizeof(struct qla_get_port_db), BUS_DMASYNC_PREREAD);
- if (qla_mbox(sc, 0x00cf, 0x0001)) {
- printf("%s: get port db for SNS failed: %x\n",
- DEVNAME(sc), sc->sc_mbox[0]);
- /* what now? */
- } else {
- struct qla_get_port_db *pdb;
- bus_dmamap_sync(sc->sc_dmat,
- QLA_DMA_MAP(sc->sc_scratch), 0,
- sizeof(struct qla_get_port_db),
- BUS_DMASYNC_POSTREAD);
- pdb = QLA_DMA_KVA(sc->sc_scratch);
- printf("%s: SNS; port id %06x, name %llx\n",
- DEVNAME(sc), ((letoh16(pdb->port_id[0]) << 16) |
- letoh16(pdb->port_id[1])) & 0xffffff,
- betoh64(pdb->port_name));
- }
-
- /*
- * register fc4 types with the fabric
- * some switches do this automatically, but apparently
- * some don't.
- */
- rft = QLA_DMA_KVA(sc->sc_scratch);
- memset(rft, 0, sizeof(*rft) + sizeof(struct qla_sns_req_hdr));
- rft->subcmd = htole16(QLA_SNS_RFT_ID);
- rft->max_word = htole16(sizeof(struct qla_sns_req_hdr) / 4);
- rft->port_id = htole32(sc->sc_port_id);
- rft->fc4_types[0] = htole16(1 << QLA_FC4_SCSI);
- if (qla_sns_req(sc, sc->sc_scratch, sizeof(*rft))) {
- printf("%s: RFT_ID failed\n", DEVNAME(sc));
- /* we might be able to continue after this fails */
- }
-
- TAILQ_INIT(&found);
- lastport = 0;
- firstport = -1;
- i = 0;
- do {
- int result;
-
- /* get the next port from the fabric nameserver */
- ga = QLA_DMA_KVA(sc->sc_scratch);
- memset(ga, 0, sizeof(*ga) + sizeof(*gar));
- ga->subcmd = htole16(QLA_SNS_GA_NXT);
- ga->max_word = htole16(sizeof(*gar) / 4);
- ga->port_id = htole32(lastport);
- result = qla_sns_req(sc, sc->sc_scratch, sizeof(*ga));
- if (result) {
- printf("%s: GA_NXT %x failed: %x\n",
- DEVNAME(sc), lastport, result);
- break;
- }
-
- gar = (struct qla_sns_ga_nxt_resp *)(ga + 1);
- /* if the response is all zeroes, try again */
- if (gar->port_type_id == 0 && gar->port_name == 0 &&
- gar->node_name == 0) {
- printf("%s: GA_NXT returned junk\n",
- DEVNAME(sc));
- continue;
- }
-
- /* are we back at the start? */
- lastport = betoh32(gar->port_type_id) & 0xffffff;
- if (lastport == firstport)
- break;
- if (firstport == -1)
- firstport = lastport;
-
- /*
- printf("%s: GA_NXT: port type/id: %x, wwpn %llx, wwnn %llx, fct: %x\n", DEVNAME(sc), lastport, betoh64(gar->port_name), betoh64(gar->node_name), gar->fc4_types[0]);
- */
+ if (sc->sc_loop_up) {
+ int i;
- /* don't try to log in to ourselves */
- if (lastport == sc->sc_port_id) {
- continue;
+ qla_update_topology(sc);
+ for (i = 0; i < sc->sc_loop_max_id; i++) {
+ if (i != sc->sc_loop_id) {
+ qla_add_port(sc, i, 0,
+ QLA_LOCATION_LOOP_ID(i));
}
+ }
- fport = malloc(sizeof(*fport), M_DEVBUF,
- M_ZERO | M_NOWAIT);
- if (fport == NULL) {
- printf("%s: failed to allocate a port struct\n",
- DEVNAME(sc));
- break;
- }
- fport->port_name = betoh64(gar->port_name);
- fport->node_name = betoh64(gar->node_name);
- fport->location = QLA_LOCATION_PORT_ID(lastport);
- fport->portid = lastport;
- TAILQ_INSERT_TAIL(&found, fport, update);
- } while (1);
-
- while (!TAILQ_EMPTY(&found)) {
- int loopid;
- int mboxin;
-
- mtx_enter(&sc->sc_port_mtx);
- loopid = qla_get_loop_id(sc);
- mtx_leave(&sc->sc_port_mtx);
-
- if (loopid == -1) {
- printf("%s: ran out of loop ids\n",
- DEVNAME(sc));
- break;
- }
- fport = TAILQ_FIRST(&found);
- TAILQ_REMOVE(&found, fport, update);
-
- mboxin = 0x000f;
- sc->sc_mbox[0] = QLA_MBOX_FABRIC_PLOGI;
- sc->sc_mbox[2] = (fport->portid >> 16) & 0xff;
- sc->sc_mbox[3] = fport->portid & 0xffff;
- if (sc->sc_2k_logins) {
- sc->sc_mbox[1] = loopid;
- sc->sc_mbox[10] = 0;
- mboxin |= (1 << 10);
- } else {
- sc->sc_mbox[1] = loopid << 8;
- }
- if (qla_mbox(sc, mboxin, 0x00c7)) {
- printf("%s: port %x login failed: %x %x %x %x\n",
- DEVNAME(sc), fport->portid, sc->sc_mbox[0],
- sc->sc_mbox[1], sc->sc_mbox[2],
- sc->sc_mbox[6]);
- } else {
- qla_add_port(sc, loopid, fport->portid,
- fport->location);
+ if (qla_update_fabric(sc) == 0) {
+ TAILQ_HEAD(, qla_fc_port) found;
+ u_int32_t firstport = 0xffffffff;
+ u_int32_t lastport = 0;
+ struct qla_fc_port *port;
+
+ TAILQ_INIT(&found);
+ do {
+ port = qla_next_fabric_port(sc, &firstport,
+ &lastport);
+ if (port != NULL)
+ TAILQ_INSERT_TAIL(&found, port, update);
+ } while (lastport != 0xffffffff);
+
+ while (!TAILQ_EMPTY(&found)) {
+ port = TAILQ_FIRST(&found);
+ if (qla_fabric_plogi(sc, port) == 0) {
+ qla_add_port(sc, port->loopid,
+ port->portid, port->location);
+ }
+ TAILQ_REMOVE(&found, port, update);
+ free(port, M_DEVBUF);
}
- free(fport, M_DEVBUF);
}
-
- /* firmware implicitly registers for change notification for
- * events detected by the controller. we might want full
- * registration instead.
- */
+ } else {
+ printf("%s: loop still down, giving up\n", DEVNAME(sc));
}
/* we should be good to go now, attach scsibus */
@@ -1409,6 +1197,292 @@ qla_write_queue_ptr(struct qla_softc *sc, enum qla_qptr queue,
qla_write(sc, qla_queue_reg(sc, queue), value);
}
+int
+qla_softreset(struct qla_softc *sc)
+{
+ int i;
+ qla_set_ints(sc, 0);
+
+ /* reset */
+ qla_write(sc, QLA_CTRL_STATUS, QLA_CTRL_RESET);
+ delay(100);
+ /* clear data and control dma engines? */
+
+ /* wait for soft reset to clear */
+ for (i = 0; i < 1000; i++) {
+ if ((qla_read(sc, QLA_CTRL_STATUS) & QLA_CTRL_RESET) == 0)
+ break;
+
+ delay(100);
+ }
+
+ if (i == 1000) {
+ printf("reset didn't clear\n");
+ qla_set_ints(sc, 0);
+ return (ENXIO);
+ }
+
+ /* reset FPM */
+ qla_write(sc, QLA_CTRL_STATUS, QLA_CTRL_FPM0_REGS);
+ qla_write(sc, QLA_FPM_DIAG, QLA_FPM_RESET);
+ qla_write(sc, QLA_FPM_DIAG, 0); /* isp(4) doesn't do this? */
+ qla_write(sc, QLA_CTRL_STATUS, QLA_CTRL_RISC_REGS);
+
+ /* reset risc processor */
+ qla_host_cmd(sc, QLA_HOST_CMD_RESET);
+ delay(100);
+ qla_write(sc, QLA_SEMA, 0);
+ qla_host_cmd(sc, QLA_HOST_CMD_MASK_PARITY); /* from isp(4) */
+ qla_host_cmd(sc, QLA_HOST_CMD_RELEASE);
+
+ /* reset queue pointers */
+ qla_write_queue_ptr(sc, QLA_REQ_QUEUE_IN, 0);
+ qla_write_queue_ptr(sc, QLA_REQ_QUEUE_OUT, 0);
+ qla_write_queue_ptr(sc, QLA_RESP_QUEUE_IN, 0);
+ qla_write_queue_ptr(sc, QLA_RESP_QUEUE_OUT, 0);
+
+ qla_set_ints(sc, 1);
+ /* isp(4) sends QLA_HOST_CMD_BIOS here.. not documented? */
+
+ /* do a basic mailbox operation to check we're alive */
+ sc->sc_mbox[0] = QLA_MBOX_NOP;
+ if (qla_mbox(sc, 0x0001, 0x0001)) {
+ printf("ISP not responding after reset\n");
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+void
+qla_update_topology(struct qla_softc *sc)
+{
+ sc->sc_mbox[0] = QLA_MBOX_GET_LOOP_ID;
+ if (qla_mbox(sc, 0x0001, QLA_MBOX_GET_LOOP_ID_OUT)) {
+ printf("%s: unable to get loop id\n", DEVNAME(sc));
+ sc->sc_topology = QLA_TOPO_N_PORT_NO_TARGET;
+ } else {
+ sc->sc_topology = sc->sc_mbox[6];
+ sc->sc_loop_id = sc->sc_mbox[1];
+
+ switch (sc->sc_topology) {
+ case QLA_TOPO_NL_PORT:
+ case QLA_TOPO_N_PORT:
+ printf("%s: loop id %d\n", DEVNAME(sc),
+ sc->sc_loop_id);
+ break;
+
+ case QLA_TOPO_FL_PORT:
+ case QLA_TOPO_F_PORT:
+ sc->sc_port_id = sc->sc_mbox[2] |
+ (sc->sc_mbox[3] << 16);
+ printf("%s: fabric port id %06x\n", DEVNAME(sc),
+ sc->sc_port_id);
+ break;
+
+ case QLA_TOPO_N_PORT_NO_TARGET:
+ default:
+ printf("%s: not useful\n", DEVNAME(sc));
+ break;
+ }
+
+ switch (sc->sc_topology) {
+ case QLA_TOPO_NL_PORT:
+ case QLA_TOPO_FL_PORT:
+ sc->sc_loop_max_id = 126;
+ break;
+
+ case QLA_TOPO_N_PORT:
+ sc->sc_loop_max_id = 2;
+ break;
+
+ default:
+ sc->sc_loop_max_id = 0;
+ break;
+ }
+ }
+}
+
+int
+qla_update_fabric(struct qla_softc *sc)
+{
+ struct qla_sns_rft_id *rft;
+
+ if (sc->sc_fabric == 0)
+ return (1);
+
+ switch (sc->sc_topology) {
+ case QLA_TOPO_F_PORT:
+ case QLA_TOPO_FL_PORT:
+ break;
+
+ default:
+ return (1);
+ }
+
+ /* get the name server's port db entry */
+ sc->sc_mbox[0] = QLA_MBOX_GET_PORT_DB;
+ if (sc->sc_2k_logins) {
+ sc->sc_mbox[1] = QLA_F_PORT_HANDLE;
+ } else {
+ sc->sc_mbox[1] = QLA_F_PORT_HANDLE << 8;
+ }
+ qla_mbox_putaddr(sc->sc_mbox, sc->sc_scratch);
+ bus_dmamap_sync(sc->sc_dmat, QLA_DMA_MAP(sc->sc_scratch), 0,
+ sizeof(struct qla_get_port_db), BUS_DMASYNC_PREREAD);
+ if (qla_mbox(sc, 0x00cf, 0x0001)) {
+ printf("%s: get port db for SNS failed: %x\n",
+ DEVNAME(sc), sc->sc_mbox[0]);
+ sc->sc_sns_port_name = 0;
+ } else {
+ struct qla_get_port_db *pdb;
+ bus_dmamap_sync(sc->sc_dmat, QLA_DMA_MAP(sc->sc_scratch), 0,
+ sizeof(struct qla_get_port_db), BUS_DMASYNC_POSTREAD);
+ pdb = QLA_DMA_KVA(sc->sc_scratch);
+ printf("%s: SNS port name %llx\n", DEVNAME(sc),
+ betoh64(pdb->port_name));
+ sc->sc_sns_port_name = betoh64(pdb->port_name);
+ }
+
+ /*
+ * register fc4 types with the fabric
+ * some switches do this automatically, but apparently
+ * some don't.
+ */
+ rft = QLA_DMA_KVA(sc->sc_scratch);
+ memset(rft, 0, sizeof(*rft) + sizeof(struct qla_sns_req_hdr));
+ rft->subcmd = htole16(QLA_SNS_RFT_ID);
+ rft->max_word = htole16(sizeof(struct qla_sns_req_hdr) / 4);
+ rft->port_id = htole32(sc->sc_port_id);
+ rft->fc4_types[0] = (1 << QLA_FC4_SCSI);
+ if (qla_sns_req(sc, sc->sc_scratch, sizeof(*rft))) {
+ printf("%s: RFT_ID failed\n", DEVNAME(sc));
+ /* we might be able to continue after this fails */
+ }
+
+ return (0);
+}
+
+struct qla_fc_port *
+qla_next_fabric_port(struct qla_softc *sc, u_int32_t *firstport,
+ u_int32_t *lastport)
+{
+ struct qla_sns_ga_nxt *ga;
+ struct qla_sns_ga_nxt_resp *gar;
+ struct qla_fc_port *fport;
+ int result;
+
+ /* get the next port from the fabric nameserver */
+ ga = QLA_DMA_KVA(sc->sc_scratch);
+ memset(ga, 0, sizeof(*ga) + sizeof(*gar));
+ ga->subcmd = htole16(QLA_SNS_GA_NXT);
+ ga->max_word = htole16(sizeof(*gar) / 4);
+ ga->port_id = htole32(*lastport);
+ result = qla_sns_req(sc, sc->sc_scratch, sizeof(*ga));
+ if (result) {
+ printf("%s: GA_NXT %x failed: %x\n", DEVNAME(sc), lastport,
+ result);
+ *lastport = 0xffffffff;
+ return (NULL);
+ }
+
+ gar = (struct qla_sns_ga_nxt_resp *)(ga + 1);
+ /* if the response is all zeroes, try again */
+ if (gar->port_type_id == 0 && gar->port_name == 0 &&
+ gar->node_name == 0) {
+ printf("%s: GA_NXT returned junk\n", DEVNAME(sc));
+ return (NULL);
+ }
+
+ /* are we back at the start? */
+ *lastport = betoh32(gar->port_type_id) & 0xffffff;
+ if (*lastport == *firstport) {
+ *lastport = 0xffffffff;
+ return (NULL);
+ }
+ if (*firstport == 0xffffffff)
+ *firstport = *lastport;
+
+ printf("%s: GA_NXT: port type/id: %x, wwpn %llx, wwnn %llx, fct: %x\n",
+ DEVNAME(sc), *lastport, betoh64(gar->port_name),
+ betoh64(gar->node_name), gar->fc4_types[0]);
+
+ /* don't try to log in to ourselves */
+ if (*lastport == sc->sc_port_id) {
+ return (NULL);
+ }
+
+ fport = malloc(sizeof(*fport), M_DEVBUF, M_ZERO | M_NOWAIT);
+ if (fport == NULL) {
+ printf("%s: failed to allocate a port struct\n",
+ DEVNAME(sc));
+ *lastport = 0xffffffff;
+ return (NULL);
+ }
+ fport->port_name = betoh64(gar->port_name);
+ fport->node_name = betoh64(gar->node_name);
+ fport->location = QLA_LOCATION_PORT_ID(*lastport);
+ fport->portid = *lastport;
+ return (fport);
+}
+
+
+int
+qla_fabric_plogi(struct qla_softc *sc, struct qla_fc_port *port)
+{
+ int loopid;
+ int mboxin;
+
+ mtx_enter(&sc->sc_port_mtx);
+ loopid = qla_get_loop_id(sc);
+ mtx_leave(&sc->sc_port_mtx);
+
+ if (loopid == -1) {
+ printf("%s: ran out of loop ids\n",
+ DEVNAME(sc));
+ return (1);
+ }
+
+ mboxin = 0x000f;
+ sc->sc_mbox[0] = QLA_MBOX_FABRIC_PLOGI;
+ sc->sc_mbox[2] = (port->portid >> 16) & 0xff;
+ sc->sc_mbox[3] = port->portid & 0xffff;
+ if (sc->sc_2k_logins) {
+ sc->sc_mbox[1] = loopid;
+ sc->sc_mbox[10] = 0;
+ mboxin |= (1 << 10);
+ } else {
+ sc->sc_mbox[1] = loopid << 8;
+ }
+
+ if (qla_mbox(sc, mboxin, 0x00c7)) {
+ printf("%s: port %x login failed: %x %x %x %x\n",
+ DEVNAME(sc), port->portid, sc->sc_mbox[0],
+ sc->sc_mbox[1], sc->sc_mbox[2],
+ sc->sc_mbox[6]);
+ return (1);
+ }
+ port->loopid = loopid;
+ return (0);
+}
+
+void
+qla_fabric_plogo(struct qla_softc *sc, struct qla_fc_port *port)
+{
+ int mboxin = 0x0003;
+ sc->sc_mbox[0] = QLA_MBOX_FABRIC_PLOGO;
+ if (sc->sc_2k_logins) {
+ sc->sc_mbox[1] = port->loopid;
+ sc->sc_mbox[10] = 0;
+ mboxin |= (1 << 10);
+ } else {
+ sc->sc_mbox[1] = port->loopid << 8;
+ }
+
+ if (qla_mbox(sc, mboxin, 0x03))
+ printf("%s: PLOGO %x failed\n", DEVNAME(sc), port->loopid);
+}
+
void
qla_update(struct qla_softc *sc, int task)
{