Line data Source code
1 : /* $OpenBSD: qle.c,v 1.45 2018/07/30 07:34:37 jmatthew Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2013, 2014 Jonathan Matthew <jmatthew@openbsd.org>
5 : *
6 : * Permission to use, copy, modify, and distribute this software for any
7 : * purpose with or without fee is hereby granted, provided that the above
8 : * copyright notice and this permission notice appear in all copies.
9 : *
10 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : */
18 :
19 : #include "bio.h"
20 :
21 : #include <sys/param.h>
22 : #include <sys/systm.h>
23 : #include <sys/atomic.h>
24 : #include <sys/malloc.h>
25 : #include <sys/device.h>
26 : #include <sys/sensors.h>
27 : #include <sys/rwlock.h>
28 : #include <sys/task.h>
29 : #include <sys/timeout.h>
30 :
31 : #include <machine/bus.h>
32 :
33 : #include <dev/pci/pcireg.h>
34 : #include <dev/pci/pcivar.h>
35 : #include <dev/pci/pcidevs.h>
36 :
37 : #ifdef __sparc64__
38 : #include <dev/ofw/openfirm.h>
39 : #endif
40 :
41 : #include <scsi/scsi_all.h>
42 : #include <scsi/scsiconf.h>
43 :
44 : #include <dev/pci/qlereg.h>
45 :
46 : #ifdef QLE_DEBUG
47 : #define DPRINTF(m, f...) do { if ((qledebug & (m)) == (m)) printf(f); } \
48 : while (0)
49 : #define QLE_D_MBOX 0x01
50 : #define QLE_D_INTR 0x02
51 : #define QLE_D_PORT 0x04
52 : #define QLE_D_IO 0x08
53 : #define QLE_D_IOCB 0x10
54 : int qledebug = QLE_D_PORT;
55 : #else
56 : #define DPRINTF(m, f...)
57 : #endif
58 :
59 : #ifndef QLE_NOFIRMWARE
60 : #include <dev/microcode/isp/asm_2400.h>
61 : #include <dev/microcode/isp/asm_2500.h>
62 : #endif
63 :
64 : #define QLE_PCI_MEM_BAR 0x14
65 : #define QLE_PCI_IO_BAR 0x10
66 :
67 :
68 : #define QLE_DEFAULT_PORT_NAME 0x400000007F000003ULL /* from isp(4) */
69 :
70 : #define QLE_WAIT_FOR_LOOP 10 /* seconds */
71 : #define QLE_LOOP_SETTLE 200 /* ms */
72 :
73 : /* rounded up range of assignable handles */
74 : #define QLE_MAX_TARGETS 2048
75 :
76 : /* maximum number of segments allowed for in a single io */
77 : #define QLE_MAX_SEGS 32
78 :
79 : enum qle_isp_gen {
80 : QLE_GEN_ISP24XX = 1,
81 : QLE_GEN_ISP25XX
82 : };
83 :
84 : enum qle_isp_type {
85 : QLE_ISP2422 = 1,
86 : QLE_ISP2432,
87 : QLE_ISP2512,
88 : QLE_ISP2522,
89 : QLE_ISP2532
90 : };
91 :
92 : /* port database things */
93 : #define QLE_SCRATCH_SIZE 0x1000
94 :
95 : enum qle_port_disp {
96 : QLE_PORT_DISP_NEW,
97 : QLE_PORT_DISP_GONE,
98 : QLE_PORT_DISP_SAME,
99 : QLE_PORT_DISP_CHANGED,
100 : QLE_PORT_DISP_MOVED,
101 : QLE_PORT_DISP_DUP
102 : };
103 :
104 : #define QLE_LOCATION_LOOP (1 << 24)
105 : #define QLE_LOCATION_FABRIC (2 << 24)
106 : #define QLE_LOCATION_LOOP_ID(l) (l | QLE_LOCATION_LOOP)
107 : #define QLE_LOCATION_PORT_ID(p) (p | QLE_LOCATION_FABRIC)
108 :
109 : struct qle_fc_port {
110 : TAILQ_ENTRY(qle_fc_port) ports;
111 : TAILQ_ENTRY(qle_fc_port) update;
112 :
113 : u_int64_t node_name;
114 : u_int64_t port_name;
115 : u_int32_t location; /* port id or loop id */
116 :
117 : int flags;
118 : #define QLE_PORT_FLAG_IS_TARGET 1
119 : #define QLE_PORT_FLAG_NEEDS_LOGIN 2
120 :
121 : u_int32_t portid;
122 : u_int16_t loopid;
123 : };
124 :
125 :
126 : /* request/response queue stuff */
127 : #define QLE_QUEUE_ENTRY_SIZE 64
128 :
129 : struct qle_ccb {
130 : struct qle_softc *ccb_sc;
131 : int ccb_id;
132 : struct scsi_xfer *ccb_xs;
133 :
134 : bus_dmamap_t ccb_dmamap;
135 :
136 : struct qle_iocb_seg *ccb_segs;
137 : u_int64_t ccb_seg_offset;
138 :
139 : SIMPLEQ_ENTRY(qle_ccb) ccb_link;
140 : };
141 :
142 : SIMPLEQ_HEAD(qle_ccb_list, qle_ccb);
143 :
144 : struct qle_dmamem {
145 : bus_dmamap_t qdm_map;
146 : bus_dma_segment_t qdm_seg;
147 : size_t qdm_size;
148 : caddr_t qdm_kva;
149 : };
150 : #define QLE_DMA_MAP(_qdm) ((_qdm)->qdm_map)
151 : #define QLE_DMA_LEN(_qdm) ((_qdm)->qdm_size)
152 : #define QLE_DMA_DVA(_qdm) ((u_int64_t)(_qdm)->qdm_map->dm_segs[0].ds_addr)
153 : #define QLE_DMA_KVA(_qdm) ((void *)(_qdm)->qdm_kva)
154 :
155 : struct qle_softc {
156 : struct device sc_dev;
157 :
158 : pci_chipset_tag_t sc_pc;
159 : pcitag_t sc_tag;
160 :
161 : void *sc_ih;
162 : bus_space_tag_t sc_iot;
163 : bus_space_handle_t sc_ioh;
164 : bus_size_t sc_ios;
165 : bus_dma_tag_t sc_dmat;
166 :
167 : struct scsi_link sc_link;
168 :
169 : struct scsibus_softc *sc_scsibus;
170 :
171 : enum qle_isp_type sc_isp_type;
172 : enum qle_isp_gen sc_isp_gen;
173 : int sc_port;
174 :
175 : bus_space_handle_t sc_mbox_ioh;
176 : u_int16_t sc_mbox[QLE_MBOX_COUNT];
177 : int sc_mbox_pending;
178 : struct mutex sc_mbox_mtx;
179 :
180 : int sc_loop_up;
181 : int sc_topology;
182 : int sc_loop_id;
183 : int sc_port_id;
184 : int sc_loop_max_id;
185 : u_int64_t sc_sns_port_name;
186 :
187 : struct mutex sc_port_mtx;
188 : TAILQ_HEAD(, qle_fc_port) sc_ports;
189 : TAILQ_HEAD(, qle_fc_port) sc_ports_new;
190 : TAILQ_HEAD(, qle_fc_port) sc_ports_gone;
191 : TAILQ_HEAD(, qle_fc_port) sc_ports_found;
192 : struct qle_fc_port *sc_targets[QLE_MAX_TARGETS];
193 :
194 : struct taskq *sc_update_taskq;
195 : struct task sc_update_task;
196 : struct timeout sc_update_timeout;
197 : int sc_update;
198 : int sc_update_tasks;
199 : #define QLE_UPDATE_TASK_CLEAR_ALL 0x00000001
200 : #define QLE_UPDATE_TASK_SOFTRESET 0x00000002
201 : #define QLE_UPDATE_TASK_UPDATE_TOPO 0x00000004
202 : #define QLE_UPDATE_TASK_GET_PORT_LIST 0x00000008
203 : #define QLE_UPDATE_TASK_PORT_LIST 0x00000010
204 : #define QLE_UPDATE_TASK_SCAN_FABRIC 0x00000020
205 : #define QLE_UPDATE_TASK_SCANNING_FABRIC 0x00000040
206 : #define QLE_UPDATE_TASK_FABRIC_LOGIN 0x00000080
207 : #define QLE_UPDATE_TASK_FABRIC_RELOGIN 0x00000100
208 : #define QLE_UPDATE_TASK_DETACH_TARGET 0x00000200
209 : #define QLE_UPDATE_TASK_ATTACH_TARGET 0x00000400
210 :
211 : int sc_maxcmds;
212 : struct qle_dmamem *sc_requests;
213 : struct qle_dmamem *sc_responses;
214 : struct qle_dmamem *sc_segments;
215 : struct qle_dmamem *sc_pri_requests;
216 : struct qle_dmamem *sc_scratch;
217 : struct qle_dmamem *sc_fcp_cmnds;
218 : struct qle_ccb *sc_ccbs;
219 : struct qle_ccb_list sc_ccb_free;
220 : struct mutex sc_ccb_mtx;
221 : struct mutex sc_queue_mtx;
222 : struct scsi_iopool sc_iopool;
223 : u_int32_t sc_next_req_id;
224 : u_int32_t sc_last_resp_id;
225 : int sc_marker_required;
226 : int sc_fabric_pending;
227 : u_int8_t sc_fabric_response[QLE_QUEUE_ENTRY_SIZE];
228 :
229 : struct qle_nvram sc_nvram;
230 : int sc_nvram_valid;
231 : };
232 : #define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
233 :
234 : int qle_intr(void *);
235 :
236 : int qle_match(struct device *, void *, void *);
237 : void qle_attach(struct device *, struct device *, void *);
238 : int qle_detach(struct device *, int);
239 :
240 : struct cfattach qle_ca = {
241 : sizeof(struct qle_softc),
242 : qle_match,
243 : qle_attach,
244 : qle_detach
245 : };
246 :
247 : struct cfdriver qle_cd = {
248 : NULL,
249 : "qle",
250 : DV_DULL
251 : };
252 :
253 : void qle_scsi_cmd(struct scsi_xfer *);
254 : int qle_scsi_probe(struct scsi_link *);
255 :
256 :
257 : struct scsi_adapter qle_switch = {
258 : qle_scsi_cmd,
259 : scsi_minphys,
260 : qle_scsi_probe,
261 : NULL, /* scsi_free */
262 : NULL /* ioctl */
263 : };
264 :
265 : u_int32_t qle_read(struct qle_softc *, int);
266 : void qle_write(struct qle_softc *, int, u_int32_t);
267 : void qle_host_cmd(struct qle_softc *sc, u_int32_t);
268 :
269 : int qle_mbox(struct qle_softc *, int);
270 : int qle_ct_pass_through(struct qle_softc *sc,
271 : u_int32_t port_handle, struct qle_dmamem *mem,
272 : size_t req_size, size_t resp_size);
273 : void qle_mbox_putaddr(u_int16_t *, struct qle_dmamem *);
274 : u_int16_t qle_read_mbox(struct qle_softc *, int);
275 : void qle_write_mbox(struct qle_softc *, int, u_int16_t);
276 :
277 : void qle_handle_intr(struct qle_softc *, u_int16_t, u_int16_t);
278 : void qle_set_ints(struct qle_softc *, int);
279 : int qle_read_isr(struct qle_softc *, u_int16_t *, u_int16_t *);
280 : void qle_clear_isr(struct qle_softc *, u_int16_t);
281 :
282 : void qle_put_marker(struct qle_softc *, void *);
283 : void qle_put_cmd(struct qle_softc *, void *, struct scsi_xfer *,
284 : struct qle_ccb *, u_int32_t);
285 : struct qle_ccb *qle_handle_resp(struct qle_softc *, u_int32_t);
286 : void qle_sge(struct qle_iocb_seg *, u_int64_t, u_int32_t);
287 :
288 : struct qle_fc_port *qle_next_fabric_port(struct qle_softc *, u_int32_t *,
289 : u_int32_t *);
290 : int qle_get_port_db(struct qle_softc *, u_int16_t,
291 : struct qle_dmamem *);
292 : int qle_get_port_name_list(struct qle_softc *sc, u_int32_t);
293 : int qle_add_loop_port(struct qle_softc *, struct qle_fc_port *);
294 : int qle_add_fabric_port(struct qle_softc *, struct qle_fc_port *);
295 : int qle_add_logged_in_port(struct qle_softc *, u_int16_t,
296 : u_int32_t);
297 : int qle_classify_port(struct qle_softc *, u_int32_t, u_int64_t,
298 : u_int64_t, struct qle_fc_port **);
299 : int qle_get_loop_id(struct qle_softc *sc, int);
300 : void qle_clear_port_lists(struct qle_softc *);
301 : int qle_softreset(struct qle_softc *);
302 : void qle_update_topology(struct qle_softc *);
303 : int qle_update_fabric(struct qle_softc *);
304 : int qle_fabric_plogx(struct qle_softc *, struct qle_fc_port *, int,
305 : u_int32_t *);
306 : int qle_fabric_plogi(struct qle_softc *, struct qle_fc_port *);
307 : void qle_fabric_plogo(struct qle_softc *, struct qle_fc_port *);
308 :
309 : void qle_update_start(struct qle_softc *, int);
310 : void qle_update_defer(struct qle_softc *, int);
311 : void qle_update_cancel(struct qle_softc *);
312 : void qle_update_done(struct qle_softc *, int);
313 : void qle_do_update(void *);
314 : void qle_deferred_update(void *);
315 : int qle_async(struct qle_softc *, u_int16_t);
316 :
317 : int qle_load_fwchunk(struct qle_softc *,
318 : struct qle_dmamem *, const u_int32_t *);
319 : u_int32_t qle_read_ram_word(struct qle_softc *, u_int32_t);
320 : int qle_verify_firmware(struct qle_softc *, u_int32_t);
321 : int qle_load_firmware_chunks(struct qle_softc *, const u_int32_t *);
322 : int qle_read_nvram(struct qle_softc *);
323 :
324 : struct qle_dmamem *qle_dmamem_alloc(struct qle_softc *, size_t);
325 : void qle_dmamem_free(struct qle_softc *, struct qle_dmamem *);
326 :
327 : int qle_alloc_ccbs(struct qle_softc *);
328 : void qle_free_ccbs(struct qle_softc *);
329 : void *qle_get_ccb(void *);
330 : void qle_put_ccb(void *, void *);
331 :
332 : void qle_dump_stuff(struct qle_softc *, void *, int);
333 : void qle_dump_iocb(struct qle_softc *, void *);
334 : void qle_dump_iocb_segs(struct qle_softc *, void *, int);
335 :
336 : static const struct pci_matchid qle_devices[] = {
337 : { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2422 },
338 : { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2432 },
339 : { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2512 },
340 : { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2522 },
341 : { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP2532 },
342 : };
343 :
344 : int
345 0 : qle_match(struct device *parent, void *match, void *aux)
346 : {
347 0 : return (pci_matchbyid(aux, qle_devices, nitems(qle_devices)));
348 : }
349 :
350 : void
351 0 : qle_attach(struct device *parent, struct device *self, void *aux)
352 : {
353 0 : struct qle_softc *sc = (void *)self;
354 0 : struct pci_attach_args *pa = aux;
355 0 : pci_intr_handle_t ih;
356 : const char *intrstr;
357 : u_int32_t pcictl;
358 0 : struct scsibus_attach_args saa;
359 : struct qle_init_cb *icb;
360 : bus_size_t mbox_base;
361 : u_int32_t firmware_addr;
362 : #ifndef QLE_NOFIRMWARE
363 : const u_int32_t *firmware = NULL;
364 : #endif
365 :
366 0 : pcireg_t bars[] = { QLE_PCI_MEM_BAR, QLE_PCI_IO_BAR };
367 : pcireg_t memtype;
368 : int r, i, rv, loop_up;
369 :
370 0 : sc->sc_pc = pa->pa_pc;
371 0 : sc->sc_tag = pa->pa_tag;
372 0 : sc->sc_ih = NULL;
373 0 : sc->sc_dmat = pa->pa_dmat;
374 0 : sc->sc_ios = 0;
375 :
376 0 : for (r = 0; r < nitems(bars); r++) {
377 0 : memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, bars[r]);
378 0 : if (pci_mapreg_map(pa, bars[r], memtype, 0,
379 0 : &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios, 0) == 0)
380 : break;
381 :
382 0 : sc->sc_ios = 0;
383 : }
384 0 : if (sc->sc_ios == 0) {
385 0 : printf(": unable to map registers\n");
386 0 : return;
387 : }
388 :
389 0 : if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
390 0 : printf(": unable to map interrupt\n");
391 0 : goto unmap;
392 : }
393 0 : intrstr = pci_intr_string(sc->sc_pc, ih);
394 0 : sc->sc_ih = pci_intr_establish(sc->sc_pc, ih, IPL_BIO,
395 0 : qle_intr, sc, DEVNAME(sc));
396 0 : if (sc->sc_ih == NULL) {
397 0 : printf(": unable to establish interrupt");
398 0 : if (intrstr != NULL)
399 0 : printf(" at %s", intrstr);
400 0 : printf("\n");
401 0 : goto deintr;
402 : }
403 :
404 0 : printf(": %s\n", intrstr);
405 :
406 0 : pcictl = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
407 0 : pcictl |= PCI_COMMAND_INVALIDATE_ENABLE |
408 : PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE;
409 0 : pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, pcictl);
410 :
411 0 : pcictl = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
412 0 : pcictl &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
413 0 : pcictl &= ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT);
414 0 : pcictl |= (0x80 << PCI_LATTIMER_SHIFT);
415 0 : pcictl |= (0x10 << PCI_CACHELINE_SHIFT);
416 0 : pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, pcictl);
417 :
418 0 : pcictl = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
419 0 : pcictl &= ~1;
420 0 : pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, pcictl);
421 :
422 0 : switch (PCI_PRODUCT(pa->pa_id)) {
423 : case PCI_PRODUCT_QLOGIC_ISP2422:
424 0 : sc->sc_isp_type = QLE_ISP2422;
425 0 : sc->sc_isp_gen = QLE_GEN_ISP24XX;
426 0 : break;
427 : case PCI_PRODUCT_QLOGIC_ISP2432:
428 0 : sc->sc_isp_type = QLE_ISP2432;
429 0 : sc->sc_isp_gen = QLE_GEN_ISP24XX;
430 0 : break;
431 : case PCI_PRODUCT_QLOGIC_ISP2512:
432 0 : sc->sc_isp_type = QLE_ISP2512;
433 0 : sc->sc_isp_gen = QLE_GEN_ISP25XX;
434 0 : break;
435 : case PCI_PRODUCT_QLOGIC_ISP2522:
436 0 : sc->sc_isp_type = QLE_ISP2522;
437 0 : sc->sc_isp_gen = QLE_GEN_ISP25XX;
438 0 : break;
439 : case PCI_PRODUCT_QLOGIC_ISP2532:
440 0 : sc->sc_isp_type = QLE_ISP2532;
441 0 : sc->sc_isp_gen = QLE_GEN_ISP25XX;
442 0 : break;
443 :
444 : default:
445 0 : printf("unknown pci id %x", pa->pa_id);
446 0 : goto deintr;
447 : }
448 :
449 : /* these are the same for 24xx and 25xx but may vary later */
450 : mbox_base = QLE_MBOX_BASE_24XX;
451 : firmware_addr = QLE_2400_CODE_ORG;
452 :
453 0 : if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, mbox_base,
454 0 : sizeof(sc->sc_mbox), &sc->sc_mbox_ioh) != 0) {
455 0 : printf("%s: unable to map mbox registers\n", DEVNAME(sc));
456 0 : goto deintr;
457 : }
458 :
459 0 : sc->sc_port = pa->pa_function;
460 :
461 0 : TAILQ_INIT(&sc->sc_ports);
462 0 : TAILQ_INIT(&sc->sc_ports_new);
463 0 : TAILQ_INIT(&sc->sc_ports_gone);
464 0 : TAILQ_INIT(&sc->sc_ports_found);
465 :
466 : /* after reset, mbox regs 1 and 2 contain the string "ISP " */
467 0 : if (qle_read_mbox(sc, 1) != 0x4953 ||
468 0 : qle_read_mbox(sc, 2) != 0x5020) {
469 : /* try releasing the risc processor */
470 0 : qle_host_cmd(sc, QLE_HOST_CMD_RELEASE);
471 0 : }
472 :
473 0 : qle_host_cmd(sc, QLE_HOST_CMD_PAUSE);
474 0 : if (qle_softreset(sc) != 0) {
475 0 : printf("softreset failed\n");
476 0 : goto deintr;
477 : }
478 :
479 0 : if (qle_read_nvram(sc) == 0)
480 0 : sc->sc_nvram_valid = 1;
481 :
482 : #ifdef QLE_NOFIRMWARE
483 : if (qle_verify_firmware(sc, firmware_addr)) {
484 : printf("%s: no firmware loaded\n", DEVNAME(sc));
485 : goto deintr;
486 : }
487 : #else
488 0 : switch (sc->sc_isp_gen) {
489 : case QLE_GEN_ISP24XX:
490 : firmware = isp_2400_risc_code;
491 0 : break;
492 : case QLE_GEN_ISP25XX:
493 : firmware = isp_2500_risc_code;
494 0 : break;
495 : default:
496 0 : printf("%s: no firmware to load?\n", DEVNAME(sc));
497 0 : goto deintr;
498 : }
499 0 : if (qle_load_firmware_chunks(sc, firmware)) {
500 0 : printf("%s: firmware load failed\n", DEVNAME(sc));
501 0 : goto deintr;
502 : }
503 : #endif
504 :
505 : /* execute firmware */
506 0 : sc->sc_mbox[0] = QLE_MBOX_EXEC_FIRMWARE;
507 0 : sc->sc_mbox[1] = firmware_addr >> 16;
508 0 : sc->sc_mbox[2] = firmware_addr & 0xffff;
509 : #ifdef QLE_NOFIRMWARE
510 : sc->sc_mbox[3] = 1;
511 : #else
512 0 : sc->sc_mbox[3] = 0;
513 : #endif
514 0 : sc->sc_mbox[4] = 0;
515 0 : if (qle_mbox(sc, 0x001f)) {
516 0 : printf("ISP couldn't exec firmware: %x\n", sc->sc_mbox[0]);
517 0 : goto deintr;
518 : }
519 :
520 0 : delay(250000); /* from isp(4) */
521 :
522 0 : sc->sc_mbox[0] = QLE_MBOX_ABOUT_FIRMWARE;
523 0 : if (qle_mbox(sc, 0x0001)) {
524 0 : printf("ISP not talking after firmware exec: %x\n",
525 0 : sc->sc_mbox[0]);
526 0 : goto deintr;
527 : }
528 0 : printf("%s: firmware rev %d.%d.%d, attrs 0x%x\n", DEVNAME(sc),
529 0 : sc->sc_mbox[1], sc->sc_mbox[2], sc->sc_mbox[3], sc->sc_mbox[6]);
530 :
531 0 : sc->sc_maxcmds = 4096;
532 :
533 : /* reserve queue slots for markers and fabric ops */
534 0 : sc->sc_maxcmds -= 2;
535 :
536 0 : if (qle_alloc_ccbs(sc)) {
537 : /* error already printed */
538 : goto deintr;
539 : }
540 0 : sc->sc_scratch = qle_dmamem_alloc(sc, QLE_SCRATCH_SIZE);
541 0 : if (sc->sc_scratch == NULL) {
542 0 : printf("%s: unable to allocate scratch\n", DEVNAME(sc));
543 0 : goto free_ccbs;
544 : }
545 :
546 : /* build init buffer thing */
547 0 : icb = (struct qle_init_cb *)QLE_DMA_KVA(sc->sc_scratch);
548 0 : memset(icb, 0, sizeof(*icb));
549 0 : icb->icb_version = QLE_ICB_VERSION;
550 0 : if (sc->sc_nvram_valid) {
551 0 : icb->icb_max_frame_len = sc->sc_nvram.frame_payload_size;
552 0 : icb->icb_exec_throttle = sc->sc_nvram.execution_throttle;
553 0 : icb->icb_hardaddr = sc->sc_nvram.hard_address;
554 0 : icb->icb_portname = sc->sc_nvram.port_name;
555 0 : icb->icb_nodename = sc->sc_nvram.node_name;
556 0 : icb->icb_login_retry = sc->sc_nvram.login_retry;
557 0 : icb->icb_login_timeout = sc->sc_nvram.login_timeout;
558 0 : icb->icb_fwoptions1 = sc->sc_nvram.fwoptions1;
559 0 : icb->icb_fwoptions2 = sc->sc_nvram.fwoptions2;
560 0 : icb->icb_fwoptions3 = sc->sc_nvram.fwoptions3;
561 0 : } else {
562 : /* defaults copied from isp(4) */
563 0 : htolem16(&icb->icb_max_frame_len, 1024);
564 0 : htolem16(&icb->icb_exec_throttle, 16);
565 0 : icb->icb_portname = htobe64(QLE_DEFAULT_PORT_NAME);
566 0 : icb->icb_nodename = 0;
567 0 : icb->icb_login_retry = 3;
568 :
569 0 : htolem32(&icb->icb_fwoptions1, QLE_ICB_FW1_FAIRNESS |
570 : QLE_ICB_FW1_HARD_ADDR | QLE_ICB_FW1_FULL_DUPLEX);
571 0 : htolem32(&icb->icb_fwoptions2, QLE_ICB_FW2_LOOP_PTP);
572 0 : htolem32(&icb->icb_fwoptions3, QLE_ICB_FW3_FCP_RSP_24_0 |
573 : QLE_ICB_FW3_AUTONEG);
574 : }
575 :
576 0 : icb->icb_exchange_count = 0;
577 :
578 0 : icb->icb_req_out = 0;
579 0 : icb->icb_resp_in = 0;
580 0 : icb->icb_pri_req_out = 0;
581 0 : htolem16(&icb->icb_req_queue_len, sc->sc_maxcmds);
582 0 : htolem16(&icb->icb_resp_queue_len, sc->sc_maxcmds);
583 0 : htolem16(&icb->icb_pri_req_queue_len, 8); /* apparently the minimum */
584 0 : htolem32(&icb->icb_req_queue_addr_lo,
585 : QLE_DMA_DVA(sc->sc_requests));
586 0 : htolem32(&icb->icb_req_queue_addr_hi,
587 : QLE_DMA_DVA(sc->sc_requests) >> 32);
588 0 : htolem32(&icb->icb_resp_queue_addr_lo,
589 : QLE_DMA_DVA(sc->sc_responses));
590 0 : htolem32(&icb->icb_resp_queue_addr_hi,
591 : QLE_DMA_DVA(sc->sc_responses) >> 32);
592 0 : htolem32(&icb->icb_pri_req_queue_addr_lo,
593 : QLE_DMA_DVA(sc->sc_pri_requests));
594 0 : htolem32(&icb->icb_pri_req_queue_addr_hi,
595 : QLE_DMA_DVA(sc->sc_pri_requests) >> 32);
596 :
597 0 : htolem16(&icb->icb_link_down_nos, 200);
598 0 : icb->icb_int_delay = 0;
599 0 : icb->icb_login_timeout = 0;
600 :
601 0 : sc->sc_mbox[0] = QLE_MBOX_INIT_FIRMWARE;
602 0 : sc->sc_mbox[4] = 0;
603 0 : sc->sc_mbox[5] = 0;
604 0 : qle_mbox_putaddr(sc->sc_mbox, sc->sc_scratch);
605 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_scratch), 0,
606 : sizeof(*icb), BUS_DMASYNC_PREWRITE);
607 0 : rv = qle_mbox(sc, 0x00fd);
608 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_scratch), 0,
609 : sizeof(*icb), BUS_DMASYNC_POSTWRITE);
610 :
611 0 : if (rv != 0) {
612 0 : printf("%s: ISP firmware init failed: %x\n", DEVNAME(sc),
613 0 : sc->sc_mbox[0]);
614 0 : goto free_scratch;
615 : }
616 :
617 : /* enable some more notifications */
618 0 : sc->sc_mbox[0] = QLE_MBOX_SET_FIRMWARE_OPTIONS;
619 0 : sc->sc_mbox[1] = QLE_FW_OPTION1_ASYNC_LIP_F8 |
620 : QLE_FW_OPTION1_ASYNC_LIP_RESET |
621 : QLE_FW_OPTION1_ASYNC_LIP_ERROR |
622 : QLE_FW_OPTION1_ASYNC_LOGIN_RJT;
623 0 : sc->sc_mbox[2] = 0;
624 0 : sc->sc_mbox[3] = 0;
625 0 : if (qle_mbox(sc, 0x000f)) {
626 0 : printf("%s: setting firmware options failed: %x\n",
627 0 : DEVNAME(sc), sc->sc_mbox[0]);
628 0 : goto free_scratch;
629 : }
630 :
631 0 : sc->sc_update_taskq = taskq_create(DEVNAME(sc), 1, IPL_BIO, 0);
632 0 : task_set(&sc->sc_update_task, qle_do_update, sc);
633 0 : timeout_set(&sc->sc_update_timeout, qle_deferred_update, sc);
634 :
635 : /* wait a bit for link to come up so we can scan and attach devices */
636 0 : for (i = 0; i < QLE_WAIT_FOR_LOOP * 1000; i++) {
637 0 : u_int16_t isr, info;
638 :
639 0 : if (sc->sc_loop_up) {
640 0 : if (++loop_up == QLE_LOOP_SETTLE)
641 0 : break;
642 : } else
643 : loop_up = 0;
644 :
645 0 : delay(1000);
646 :
647 0 : if (qle_read_isr(sc, &isr, &info) == 0)
648 0 : continue;
649 :
650 0 : qle_handle_intr(sc, isr, info);
651 :
652 0 : }
653 :
654 0 : if (sc->sc_loop_up) {
655 0 : qle_do_update(sc);
656 0 : } else {
657 : DPRINTF(QLE_D_PORT, "%s: loop still down, giving up\n",
658 : DEVNAME(sc));
659 : }
660 :
661 : /* we should be good to go now, attach scsibus */
662 0 : sc->sc_link.adapter = &qle_switch;
663 0 : sc->sc_link.adapter_softc = sc;
664 0 : sc->sc_link.adapter_target = QLE_MAX_TARGETS;
665 0 : sc->sc_link.adapter_buswidth = QLE_MAX_TARGETS;
666 0 : sc->sc_link.openings = sc->sc_maxcmds;
667 0 : sc->sc_link.pool = &sc->sc_iopool;
668 0 : if (sc->sc_nvram_valid) {
669 0 : sc->sc_link.port_wwn = betoh64(sc->sc_nvram.port_name);
670 0 : sc->sc_link.node_wwn = betoh64(sc->sc_nvram.node_name);
671 0 : } else {
672 0 : sc->sc_link.port_wwn = QLE_DEFAULT_PORT_NAME;
673 0 : sc->sc_link.node_wwn = 0;
674 : }
675 0 : if (sc->sc_link.node_wwn == 0) {
676 : /*
677 : * mask out the port number from the port name to get
678 : * the node name.
679 : */
680 0 : sc->sc_link.node_wwn = sc->sc_link.port_wwn;
681 0 : sc->sc_link.node_wwn &= ~(0xfULL << 56);
682 0 : }
683 :
684 0 : memset(&saa, 0, sizeof(saa));
685 0 : saa.saa_sc_link = &sc->sc_link;
686 :
687 : /* config_found() returns the scsibus attached to us */
688 0 : sc->sc_scsibus = (struct scsibus_softc *)config_found(&sc->sc_dev,
689 : &saa, scsiprint);
690 :
691 0 : return;
692 :
693 : free_scratch:
694 0 : qle_dmamem_free(sc, sc->sc_scratch);
695 : free_ccbs:
696 0 : qle_free_ccbs(sc);
697 : deintr:
698 0 : pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
699 0 : sc->sc_ih = NULL;
700 : unmap:
701 0 : bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
702 0 : sc->sc_ios = 0;
703 0 : }
704 :
705 : int
706 0 : qle_detach(struct device *self, int flags)
707 : {
708 0 : struct qle_softc *sc = (struct qle_softc *)self;
709 :
710 0 : if (sc->sc_ih == NULL) {
711 : /* we didnt attach properly, so nothing to detach */
712 0 : return (0);
713 : }
714 :
715 0 : pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
716 0 : sc->sc_ih = NULL;
717 :
718 0 : bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
719 0 : sc->sc_ios = 0;
720 :
721 0 : return (0);
722 0 : }
723 :
724 : int
725 0 : qle_classify_port(struct qle_softc *sc, u_int32_t location,
726 : u_int64_t port_name, u_int64_t node_name, struct qle_fc_port **prev)
727 : {
728 : struct qle_fc_port *port, *locmatch, *wwnmatch;
729 : locmatch = NULL;
730 : wwnmatch = NULL;
731 :
732 : /* make sure we don't try to add a port or location twice */
733 0 : TAILQ_FOREACH(port, &sc->sc_ports_new, update) {
734 0 : if ((port->port_name == port_name &&
735 0 : port->node_name == node_name) ||
736 0 : port->location == location) {
737 0 : *prev = port;
738 0 : return (QLE_PORT_DISP_DUP);
739 : }
740 : }
741 :
742 : /* if we're attaching, everything is new */
743 0 : if (sc->sc_scsibus == NULL) {
744 0 : *prev = NULL;
745 0 : return (QLE_PORT_DISP_NEW);
746 : }
747 :
748 0 : TAILQ_FOREACH(port, &sc->sc_ports, ports) {
749 0 : if (port->location == location)
750 0 : locmatch = port;
751 :
752 0 : if (port->port_name == port_name &&
753 0 : port->node_name == node_name)
754 0 : wwnmatch = port;
755 : }
756 :
757 0 : if (locmatch == NULL && wwnmatch == NULL) {
758 0 : *prev = NULL;
759 0 : return (QLE_PORT_DISP_NEW);
760 0 : } else if (locmatch == wwnmatch) {
761 0 : *prev = locmatch;
762 0 : return (QLE_PORT_DISP_SAME);
763 0 : } else if (wwnmatch != NULL) {
764 0 : *prev = wwnmatch;
765 0 : return (QLE_PORT_DISP_MOVED);
766 : } else {
767 0 : *prev = locmatch;
768 0 : return (QLE_PORT_DISP_CHANGED);
769 : }
770 0 : }
771 :
772 : int
773 0 : qle_get_loop_id(struct qle_softc *sc, int start)
774 : {
775 : int i, last;
776 :
777 : i = QLE_MIN_HANDLE;
778 : last = QLE_MAX_HANDLE;
779 0 : if (i < start)
780 0 : i = start;
781 :
782 0 : for (; i <= last; i++) {
783 0 : if (sc->sc_targets[i] == NULL)
784 0 : return (i);
785 : }
786 :
787 0 : return (-1);
788 0 : }
789 :
790 : int
791 0 : qle_get_port_db(struct qle_softc *sc, u_int16_t loopid, struct qle_dmamem *mem)
792 : {
793 0 : sc->sc_mbox[0] = QLE_MBOX_GET_PORT_DB;
794 0 : sc->sc_mbox[1] = loopid;
795 0 : qle_mbox_putaddr(sc->sc_mbox, mem);
796 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(mem), 0,
797 : sizeof(struct qle_get_port_db), BUS_DMASYNC_PREREAD);
798 0 : if (qle_mbox(sc, 0x00cf)) {
799 : DPRINTF(QLE_D_PORT, "%s: get port db for %d failed: %x\n",
800 : DEVNAME(sc), loopid, sc->sc_mbox[0]);
801 0 : return (1);
802 : }
803 :
804 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(mem), 0,
805 : sizeof(struct qle_get_port_db), BUS_DMASYNC_POSTREAD);
806 0 : return (0);
807 0 : }
808 :
809 : int
810 0 : qle_get_port_name_list(struct qle_softc *sc, u_int32_t match)
811 : {
812 : struct qle_port_name_list *l;
813 : struct qle_fc_port *port;
814 : int i;
815 :
816 0 : sc->sc_mbox[0] = QLE_MBOX_GET_PORT_NAME_LIST;
817 0 : sc->sc_mbox[1] = 0;
818 0 : sc->sc_mbox[8] = QLE_DMA_LEN(sc->sc_scratch);
819 0 : sc->sc_mbox[9] = 0;
820 0 : qle_mbox_putaddr(sc->sc_mbox, sc->sc_scratch);
821 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_scratch), 0,
822 : QLE_DMA_LEN(sc->sc_scratch), BUS_DMASYNC_PREREAD);
823 0 : if (qle_mbox(sc, 0x03cf)) {
824 : DPRINTF(QLE_D_PORT, "%s: get port name list failed: %x\n",
825 : DEVNAME(sc), sc->sc_mbox[0]);
826 0 : return (1);
827 : }
828 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_scratch), 0,
829 : sc->sc_mbox[1], BUS_DMASYNC_POSTREAD);
830 :
831 : i = 0;
832 0 : l = QLE_DMA_KVA(sc->sc_scratch);
833 0 : mtx_enter(&sc->sc_port_mtx);
834 0 : while (i * sizeof(*l) < sc->sc_mbox[1]) {
835 : u_int16_t loopid;
836 : u_int32_t loc;
837 :
838 0 : loopid = lemtoh16(&l[i].loopid) & 0xfff;
839 : /* skip special ports */
840 0 : switch (loopid) {
841 : case QLE_F_PORT_HANDLE:
842 : case QLE_SNS_HANDLE:
843 : case QLE_FABRIC_CTRL_HANDLE:
844 : case QLE_IP_BCAST_HANDLE:
845 : loc = 0;
846 0 : break;
847 : default:
848 0 : if (loopid <= sc->sc_loop_max_id) {
849 0 : loc = QLE_LOCATION_LOOP_ID(loopid);
850 0 : } else {
851 : /*
852 : * we don't have the port id here, so just
853 : * indicate it's a fabric port.
854 : */
855 : loc = QLE_LOCATION_FABRIC;
856 : }
857 : break;
858 : }
859 :
860 0 : if (match & loc) {
861 0 : port = malloc(sizeof(*port), M_DEVBUF, M_ZERO |
862 : M_NOWAIT);
863 0 : if (port == NULL) {
864 0 : printf("%s: failed to allocate port struct\n",
865 0 : DEVNAME(sc));
866 0 : break;
867 : }
868 0 : port->location = loc;
869 0 : port->loopid = loopid;
870 0 : port->port_name = letoh64(l[i].port_name);
871 : DPRINTF(QLE_D_PORT, "%s: loop id %d, port name %llx\n",
872 : DEVNAME(sc), port->loopid, port->port_name);
873 0 : TAILQ_INSERT_TAIL(&sc->sc_ports_found, port, update);
874 0 : }
875 0 : i++;
876 0 : }
877 0 : mtx_leave(&sc->sc_port_mtx);
878 :
879 0 : return (0);
880 0 : }
881 :
882 : int
883 0 : qle_add_loop_port(struct qle_softc *sc, struct qle_fc_port *port)
884 : {
885 : struct qle_get_port_db *pdb;
886 0 : struct qle_fc_port *pport;
887 : int disp;
888 :
889 0 : if (qle_get_port_db(sc, port->loopid, sc->sc_scratch) != 0) {
890 0 : return (1);
891 : }
892 0 : pdb = QLE_DMA_KVA(sc->sc_scratch);
893 :
894 0 : if (lemtoh16(&pdb->prli_svc_word3) & QLE_SVC3_TARGET_ROLE)
895 0 : port->flags |= QLE_PORT_FLAG_IS_TARGET;
896 :
897 0 : port->port_name = betoh64(pdb->port_name);
898 0 : port->node_name = betoh64(pdb->node_name);
899 0 : port->portid = (pdb->port_id[0] << 16) | (pdb->port_id[1] << 8) |
900 0 : pdb->port_id[2];
901 :
902 0 : mtx_enter(&sc->sc_port_mtx);
903 0 : disp = qle_classify_port(sc, port->location, port->port_name,
904 0 : port->node_name, &pport);
905 0 : switch (disp) {
906 : case QLE_PORT_DISP_CHANGED:
907 : case QLE_PORT_DISP_MOVED:
908 : case QLE_PORT_DISP_NEW:
909 0 : TAILQ_INSERT_TAIL(&sc->sc_ports_new, port, update);
910 0 : sc->sc_targets[port->loopid] = port;
911 0 : break;
912 : case QLE_PORT_DISP_DUP:
913 0 : free(port, M_DEVBUF, sizeof *port);
914 0 : break;
915 : case QLE_PORT_DISP_SAME:
916 0 : TAILQ_REMOVE(&sc->sc_ports_gone, pport, update);
917 0 : free(port, M_DEVBUF, sizeof *port);
918 0 : break;
919 : }
920 0 : mtx_leave(&sc->sc_port_mtx);
921 :
922 : switch (disp) {
923 : case QLE_PORT_DISP_CHANGED:
924 : case QLE_PORT_DISP_MOVED:
925 : case QLE_PORT_DISP_NEW:
926 : DPRINTF(QLE_D_PORT, "%s: %s %d; name %llx\n",
927 : DEVNAME(sc), ISSET(port->flags, QLE_PORT_FLAG_IS_TARGET) ?
928 : "target" : "non-target", port->loopid,
929 : betoh64(pdb->port_name));
930 : break;
931 : default:
932 : break;
933 : }
934 0 : return (0);
935 0 : }
936 :
937 : int
938 0 : qle_add_fabric_port(struct qle_softc *sc, struct qle_fc_port *port)
939 : {
940 : struct qle_get_port_db *pdb;
941 :
942 0 : if (qle_get_port_db(sc, port->loopid, sc->sc_scratch) != 0) {
943 0 : free(port, M_DEVBUF, sizeof *port);
944 0 : return (1);
945 : }
946 0 : pdb = QLE_DMA_KVA(sc->sc_scratch);
947 :
948 0 : if (lemtoh16(&pdb->prli_svc_word3) & QLE_SVC3_TARGET_ROLE)
949 0 : port->flags |= QLE_PORT_FLAG_IS_TARGET;
950 :
951 : /*
952 : * if we only know about this port because qle_get_port_name_list
953 : * returned it, we don't have its port id or node name, so fill
954 : * those in and update its location.
955 : */
956 0 : if (port->location == QLE_LOCATION_FABRIC) {
957 0 : port->node_name = betoh64(pdb->node_name);
958 0 : port->port_name = betoh64(pdb->port_name);
959 0 : port->portid = (pdb->port_id[0] << 16) |
960 0 : (pdb->port_id[1] << 8) | pdb->port_id[2];
961 0 : port->location = QLE_LOCATION_PORT_ID(port->portid);
962 0 : }
963 :
964 0 : mtx_enter(&sc->sc_port_mtx);
965 0 : TAILQ_INSERT_TAIL(&sc->sc_ports_new, port, update);
966 0 : sc->sc_targets[port->loopid] = port;
967 0 : mtx_leave(&sc->sc_port_mtx);
968 :
969 : DPRINTF(QLE_D_PORT, "%s: %s %d; name %llx\n",
970 : DEVNAME(sc), ISSET(port->flags, QLE_PORT_FLAG_IS_TARGET) ?
971 : "target" : "non-target", port->loopid, port->port_name);
972 0 : return (0);
973 0 : }
974 :
975 : int
976 0 : qle_add_logged_in_port(struct qle_softc *sc, u_int16_t loopid,
977 : u_int32_t portid)
978 : {
979 : struct qle_fc_port *port;
980 : struct qle_get_port_db *pdb;
981 : u_int64_t node_name, port_name;
982 : int flags, ret;
983 :
984 0 : ret = qle_get_port_db(sc, loopid, sc->sc_scratch);
985 0 : mtx_enter(&sc->sc_port_mtx);
986 0 : if (ret != 0) {
987 : /* put in a fake port to prevent use of this loop id */
988 0 : printf("%s: loop id %d used, but can't see what's using it\n",
989 0 : DEVNAME(sc), loopid);
990 : node_name = 0;
991 : port_name = 0;
992 : flags = 0;
993 0 : } else {
994 0 : pdb = QLE_DMA_KVA(sc->sc_scratch);
995 0 : node_name = betoh64(pdb->node_name);
996 0 : port_name = betoh64(pdb->port_name);
997 : flags = 0;
998 0 : if (lemtoh16(&pdb->prli_svc_word3) & QLE_SVC3_TARGET_ROLE)
999 0 : flags |= QLE_PORT_FLAG_IS_TARGET;
1000 :
1001 : /* see if we've already found this port */
1002 0 : TAILQ_FOREACH(port, &sc->sc_ports_found, update) {
1003 0 : if ((port->node_name == node_name) &&
1004 0 : (port->port_name == port_name) &&
1005 0 : (port->portid == portid)) {
1006 0 : mtx_leave(&sc->sc_port_mtx);
1007 : DPRINTF(QLE_D_PORT, "%s: already found port "
1008 : "%06x\n", DEVNAME(sc), portid);
1009 0 : return (0);
1010 : }
1011 : }
1012 : }
1013 :
1014 0 : port = malloc(sizeof(*port), M_DEVBUF, M_ZERO | M_NOWAIT);
1015 0 : if (port == NULL) {
1016 0 : mtx_leave(&sc->sc_port_mtx);
1017 0 : printf("%s: failed to allocate a port structure\n",
1018 0 : DEVNAME(sc));
1019 0 : return (1);
1020 : }
1021 0 : port->location = QLE_LOCATION_PORT_ID(portid);
1022 0 : port->port_name = port_name;
1023 0 : port->node_name = node_name;
1024 0 : port->loopid = loopid;
1025 0 : port->portid = portid;
1026 0 : port->flags = flags;
1027 :
1028 0 : TAILQ_INSERT_TAIL(&sc->sc_ports, port, ports);
1029 0 : sc->sc_targets[port->loopid] = port;
1030 0 : mtx_leave(&sc->sc_port_mtx);
1031 :
1032 : DPRINTF(QLE_D_PORT, "%s: added logged in port %06x at %d\n",
1033 : DEVNAME(sc), portid, loopid);
1034 0 : return (0);
1035 0 : }
1036 :
1037 : struct qle_ccb *
1038 0 : qle_handle_resp(struct qle_softc *sc, u_int32_t id)
1039 : {
1040 : struct qle_ccb *ccb;
1041 : struct qle_iocb_status *status;
1042 : struct qle_iocb_req6 *req;
1043 : struct scsi_xfer *xs;
1044 : u_int32_t handle;
1045 : u_int16_t completion;
1046 : u_int8_t *entry;
1047 : u_int8_t *data;
1048 :
1049 : ccb = NULL;
1050 0 : entry = QLE_DMA_KVA(sc->sc_responses) + (id * QLE_QUEUE_ENTRY_SIZE);
1051 :
1052 0 : bus_dmamap_sync(sc->sc_dmat,
1053 : QLE_DMA_MAP(sc->sc_responses), id * QLE_QUEUE_ENTRY_SIZE,
1054 : QLE_QUEUE_ENTRY_SIZE, BUS_DMASYNC_POSTREAD);
1055 :
1056 0 : qle_dump_iocb(sc, entry);
1057 0 : switch(entry[0]) {
1058 : case QLE_IOCB_STATUS:
1059 0 : status = (struct qle_iocb_status *)entry;
1060 0 : handle = status->handle;
1061 0 : if (handle > sc->sc_maxcmds) {
1062 0 : panic("bad completed command handle: %d (> %d)",
1063 : handle, sc->sc_maxcmds);
1064 : }
1065 :
1066 0 : ccb = &sc->sc_ccbs[handle];
1067 0 : xs = ccb->ccb_xs;
1068 0 : if (xs == NULL) {
1069 : DPRINTF(QLE_D_IO, "%s: got status for inactive ccb %d\n",
1070 : DEVNAME(sc), handle);
1071 : ccb = NULL;
1072 0 : break;
1073 : }
1074 0 : if (xs->io != ccb) {
1075 0 : panic("completed command handle doesn't match xs "
1076 : "(handle %d, ccb %p, xs->io %p)", handle, ccb,
1077 : xs->io);
1078 : }
1079 :
1080 0 : if (xs->datalen > 0) {
1081 0 : if (ccb->ccb_dmamap->dm_nsegs >
1082 : QLE_IOCB_SEGS_PER_CMD) {
1083 0 : bus_dmamap_sync(sc->sc_dmat,
1084 : QLE_DMA_MAP(sc->sc_segments),
1085 : ccb->ccb_seg_offset,
1086 : sizeof(*ccb->ccb_segs) *
1087 : ccb->ccb_dmamap->dm_nsegs + 1,
1088 : BUS_DMASYNC_POSTWRITE);
1089 0 : }
1090 :
1091 0 : bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
1092 : ccb->ccb_dmamap->dm_mapsize,
1093 : (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
1094 : BUS_DMASYNC_POSTWRITE);
1095 0 : bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
1096 0 : }
1097 :
1098 0 : xs->status = lemtoh16(&status->scsi_status) & 0xff;
1099 0 : xs->resid = 0;
1100 0 : completion = lemtoh16(&status->completion);
1101 0 : switch (completion) {
1102 : case QLE_IOCB_STATUS_DATA_UNDERRUN:
1103 0 : xs->resid = lemtoh32(&status->resid);
1104 : case QLE_IOCB_STATUS_DATA_OVERRUN:
1105 : case QLE_IOCB_STATUS_COMPLETE:
1106 0 : if (lemtoh16(&status->scsi_status) &
1107 : QLE_SCSI_STATUS_SENSE_VALID) {
1108 : u_int32_t *pp;
1109 : int sr;
1110 0 : data = status->data +
1111 0 : lemtoh32(&status->fcp_rsp_len);
1112 0 : sr = MIN(lemtoh32(&status->fcp_sense_len),
1113 : sizeof(xs->sense));
1114 0 : memcpy(&xs->sense, data, sr);
1115 0 : xs->error = XS_SENSE;
1116 0 : pp = (u_int32_t *)&xs->sense;
1117 0 : for (sr = 0; sr < sizeof(xs->sense)/4; sr++) {
1118 0 : pp[sr] = swap32(pp[sr]);
1119 : }
1120 0 : } else {
1121 0 : xs->error = XS_NOERROR;
1122 : }
1123 : break;
1124 :
1125 : case QLE_IOCB_STATUS_DMA_ERROR:
1126 : DPRINTF(QLE_D_IO, "%s: dma error\n", DEVNAME(sc));
1127 : /* set resid apparently? */
1128 : break;
1129 :
1130 : case QLE_IOCB_STATUS_RESET:
1131 : DPRINTF(QLE_D_IO, "%s: reset destroyed command\n",
1132 : DEVNAME(sc));
1133 0 : sc->sc_marker_required = 1;
1134 0 : xs->error = XS_RESET;
1135 0 : break;
1136 :
1137 : case QLE_IOCB_STATUS_ABORTED:
1138 : DPRINTF(QLE_D_IO, "%s: aborted\n", DEVNAME(sc));
1139 0 : sc->sc_marker_required = 1;
1140 0 : xs->error = XS_DRIVER_STUFFUP;
1141 0 : break;
1142 :
1143 : case QLE_IOCB_STATUS_TIMEOUT:
1144 : DPRINTF(QLE_D_IO, "%s: command timed out\n",
1145 : DEVNAME(sc));
1146 0 : xs->error = XS_TIMEOUT;
1147 0 : break;
1148 :
1149 : case QLE_IOCB_STATUS_QUEUE_FULL:
1150 : DPRINTF(QLE_D_IO, "%s: queue full\n", DEVNAME(sc));
1151 0 : xs->error = XS_BUSY;
1152 0 : break;
1153 :
1154 : case QLE_IOCB_STATUS_PORT_UNAVAIL:
1155 : case QLE_IOCB_STATUS_PORT_LOGGED_OUT:
1156 : case QLE_IOCB_STATUS_PORT_CHANGED:
1157 : DPRINTF(QLE_D_IO, "%s: dev gone\n", DEVNAME(sc));
1158 0 : xs->error = XS_SELTIMEOUT;
1159 : /* mark port as needing relogin? */
1160 0 : break;
1161 :
1162 : default:
1163 : DPRINTF(QLE_D_IO, "%s: unexpected completion status "
1164 : "%x\n", DEVNAME(sc), status->completion);
1165 0 : xs->error = XS_DRIVER_STUFFUP;
1166 0 : break;
1167 : }
1168 : break;
1169 :
1170 : case QLE_IOCB_STATUS_CONT:
1171 : DPRINTF(QLE_D_IO, "%s: ignoring status continuation iocb\n",
1172 : DEVNAME(sc));
1173 : break;
1174 :
1175 : case QLE_IOCB_PLOGX:
1176 : case QLE_IOCB_CT_PASSTHROUGH:
1177 0 : if (sc->sc_fabric_pending) {
1178 0 : qle_dump_iocb(sc, entry);
1179 0 : memcpy(sc->sc_fabric_response, entry,
1180 : QLE_QUEUE_ENTRY_SIZE);
1181 0 : sc->sc_fabric_pending = 2;
1182 0 : wakeup(sc->sc_scratch);
1183 0 : } else {
1184 : DPRINTF(QLE_D_IO, "%s: unexpected fabric response %x\n",
1185 : DEVNAME(sc), entry[0]);
1186 : }
1187 : break;
1188 :
1189 : case QLE_IOCB_MARKER:
1190 : break;
1191 :
1192 : case QLE_IOCB_CMD_TYPE_6:
1193 : case QLE_IOCB_CMD_TYPE_7:
1194 : DPRINTF(QLE_D_IO, "%s: request bounced back\n", DEVNAME(sc));
1195 0 : req = (struct qle_iocb_req6 *)entry;
1196 0 : handle = req->req_handle;
1197 0 : if (handle > sc->sc_maxcmds) {
1198 0 : panic("bad bounced command handle: %d (> %d)",
1199 : handle, sc->sc_maxcmds);
1200 : }
1201 :
1202 0 : ccb = &sc->sc_ccbs[handle];
1203 0 : xs = ccb->ccb_xs;
1204 0 : xs->error = XS_DRIVER_STUFFUP;
1205 0 : break;
1206 : default:
1207 : DPRINTF(QLE_D_IO, "%s: unexpected response entry type %x\n",
1208 : DEVNAME(sc), entry[0]);
1209 : break;
1210 : }
1211 :
1212 0 : return (ccb);
1213 : }
1214 :
1215 : void
1216 0 : qle_handle_intr(struct qle_softc *sc, u_int16_t isr, u_int16_t info)
1217 : {
1218 : int i;
1219 : u_int32_t rspin;
1220 : struct qle_ccb *ccb;
1221 :
1222 0 : switch (isr) {
1223 : case QLE_INT_TYPE_ASYNC:
1224 0 : qle_async(sc, info);
1225 0 : break;
1226 :
1227 : case QLE_INT_TYPE_IO:
1228 0 : rspin = qle_read(sc, QLE_RESP_IN);
1229 0 : if (rspin == sc->sc_last_resp_id)
1230 : break;
1231 :
1232 0 : do {
1233 0 : ccb = qle_handle_resp(sc, sc->sc_last_resp_id);
1234 0 : if (ccb)
1235 0 : scsi_done(ccb->ccb_xs);
1236 :
1237 0 : sc->sc_last_resp_id++;
1238 0 : sc->sc_last_resp_id %= sc->sc_maxcmds;
1239 0 : } while (sc->sc_last_resp_id != rspin);
1240 :
1241 0 : qle_write(sc, QLE_RESP_OUT, sc->sc_last_resp_id);
1242 0 : break;
1243 :
1244 : case QLE_INT_TYPE_MBOX:
1245 0 : mtx_enter(&sc->sc_mbox_mtx);
1246 0 : if (sc->sc_mbox_pending) {
1247 0 : for (i = 0; i < nitems(sc->sc_mbox); i++) {
1248 0 : sc->sc_mbox[i] = qle_read_mbox(sc, i);
1249 : }
1250 0 : sc->sc_mbox_pending = 2;
1251 0 : wakeup(sc->sc_mbox);
1252 0 : mtx_leave(&sc->sc_mbox_mtx);
1253 0 : } else {
1254 0 : mtx_leave(&sc->sc_mbox_mtx);
1255 : DPRINTF(QLE_D_INTR, "%s: unexpected mbox interrupt: "
1256 : "%x\n", DEVNAME(sc), info);
1257 : }
1258 : break;
1259 :
1260 : default:
1261 : break;
1262 : }
1263 :
1264 0 : qle_clear_isr(sc, isr);
1265 0 : }
1266 :
1267 : int
1268 0 : qle_intr(void *xsc)
1269 : {
1270 0 : struct qle_softc *sc = xsc;
1271 0 : u_int16_t isr;
1272 0 : u_int16_t info;
1273 :
1274 0 : if (qle_read_isr(sc, &isr, &info) == 0)
1275 0 : return (0);
1276 :
1277 0 : qle_handle_intr(sc, isr, info);
1278 0 : return (1);
1279 0 : }
1280 :
1281 : int
1282 0 : qle_scsi_probe(struct scsi_link *link)
1283 : {
1284 0 : struct qle_softc *sc = link->adapter_softc;
1285 : int rv = 0;
1286 :
1287 0 : mtx_enter(&sc->sc_port_mtx);
1288 0 : if (sc->sc_targets[link->target] == NULL)
1289 0 : rv = ENXIO;
1290 0 : else if (!ISSET(sc->sc_targets[link->target]->flags,
1291 : QLE_PORT_FLAG_IS_TARGET))
1292 0 : rv = ENXIO;
1293 0 : mtx_leave(&sc->sc_port_mtx);
1294 :
1295 0 : return (rv);
1296 : }
1297 :
1298 : void
1299 0 : qle_scsi_cmd(struct scsi_xfer *xs)
1300 : {
1301 0 : struct scsi_link *link = xs->sc_link;
1302 0 : struct qle_softc *sc = link->adapter_softc;
1303 : struct qle_ccb *ccb;
1304 : void *iocb;
1305 0 : struct qle_ccb_list list;
1306 : u_int16_t req;
1307 : u_int32_t portid;
1308 : int offset, error, done;
1309 : bus_dmamap_t dmap;
1310 :
1311 0 : if (xs->cmdlen > 16) {
1312 : DPRINTF(QLE_D_IO, "%s: cmd too big (%d)\n", DEVNAME(sc),
1313 : xs->cmdlen);
1314 0 : memset(&xs->sense, 0, sizeof(xs->sense));
1315 0 : xs->sense.error_code = SSD_ERRCODE_VALID | SSD_ERRCODE_CURRENT;
1316 0 : xs->sense.flags = SKEY_ILLEGAL_REQUEST;
1317 0 : xs->sense.add_sense_code = 0x20;
1318 0 : xs->error = XS_SENSE;
1319 0 : scsi_done(xs);
1320 0 : return;
1321 : }
1322 :
1323 : portid = 0xffffffff;
1324 0 : mtx_enter(&sc->sc_port_mtx);
1325 0 : if (sc->sc_targets[xs->sc_link->target] != NULL) {
1326 0 : portid = sc->sc_targets[xs->sc_link->target]->portid;
1327 0 : }
1328 0 : mtx_leave(&sc->sc_port_mtx);
1329 0 : if (portid == 0xffffffff) {
1330 0 : xs->error = XS_DRIVER_STUFFUP;
1331 0 : scsi_done(xs);
1332 0 : return;
1333 : }
1334 :
1335 0 : ccb = xs->io;
1336 0 : dmap = ccb->ccb_dmamap;
1337 0 : if (xs->datalen > 0) {
1338 0 : error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data,
1339 : xs->datalen, NULL, (xs->flags & SCSI_NOSLEEP) ?
1340 : BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
1341 0 : if (error) {
1342 0 : xs->error = XS_DRIVER_STUFFUP;
1343 0 : scsi_done(xs);
1344 0 : return;
1345 : }
1346 :
1347 0 : bus_dmamap_sync(sc->sc_dmat, dmap, 0,
1348 : dmap->dm_mapsize,
1349 : (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
1350 : BUS_DMASYNC_PREWRITE);
1351 0 : }
1352 :
1353 0 : mtx_enter(&sc->sc_queue_mtx);
1354 :
1355 : /* put in a sync marker if required */
1356 0 : if (sc->sc_marker_required) {
1357 0 : req = sc->sc_next_req_id++;
1358 0 : if (sc->sc_next_req_id == sc->sc_maxcmds)
1359 0 : sc->sc_next_req_id = 0;
1360 :
1361 : DPRINTF(QLE_D_IO, "%s: writing marker at request %d\n",
1362 : DEVNAME(sc), req);
1363 0 : offset = (req * QLE_QUEUE_ENTRY_SIZE);
1364 0 : iocb = QLE_DMA_KVA(sc->sc_requests) + offset;
1365 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_requests),
1366 : offset, QLE_QUEUE_ENTRY_SIZE, BUS_DMASYNC_POSTWRITE);
1367 0 : qle_put_marker(sc, iocb);
1368 0 : qle_write(sc, QLE_REQ_IN, sc->sc_next_req_id);
1369 0 : sc->sc_marker_required = 0;
1370 0 : }
1371 :
1372 0 : req = sc->sc_next_req_id++;
1373 0 : if (sc->sc_next_req_id == sc->sc_maxcmds)
1374 0 : sc->sc_next_req_id = 0;
1375 :
1376 0 : offset = (req * QLE_QUEUE_ENTRY_SIZE);
1377 0 : iocb = QLE_DMA_KVA(sc->sc_requests) + offset;
1378 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_requests), offset,
1379 : QLE_QUEUE_ENTRY_SIZE, BUS_DMASYNC_POSTWRITE);
1380 :
1381 0 : ccb->ccb_xs = xs;
1382 :
1383 0 : qle_put_cmd(sc, iocb, xs, ccb, portid);
1384 :
1385 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_requests), offset,
1386 : QLE_QUEUE_ENTRY_SIZE, BUS_DMASYNC_PREREAD);
1387 0 : qle_write(sc, QLE_REQ_IN, sc->sc_next_req_id);
1388 :
1389 0 : if (!ISSET(xs->flags, SCSI_POLL)) {
1390 0 : mtx_leave(&sc->sc_queue_mtx);
1391 0 : return;
1392 : }
1393 :
1394 : done = 0;
1395 0 : SIMPLEQ_INIT(&list);
1396 0 : do {
1397 0 : u_int16_t isr, info;
1398 : u_int32_t rspin;
1399 0 : delay(100);
1400 :
1401 0 : if (qle_read_isr(sc, &isr, &info) == 0) {
1402 0 : continue;
1403 : }
1404 :
1405 0 : if (isr != QLE_INT_TYPE_IO) {
1406 0 : qle_handle_intr(sc, isr, info);
1407 0 : continue;
1408 : }
1409 :
1410 0 : rspin = qle_read(sc, QLE_RESP_IN);
1411 0 : while (rspin != sc->sc_last_resp_id) {
1412 0 : ccb = qle_handle_resp(sc, sc->sc_last_resp_id);
1413 :
1414 0 : sc->sc_last_resp_id++;
1415 0 : if (sc->sc_last_resp_id == sc->sc_maxcmds)
1416 0 : sc->sc_last_resp_id = 0;
1417 :
1418 0 : if (ccb != NULL)
1419 0 : SIMPLEQ_INSERT_TAIL(&list, ccb, ccb_link);
1420 0 : if (ccb == xs->io)
1421 0 : done = 1;
1422 : }
1423 0 : qle_write(sc, QLE_RESP_OUT, sc->sc_last_resp_id);
1424 0 : qle_clear_isr(sc, isr);
1425 0 : } while (done == 0);
1426 :
1427 0 : mtx_leave(&sc->sc_queue_mtx);
1428 :
1429 0 : while ((ccb = SIMPLEQ_FIRST(&list)) != NULL) {
1430 0 : SIMPLEQ_REMOVE_HEAD(&list, ccb_link);
1431 0 : scsi_done(ccb->ccb_xs);
1432 : }
1433 0 : }
1434 :
1435 : u_int32_t
1436 0 : qle_read(struct qle_softc *sc, int offset)
1437 : {
1438 : u_int32_t v;
1439 0 : v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
1440 0 : bus_space_barrier(sc->sc_iot, sc->sc_ioh, offset, 4,
1441 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1442 0 : return (v);
1443 : }
1444 :
1445 : void
1446 0 : qle_write(struct qle_softc *sc, int offset, u_int32_t value)
1447 : {
1448 0 : bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, value);
1449 0 : bus_space_barrier(sc->sc_iot, sc->sc_ioh, offset, 4,
1450 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1451 0 : }
1452 :
1453 : u_int16_t
1454 0 : qle_read_mbox(struct qle_softc *sc, int mbox)
1455 : {
1456 : u_int16_t v;
1457 0 : bus_size_t offset = mbox * 2;
1458 0 : v = bus_space_read_2(sc->sc_iot, sc->sc_mbox_ioh, offset);
1459 0 : bus_space_barrier(sc->sc_iot, sc->sc_mbox_ioh, offset, 2,
1460 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1461 0 : return (v);
1462 : }
1463 :
1464 : void
1465 0 : qle_write_mbox(struct qle_softc *sc, int mbox, u_int16_t value)
1466 : {
1467 0 : bus_size_t offset = (mbox * 2);
1468 0 : bus_space_write_2(sc->sc_iot, sc->sc_mbox_ioh, offset, value);
1469 0 : bus_space_barrier(sc->sc_iot, sc->sc_mbox_ioh, offset, 2,
1470 : BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1471 0 : }
1472 :
1473 : void
1474 0 : qle_host_cmd(struct qle_softc *sc, u_int32_t cmd)
1475 : {
1476 0 : qle_write(sc, QLE_HOST_CMD_CTRL, cmd << QLE_HOST_CMD_SHIFT);
1477 0 : }
1478 :
1479 : #define MBOX_COMMAND_TIMEOUT 400000
1480 :
1481 : int
1482 0 : qle_mbox(struct qle_softc *sc, int maskin)
1483 : {
1484 : int i;
1485 : int result = 0;
1486 : int rv;
1487 :
1488 0 : for (i = 0; i < nitems(sc->sc_mbox); i++) {
1489 0 : if (maskin & (1 << i)) {
1490 0 : qle_write_mbox(sc, i, sc->sc_mbox[i]);
1491 0 : }
1492 : }
1493 0 : qle_host_cmd(sc, QLE_HOST_CMD_SET_HOST_INT);
1494 :
1495 0 : if (sc->sc_scsibus != NULL) {
1496 0 : mtx_enter(&sc->sc_mbox_mtx);
1497 0 : sc->sc_mbox_pending = 1;
1498 0 : while (sc->sc_mbox_pending == 1) {
1499 0 : msleep(sc->sc_mbox, &sc->sc_mbox_mtx, PRIBIO,
1500 : "qlembox", 0);
1501 : }
1502 0 : result = sc->sc_mbox[0];
1503 0 : sc->sc_mbox_pending = 0;
1504 0 : mtx_leave(&sc->sc_mbox_mtx);
1505 0 : return (result == QLE_MBOX_COMPLETE ? 0 : result);
1506 : }
1507 :
1508 0 : for (i = 0; i < MBOX_COMMAND_TIMEOUT && result == 0; i++) {
1509 0 : u_int16_t isr, info;
1510 :
1511 0 : delay(100);
1512 :
1513 0 : if (qle_read_isr(sc, &isr, &info) == 0)
1514 0 : continue;
1515 :
1516 0 : switch (isr) {
1517 : case QLE_INT_TYPE_MBOX:
1518 0 : result = info;
1519 0 : break;
1520 :
1521 : default:
1522 0 : qle_handle_intr(sc, isr, info);
1523 0 : break;
1524 : }
1525 0 : }
1526 :
1527 0 : if (result == 0) {
1528 : /* timed out; do something? */
1529 : DPRINTF(QLE_D_MBOX, "%s: mbox timed out\n", DEVNAME(sc));
1530 : rv = 1;
1531 0 : } else {
1532 0 : for (i = 0; i < nitems(sc->sc_mbox); i++) {
1533 0 : sc->sc_mbox[i] = qle_read_mbox(sc, i);
1534 : }
1535 0 : rv = (result == QLE_MBOX_COMPLETE ? 0 : result);
1536 : }
1537 :
1538 0 : qle_clear_isr(sc, QLE_INT_TYPE_MBOX);
1539 0 : return (rv);
1540 0 : }
1541 :
1542 : void
1543 0 : qle_mbox_putaddr(u_int16_t *mbox, struct qle_dmamem *mem)
1544 : {
1545 0 : mbox[2] = (QLE_DMA_DVA(mem) >> 16) & 0xffff;
1546 0 : mbox[3] = (QLE_DMA_DVA(mem) >> 0) & 0xffff;
1547 0 : mbox[6] = (QLE_DMA_DVA(mem) >> 48) & 0xffff;
1548 0 : mbox[7] = (QLE_DMA_DVA(mem) >> 32) & 0xffff;
1549 0 : }
1550 :
1551 : void
1552 0 : qle_set_ints(struct qle_softc *sc, int enabled)
1553 : {
1554 0 : u_int32_t v = enabled ? QLE_INT_CTRL_ENABLE : 0;
1555 0 : qle_write(sc, QLE_INT_CTRL, v);
1556 0 : }
1557 :
1558 : int
1559 0 : qle_read_isr(struct qle_softc *sc, u_int16_t *isr, u_int16_t *info)
1560 : {
1561 : u_int32_t v;
1562 :
1563 0 : switch (sc->sc_isp_gen) {
1564 : case QLE_GEN_ISP24XX:
1565 : case QLE_GEN_ISP25XX:
1566 0 : if ((qle_read(sc, QLE_INT_STATUS) & QLE_RISC_INT_REQ) == 0)
1567 0 : return (0);
1568 :
1569 0 : v = qle_read(sc, QLE_RISC_STATUS);
1570 :
1571 0 : switch (v & QLE_INT_STATUS_MASK) {
1572 : case QLE_24XX_INT_ROM_MBOX:
1573 : case QLE_24XX_INT_ROM_MBOX_FAIL:
1574 : case QLE_24XX_INT_MBOX:
1575 : case QLE_24XX_INT_MBOX_FAIL:
1576 0 : *isr = QLE_INT_TYPE_MBOX;
1577 0 : break;
1578 :
1579 : case QLE_24XX_INT_ASYNC:
1580 0 : *isr = QLE_INT_TYPE_ASYNC;
1581 0 : break;
1582 :
1583 : case QLE_24XX_INT_RSPQ:
1584 0 : *isr = QLE_INT_TYPE_IO;
1585 0 : break;
1586 :
1587 : default:
1588 0 : *isr = QLE_INT_TYPE_OTHER;
1589 0 : break;
1590 : }
1591 :
1592 0 : *info = (v >> QLE_INT_INFO_SHIFT);
1593 0 : return (1);
1594 :
1595 : default:
1596 0 : return (0);
1597 : }
1598 0 : }
1599 :
1600 : void
1601 0 : qle_clear_isr(struct qle_softc *sc, u_int16_t isr)
1602 : {
1603 0 : qle_host_cmd(sc, QLE_HOST_CMD_CLR_RISC_INT);
1604 0 : }
1605 :
1606 : void
1607 0 : qle_update_done(struct qle_softc *sc, int task)
1608 : {
1609 0 : atomic_clearbits_int(&sc->sc_update_tasks, task);
1610 0 : }
1611 :
1612 : void
1613 0 : qle_update_cancel(struct qle_softc *sc)
1614 : {
1615 0 : atomic_swap_uint(&sc->sc_update_tasks, 0);
1616 0 : timeout_del(&sc->sc_update_timeout);
1617 0 : task_del(sc->sc_update_taskq, &sc->sc_update_task);
1618 0 : }
1619 :
1620 : void
1621 0 : qle_update_start(struct qle_softc *sc, int task)
1622 : {
1623 0 : atomic_setbits_int(&sc->sc_update_tasks, task);
1624 0 : if (!timeout_pending(&sc->sc_update_timeout))
1625 0 : task_add(sc->sc_update_taskq, &sc->sc_update_task);
1626 0 : }
1627 :
1628 : void
1629 0 : qle_update_defer(struct qle_softc *sc, int task)
1630 : {
1631 0 : atomic_setbits_int(&sc->sc_update_tasks, task);
1632 0 : timeout_del(&sc->sc_update_timeout);
1633 0 : task_del(sc->sc_update_taskq, &sc->sc_update_task);
1634 0 : timeout_add_msec(&sc->sc_update_timeout, QLE_LOOP_SETTLE);
1635 0 : }
1636 :
1637 : void
1638 0 : qle_clear_port_lists(struct qle_softc *sc)
1639 : {
1640 : struct qle_fc_port *port;
1641 0 : while (!TAILQ_EMPTY(&sc->sc_ports_found)) {
1642 : port = TAILQ_FIRST(&sc->sc_ports_found);
1643 0 : TAILQ_REMOVE(&sc->sc_ports_found, port, update);
1644 0 : free(port, M_DEVBUF, sizeof *port);
1645 : }
1646 :
1647 0 : while (!TAILQ_EMPTY(&sc->sc_ports_new)) {
1648 : port = TAILQ_FIRST(&sc->sc_ports_new);
1649 0 : TAILQ_REMOVE(&sc->sc_ports_new, port, update);
1650 0 : free(port, M_DEVBUF, sizeof *port);
1651 : }
1652 :
1653 0 : while (!TAILQ_EMPTY(&sc->sc_ports_gone)) {
1654 : port = TAILQ_FIRST(&sc->sc_ports_gone);
1655 0 : TAILQ_REMOVE(&sc->sc_ports_gone, port, update);
1656 : }
1657 0 : }
1658 :
1659 : int
1660 0 : qle_softreset(struct qle_softc *sc)
1661 : {
1662 : int i;
1663 0 : qle_set_ints(sc, 0);
1664 :
1665 : /* set led control bits, stop dma */
1666 0 : qle_write(sc, QLE_GPIO_DATA, 0);
1667 0 : qle_write(sc, QLE_CTRL_STATUS, QLE_CTRL_DMA_SHUTDOWN);
1668 0 : while (qle_read(sc, QLE_CTRL_STATUS) & QLE_CTRL_DMA_ACTIVE) {
1669 : DPRINTF(QLE_D_IO, "%s: dma still active\n", DEVNAME(sc));
1670 0 : delay(100);
1671 : }
1672 :
1673 : /* reset */
1674 0 : qle_write(sc, QLE_CTRL_STATUS, QLE_CTRL_RESET | QLE_CTRL_DMA_SHUTDOWN);
1675 0 : delay(100);
1676 : /* clear data and control dma engines? */
1677 :
1678 : /* wait for soft reset to clear */
1679 0 : for (i = 0; i < 1000; i++) {
1680 0 : if (qle_read_mbox(sc, 0) == 0x0000)
1681 : break;
1682 :
1683 0 : delay(100);
1684 : }
1685 :
1686 0 : if (i == 1000) {
1687 0 : printf("%s: reset mbox didn't clear\n", DEVNAME(sc));
1688 0 : qle_set_ints(sc, 0);
1689 0 : return (ENXIO);
1690 : }
1691 :
1692 0 : for (i = 0; i < 500000; i++) {
1693 0 : if ((qle_read(sc, QLE_CTRL_STATUS) & QLE_CTRL_RESET) == 0)
1694 : break;
1695 0 : delay(5);
1696 : }
1697 0 : if (i == 500000) {
1698 0 : printf("%s: reset status didn't clear\n", DEVNAME(sc));
1699 0 : return (ENXIO);
1700 : }
1701 :
1702 : /* reset risc processor */
1703 0 : qle_host_cmd(sc, QLE_HOST_CMD_RESET);
1704 0 : qle_host_cmd(sc, QLE_HOST_CMD_RELEASE);
1705 0 : qle_host_cmd(sc, QLE_HOST_CMD_CLEAR_RESET);
1706 :
1707 : /* wait for reset to clear */
1708 0 : for (i = 0; i < 1000; i++) {
1709 0 : if (qle_read_mbox(sc, 0) == 0x0000)
1710 : break;
1711 0 : delay(100);
1712 : }
1713 0 : if (i == 1000) {
1714 0 : printf("%s: risc not ready after reset\n", DEVNAME(sc));
1715 0 : return (ENXIO);
1716 : }
1717 :
1718 : /* reset queue pointers */
1719 0 : qle_write(sc, QLE_REQ_IN, 0);
1720 0 : qle_write(sc, QLE_REQ_OUT, 0);
1721 0 : qle_write(sc, QLE_RESP_IN, 0);
1722 0 : qle_write(sc, QLE_RESP_OUT, 0);
1723 :
1724 0 : qle_set_ints(sc, 1);
1725 :
1726 : /* do a basic mailbox operation to check we're alive */
1727 0 : sc->sc_mbox[0] = QLE_MBOX_NOP;
1728 0 : if (qle_mbox(sc, 0x0001)) {
1729 0 : printf("ISP not responding after reset\n");
1730 0 : return (ENXIO);
1731 : }
1732 :
1733 0 : return (0);
1734 0 : }
1735 :
1736 : void
1737 0 : qle_update_topology(struct qle_softc *sc)
1738 : {
1739 0 : sc->sc_mbox[0] = QLE_MBOX_GET_ID;
1740 0 : if (qle_mbox(sc, 0x0001)) {
1741 : DPRINTF(QLE_D_PORT, "%s: unable to get loop id\n", DEVNAME(sc));
1742 0 : sc->sc_topology = QLE_TOPO_N_PORT_NO_TARGET;
1743 0 : } else {
1744 0 : sc->sc_topology = sc->sc_mbox[6];
1745 0 : sc->sc_loop_id = sc->sc_mbox[1];
1746 :
1747 0 : switch (sc->sc_topology) {
1748 : case QLE_TOPO_NL_PORT:
1749 : case QLE_TOPO_N_PORT:
1750 : DPRINTF(QLE_D_PORT, "%s: loop id %d\n", DEVNAME(sc),
1751 : sc->sc_loop_id);
1752 : break;
1753 :
1754 : case QLE_TOPO_FL_PORT:
1755 : case QLE_TOPO_F_PORT:
1756 0 : sc->sc_port_id = sc->sc_mbox[2] |
1757 0 : (sc->sc_mbox[3] << 16);
1758 : DPRINTF(QLE_D_PORT, "%s: fabric port id %06x\n",
1759 : DEVNAME(sc), sc->sc_port_id);
1760 0 : break;
1761 :
1762 : case QLE_TOPO_N_PORT_NO_TARGET:
1763 : default:
1764 : DPRINTF(QLE_D_PORT, "%s: not useful\n", DEVNAME(sc));
1765 : break;
1766 : }
1767 :
1768 0 : switch (sc->sc_topology) {
1769 : case QLE_TOPO_NL_PORT:
1770 : case QLE_TOPO_FL_PORT:
1771 0 : sc->sc_loop_max_id = 126;
1772 0 : break;
1773 :
1774 : case QLE_TOPO_N_PORT:
1775 0 : sc->sc_loop_max_id = 2;
1776 0 : break;
1777 :
1778 : default:
1779 0 : sc->sc_loop_max_id = 0;
1780 0 : break;
1781 : }
1782 : }
1783 0 : }
1784 :
1785 : int
1786 0 : qle_update_fabric(struct qle_softc *sc)
1787 : {
1788 : /*struct qle_sns_rft_id *rft;*/
1789 :
1790 0 : switch (sc->sc_topology) {
1791 : case QLE_TOPO_F_PORT:
1792 : case QLE_TOPO_FL_PORT:
1793 : break;
1794 :
1795 : default:
1796 0 : return (0);
1797 : }
1798 :
1799 : /* get the name server's port db entry */
1800 0 : sc->sc_mbox[0] = QLE_MBOX_GET_PORT_DB;
1801 0 : sc->sc_mbox[1] = QLE_F_PORT_HANDLE;
1802 0 : qle_mbox_putaddr(sc->sc_mbox, sc->sc_scratch);
1803 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_scratch), 0,
1804 : sizeof(struct qle_get_port_db), BUS_DMASYNC_PREREAD);
1805 0 : if (qle_mbox(sc, 0x00cf)) {
1806 : DPRINTF(QLE_D_PORT, "%s: get port db for SNS failed: %x\n",
1807 : DEVNAME(sc), sc->sc_mbox[0]);
1808 0 : sc->sc_sns_port_name = 0;
1809 0 : } else {
1810 : struct qle_get_port_db *pdb;
1811 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_scratch), 0,
1812 : sizeof(struct qle_get_port_db), BUS_DMASYNC_POSTREAD);
1813 0 : pdb = QLE_DMA_KVA(sc->sc_scratch);
1814 : DPRINTF(QLE_D_PORT, "%s: SNS port name %llx\n", DEVNAME(sc),
1815 : betoh64(pdb->port_name));
1816 0 : sc->sc_sns_port_name = betoh64(pdb->port_name);
1817 : }
1818 :
1819 : /*
1820 : * register fc4 types with the fabric
1821 : * some switches do this automatically, but apparently
1822 : * some don't.
1823 : */
1824 : /*
1825 : rft = QLE_DMA_KVA(sc->sc_scratch);
1826 : memset(rft, 0, sizeof(*rft) + sizeof(struct qle_sns_req_hdr));
1827 : htolem16(&rft->subcmd, QLE_SNS_RFT_ID);
1828 : htolem16(&rft->max_word, sizeof(struct qle_sns_req_hdr) / 4);
1829 : htolem32(&rft->port_id, sc->sc_port_id);
1830 : rft->fc4_types[0] = (1 << QLE_FC4_SCSI);
1831 : if (qle_sns_req(sc, sc->sc_scratch, sizeof(*rft))) {
1832 : printf("%s: RFT_ID failed\n", DEVNAME(sc));
1833 : / * we might be able to continue after this fails * /
1834 : }
1835 : */
1836 :
1837 0 : return (1);
1838 0 : }
1839 :
1840 : int
1841 0 : qle_ct_pass_through(struct qle_softc *sc, u_int32_t port_handle,
1842 : struct qle_dmamem *mem, size_t req_size, size_t resp_size)
1843 : {
1844 : struct qle_iocb_ct_passthrough *iocb;
1845 : u_int16_t req;
1846 : u_int64_t offset;
1847 : int rv;
1848 :
1849 0 : mtx_enter(&sc->sc_queue_mtx);
1850 :
1851 0 : req = sc->sc_next_req_id++;
1852 0 : if (sc->sc_next_req_id == sc->sc_maxcmds)
1853 0 : sc->sc_next_req_id = 0;
1854 :
1855 0 : offset = (req * QLE_QUEUE_ENTRY_SIZE);
1856 0 : iocb = QLE_DMA_KVA(sc->sc_requests) + offset;
1857 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_requests), offset,
1858 : QLE_QUEUE_ENTRY_SIZE, BUS_DMASYNC_POSTWRITE);
1859 :
1860 0 : memset(iocb, 0, QLE_QUEUE_ENTRY_SIZE);
1861 0 : iocb->entry_type = QLE_IOCB_CT_PASSTHROUGH;
1862 0 : iocb->entry_count = 1;
1863 :
1864 0 : iocb->req_handle = 9;
1865 0 : htolem16(&iocb->req_nport_handle, port_handle);
1866 0 : htolem16(&iocb->req_dsd_count, 1);
1867 0 : htolem16(&iocb->req_resp_dsd_count, 1);
1868 0 : htolem32(&iocb->req_cmd_byte_count, req_size);
1869 0 : htolem32(&iocb->req_resp_byte_count, resp_size);
1870 0 : qle_sge(&iocb->req_cmd_seg, QLE_DMA_DVA(mem), req_size);
1871 0 : qle_sge(&iocb->req_resp_seg, QLE_DMA_DVA(mem) + req_size, resp_size);
1872 :
1873 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(mem), 0, QLE_DMA_LEN(mem),
1874 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1875 0 : qle_write(sc, QLE_REQ_IN, sc->sc_next_req_id);
1876 0 : sc->sc_fabric_pending = 1;
1877 0 : mtx_leave(&sc->sc_queue_mtx);
1878 :
1879 : /* maybe put a proper timeout on this */
1880 : rv = 0;
1881 0 : while (sc->sc_fabric_pending == 1) {
1882 0 : if (sc->sc_scsibus == NULL) {
1883 0 : u_int16_t isr, info;
1884 :
1885 0 : delay(100);
1886 0 : if (qle_read_isr(sc, &isr, &info) != 0)
1887 0 : qle_handle_intr(sc, isr, info);
1888 0 : } else {
1889 0 : tsleep(sc->sc_scratch, PRIBIO, "qle_fabric", 100);
1890 : }
1891 : }
1892 0 : if (rv == 0)
1893 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(mem), 0,
1894 : QLE_DMA_LEN(mem), BUS_DMASYNC_POSTREAD |
1895 : BUS_DMASYNC_POSTWRITE);
1896 :
1897 0 : sc->sc_fabric_pending = 0;
1898 :
1899 0 : return (rv);
1900 : }
1901 :
1902 : struct qle_fc_port *
1903 0 : qle_next_fabric_port(struct qle_softc *sc, u_int32_t *firstport,
1904 : u_int32_t *lastport)
1905 : {
1906 : struct qle_ct_ga_nxt_req *ga;
1907 : struct qle_ct_ga_nxt_resp *gar;
1908 : struct qle_fc_port *fport;
1909 : int result;
1910 :
1911 : /* get the next port from the fabric nameserver */
1912 0 : ga = QLE_DMA_KVA(sc->sc_scratch);
1913 0 : memset(ga, 0, sizeof(*ga) + sizeof(*gar));
1914 0 : ga->header.ct_revision = 0x01;
1915 0 : ga->header.ct_gs_type = 0xfc;
1916 0 : ga->header.ct_gs_subtype = 0x02;
1917 0 : ga->subcmd = htobe16(QLE_SNS_GA_NXT);
1918 0 : ga->max_word = htobe16((sizeof(*gar) - 16) / 4);
1919 0 : ga->port_id = htobe32(*lastport);
1920 0 : result = qle_ct_pass_through(sc, QLE_SNS_HANDLE, sc->sc_scratch,
1921 : sizeof(*ga), sizeof(*gar));
1922 0 : if (result) {
1923 : DPRINTF(QLE_D_PORT, "%s: GA_NXT %06x failed: %x\n", DEVNAME(sc),
1924 : *lastport, result);
1925 0 : *lastport = 0xffffffff;
1926 0 : return (NULL);
1927 : }
1928 :
1929 0 : gar = (struct qle_ct_ga_nxt_resp *)(ga + 1);
1930 : /* if the response is all zeroes, try again */
1931 0 : if (gar->port_type_id == 0 && gar->port_name == 0 &&
1932 0 : gar->node_name == 0) {
1933 : DPRINTF(QLE_D_PORT, "%s: GA_NXT returned junk\n", DEVNAME(sc));
1934 0 : return (NULL);
1935 : }
1936 :
1937 : /* are we back at the start? */
1938 0 : *lastport = betoh32(gar->port_type_id) & 0xffffff;
1939 0 : if (*lastport == *firstport) {
1940 0 : *lastport = 0xffffffff;
1941 0 : return (NULL);
1942 : }
1943 0 : if (*firstport == 0xffffffff)
1944 0 : *firstport = *lastport;
1945 :
1946 : DPRINTF(QLE_D_PORT, "%s: GA_NXT: port id: %06x, wwpn %llx, wwnn %llx\n",
1947 : DEVNAME(sc), *lastport, betoh64(gar->port_name),
1948 : betoh64(gar->node_name));
1949 :
1950 : /* don't try to log in to ourselves */
1951 0 : if (*lastport == sc->sc_port_id) {
1952 0 : return (NULL);
1953 : }
1954 :
1955 0 : fport = malloc(sizeof(*fport), M_DEVBUF, M_ZERO | M_NOWAIT);
1956 0 : if (fport == NULL) {
1957 0 : printf("%s: failed to allocate a port struct\n",
1958 0 : DEVNAME(sc));
1959 0 : *lastport = 0xffffffff;
1960 0 : return (NULL);
1961 : }
1962 0 : fport->port_name = betoh64(gar->port_name);
1963 0 : fport->node_name = betoh64(gar->node_name);
1964 0 : fport->location = QLE_LOCATION_PORT_ID(*lastport);
1965 0 : fport->portid = *lastport;
1966 0 : return (fport);
1967 0 : }
1968 :
1969 : int
1970 0 : qle_fabric_plogx(struct qle_softc *sc, struct qle_fc_port *port, int flags,
1971 : u_int32_t *info)
1972 : {
1973 : struct qle_iocb_plogx *iocb;
1974 : u_int16_t req;
1975 : u_int64_t offset;
1976 : int rv;
1977 :
1978 0 : mtx_enter(&sc->sc_queue_mtx);
1979 :
1980 0 : req = sc->sc_next_req_id++;
1981 0 : if (sc->sc_next_req_id == sc->sc_maxcmds)
1982 0 : sc->sc_next_req_id = 0;
1983 :
1984 0 : offset = (req * QLE_QUEUE_ENTRY_SIZE);
1985 0 : iocb = QLE_DMA_KVA(sc->sc_requests) + offset;
1986 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(sc->sc_requests), offset,
1987 : QLE_QUEUE_ENTRY_SIZE, BUS_DMASYNC_POSTWRITE);
1988 :
1989 0 : memset(iocb, 0, QLE_QUEUE_ENTRY_SIZE);
1990 0 : iocb->entry_type = QLE_IOCB_PLOGX;
1991 0 : iocb->entry_count = 1;
1992 :
1993 0 : iocb->req_handle = 7;
1994 0 : htolem16(&iocb->req_nport_handle, port->loopid);
1995 0 : htolem16(&iocb->req_port_id_lo, port->portid);
1996 0 : iocb->req_port_id_hi = port->portid >> 16;
1997 0 : htolem16(&iocb->req_flags, flags);
1998 :
1999 : DPRINTF(QLE_D_PORT, "%s: plogx loop id %d port %06x, flags %x\n",
2000 : DEVNAME(sc), port->loopid, port->portid, flags);
2001 0 : qle_dump_iocb(sc, iocb);
2002 :
2003 0 : qle_write(sc, QLE_REQ_IN, sc->sc_next_req_id);
2004 0 : sc->sc_fabric_pending = 1;
2005 0 : mtx_leave(&sc->sc_queue_mtx);
2006 :
2007 : /* maybe put a proper timeout on this */
2008 : rv = 0;
2009 0 : while (sc->sc_fabric_pending == 1) {
2010 0 : if (sc->sc_scsibus == NULL) {
2011 0 : u_int16_t isr, info;
2012 :
2013 0 : delay(100);
2014 0 : if (qle_read_isr(sc, &isr, &info) != 0)
2015 0 : qle_handle_intr(sc, isr, info);
2016 0 : } else {
2017 0 : tsleep(sc->sc_scratch, PRIBIO, "qle_fabric", 100);
2018 : }
2019 : }
2020 0 : sc->sc_fabric_pending = 0;
2021 :
2022 0 : iocb = (struct qle_iocb_plogx *)&sc->sc_fabric_response;
2023 0 : rv = lemtoh16(&iocb->req_status);
2024 0 : if (rv == QLE_PLOGX_ERROR) {
2025 0 : rv = lemtoh32(&iocb->req_ioparms[0]);
2026 0 : *info = lemtoh32(&iocb->req_ioparms[1]);
2027 0 : }
2028 :
2029 0 : return (rv);
2030 : }
2031 :
2032 : int
2033 0 : qle_fabric_plogi(struct qle_softc *sc, struct qle_fc_port *port)
2034 : {
2035 0 : u_int32_t info;
2036 : int err, loopid;
2037 :
2038 0 : loopid = 0;
2039 : retry:
2040 0 : if (port->loopid == 0) {
2041 :
2042 0 : mtx_enter(&sc->sc_port_mtx);
2043 0 : loopid = qle_get_loop_id(sc, loopid);
2044 0 : mtx_leave(&sc->sc_port_mtx);
2045 0 : if (loopid == -1) {
2046 0 : printf("%s: ran out of loop ids\n", DEVNAME(sc));
2047 0 : return (1);
2048 : }
2049 :
2050 0 : port->loopid = loopid;
2051 0 : }
2052 :
2053 0 : err = qle_fabric_plogx(sc, port, QLE_PLOGX_LOGIN, &info);
2054 0 : switch (err) {
2055 : case 0:
2056 : DPRINTF(QLE_D_PORT, "%s: logged in to %06x as %d\n",
2057 : DEVNAME(sc), port->portid, port->loopid);
2058 0 : port->flags &= ~QLE_PORT_FLAG_NEEDS_LOGIN;
2059 0 : return (0);
2060 :
2061 : case QLE_PLOGX_ERROR_PORT_ID_USED:
2062 : DPRINTF(QLE_D_PORT, "%s: already logged in to %06x as %d\n",
2063 : DEVNAME(sc), port->portid, info);
2064 0 : port->loopid = info;
2065 0 : port->flags &= ~QLE_PORT_FLAG_NEEDS_LOGIN;
2066 0 : return (0);
2067 :
2068 : case QLE_PLOGX_ERROR_HANDLE_USED:
2069 0 : if (qle_add_logged_in_port(sc, loopid, info)) {
2070 0 : return (1);
2071 : }
2072 0 : port->loopid = 0;
2073 0 : loopid++;
2074 0 : goto retry;
2075 :
2076 : default:
2077 : DPRINTF(QLE_D_PORT, "%s: error %x logging in to port %06x\n",
2078 : DEVNAME(sc), err, port->portid);
2079 0 : port->loopid = 0;
2080 0 : return (1);
2081 : }
2082 0 : }
2083 :
2084 : void
2085 0 : qle_fabric_plogo(struct qle_softc *sc, struct qle_fc_port *port)
2086 : {
2087 : int err;
2088 0 : u_int32_t info;
2089 :
2090 : /*
2091 : * we only log out if we can't see the port any more, so we always
2092 : * want to do an explicit logout and free the n-port handle.
2093 : */
2094 0 : err = qle_fabric_plogx(sc, port, QLE_PLOGX_LOGOUT |
2095 : QLE_PLOGX_LOGOUT_EXPLICIT | QLE_PLOGX_LOGOUT_FREE_HANDLE, &info);
2096 : if (err == 0) {
2097 : DPRINTF(QLE_D_PORT, "%s: logged out of port %06x\n",
2098 : DEVNAME(sc), port->portid);
2099 : } else {
2100 : DPRINTF(QLE_D_PORT, "%s: failed to log out of port %06x: "
2101 : "%x %x\n", DEVNAME(sc), port->portid, err, info);
2102 : }
2103 0 : }
2104 :
2105 : void
2106 0 : qle_deferred_update(void *xsc)
2107 : {
2108 0 : struct qle_softc *sc = xsc;
2109 0 : task_add(sc->sc_update_taskq, &sc->sc_update_task);
2110 0 : }
2111 :
2112 : void
2113 0 : qle_do_update(void *xsc)
2114 : {
2115 0 : struct qle_softc *sc = xsc;
2116 0 : int firstport, lastport;
2117 0 : struct qle_fc_port *port, *fport;
2118 :
2119 : DPRINTF(QLE_D_PORT, "%s: updating\n", DEVNAME(sc));
2120 0 : while (sc->sc_update_tasks != 0) {
2121 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_CLEAR_ALL) {
2122 0 : TAILQ_HEAD(, qle_fc_port) detach;
2123 : DPRINTF(QLE_D_PORT, "%s: detaching everything\n",
2124 : DEVNAME(sc));
2125 :
2126 0 : mtx_enter(&sc->sc_port_mtx);
2127 0 : qle_clear_port_lists(sc);
2128 0 : TAILQ_INIT(&detach);
2129 0 : while (!TAILQ_EMPTY(&sc->sc_ports)) {
2130 0 : port = TAILQ_FIRST(&sc->sc_ports);
2131 0 : TAILQ_REMOVE(&sc->sc_ports, port, ports);
2132 0 : TAILQ_INSERT_TAIL(&detach, port, ports);
2133 : }
2134 0 : mtx_leave(&sc->sc_port_mtx);
2135 :
2136 0 : while (!TAILQ_EMPTY(&detach)) {
2137 0 : port = TAILQ_FIRST(&detach);
2138 0 : TAILQ_REMOVE(&detach, port, ports);
2139 0 : if (port->flags & QLE_PORT_FLAG_IS_TARGET) {
2140 0 : scsi_detach_target(sc->sc_scsibus,
2141 0 : port->loopid, -1);
2142 0 : sc->sc_targets[port->loopid] = NULL;
2143 0 : }
2144 0 : if (port->location & QLE_LOCATION_FABRIC)
2145 0 : qle_fabric_plogo(sc, port);
2146 :
2147 0 : free(port, M_DEVBUF, sizeof *port);
2148 : }
2149 :
2150 0 : qle_update_done(sc, QLE_UPDATE_TASK_CLEAR_ALL);
2151 : continue;
2152 0 : }
2153 :
2154 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_SOFTRESET) {
2155 : DPRINTF(QLE_D_IO, "%s: attempting softreset\n",
2156 : DEVNAME(sc));
2157 0 : if (qle_softreset(sc) != 0) {
2158 : DPRINTF(QLE_D_IO, "%s: couldn't softreset\n",
2159 : DEVNAME(sc));
2160 : }
2161 0 : qle_update_done(sc, QLE_UPDATE_TASK_SOFTRESET);
2162 0 : continue;
2163 : }
2164 :
2165 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_UPDATE_TOPO) {
2166 : DPRINTF(QLE_D_PORT, "%s: updating topology\n",
2167 : DEVNAME(sc));
2168 0 : qle_update_topology(sc);
2169 0 : qle_update_done(sc, QLE_UPDATE_TASK_UPDATE_TOPO);
2170 0 : continue;
2171 : }
2172 :
2173 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_GET_PORT_LIST) {
2174 : DPRINTF(QLE_D_PORT, "%s: getting port name list\n",
2175 : DEVNAME(sc));
2176 0 : mtx_enter(&sc->sc_port_mtx);
2177 0 : qle_clear_port_lists(sc);
2178 0 : mtx_leave(&sc->sc_port_mtx);
2179 :
2180 0 : qle_get_port_name_list(sc, QLE_LOCATION_LOOP |
2181 : QLE_LOCATION_FABRIC);
2182 0 : mtx_enter(&sc->sc_port_mtx);
2183 0 : TAILQ_FOREACH(port, &sc->sc_ports, ports) {
2184 0 : TAILQ_INSERT_TAIL(&sc->sc_ports_gone, port,
2185 : update);
2186 0 : if (port->location & QLE_LOCATION_FABRIC) {
2187 0 : port->flags |=
2188 : QLE_PORT_FLAG_NEEDS_LOGIN;
2189 0 : }
2190 : }
2191 :
2192 : /* take care of ports that haven't changed first */
2193 0 : TAILQ_FOREACH(fport, &sc->sc_ports_found, update) {
2194 0 : port = sc->sc_targets[fport->loopid];
2195 0 : if (port == NULL || fport->port_name !=
2196 0 : port->port_name) {
2197 : /* new or changed port, handled later */
2198 : continue;
2199 : }
2200 :
2201 : /*
2202 : * the port hasn't been logged out, which
2203 : * means we don't need to log in again, and,
2204 : * for loop ports, that the port still exists
2205 : */
2206 0 : port->flags &= ~QLE_PORT_FLAG_NEEDS_LOGIN;
2207 0 : if (port->location & QLE_LOCATION_LOOP)
2208 0 : TAILQ_REMOVE(&sc->sc_ports_gone,
2209 : port, update);
2210 :
2211 0 : fport->location = 0;
2212 0 : }
2213 0 : mtx_leave(&sc->sc_port_mtx);
2214 0 : qle_update_start(sc, QLE_UPDATE_TASK_PORT_LIST);
2215 0 : qle_update_done(sc, QLE_UPDATE_TASK_GET_PORT_LIST);
2216 0 : continue;
2217 : }
2218 :
2219 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_PORT_LIST) {
2220 0 : mtx_enter(&sc->sc_port_mtx);
2221 0 : fport = TAILQ_FIRST(&sc->sc_ports_found);
2222 0 : if (fport != NULL) {
2223 0 : TAILQ_REMOVE(&sc->sc_ports_found, fport,
2224 : update);
2225 0 : }
2226 0 : mtx_leave(&sc->sc_port_mtx);
2227 :
2228 0 : if (fport == NULL) {
2229 : DPRINTF(QLE_D_PORT, "%s: done with ports\n",
2230 : DEVNAME(sc));
2231 0 : qle_update_done(sc,
2232 : QLE_UPDATE_TASK_PORT_LIST);
2233 0 : qle_update_start(sc,
2234 : QLE_UPDATE_TASK_SCAN_FABRIC);
2235 0 : } else if (fport->location & QLE_LOCATION_LOOP) {
2236 : DPRINTF(QLE_D_PORT, "%s: loop port %04x\n",
2237 : DEVNAME(sc), fport->loopid);
2238 0 : if (qle_add_loop_port(sc, fport) != 0)
2239 0 : free(fport, M_DEVBUF, sizeof *port);
2240 0 : } else if (fport->location & QLE_LOCATION_FABRIC) {
2241 0 : qle_add_fabric_port(sc, fport);
2242 0 : } else {
2243 : /* already processed */
2244 0 : free(fport, M_DEVBUF, sizeof *port);
2245 : }
2246 0 : continue;
2247 : }
2248 :
2249 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_SCAN_FABRIC) {
2250 : DPRINTF(QLE_D_PORT, "%s: starting fabric scan\n",
2251 : DEVNAME(sc));
2252 0 : lastport = sc->sc_port_id;
2253 0 : firstport = 0xffffffff;
2254 0 : if (qle_update_fabric(sc))
2255 0 : qle_update_start(sc,
2256 : QLE_UPDATE_TASK_SCANNING_FABRIC);
2257 : else
2258 0 : qle_update_start(sc,
2259 : QLE_UPDATE_TASK_ATTACH_TARGET |
2260 : QLE_UPDATE_TASK_DETACH_TARGET);
2261 :
2262 0 : qle_update_done(sc, QLE_UPDATE_TASK_SCAN_FABRIC);
2263 0 : continue;
2264 : }
2265 :
2266 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_SCANNING_FABRIC) {
2267 0 : fport = qle_next_fabric_port(sc, &firstport, &lastport);
2268 0 : if (fport != NULL) {
2269 : int disp;
2270 :
2271 0 : mtx_enter(&sc->sc_port_mtx);
2272 0 : disp = qle_classify_port(sc, fport->location,
2273 0 : fport->port_name, fport->node_name, &port);
2274 0 : switch (disp) {
2275 : case QLE_PORT_DISP_CHANGED:
2276 : case QLE_PORT_DISP_MOVED:
2277 : /* we'll log out the old port later */
2278 : case QLE_PORT_DISP_NEW:
2279 : DPRINTF(QLE_D_PORT, "%s: new port "
2280 : "%06x\n", DEVNAME(sc),
2281 : fport->portid);
2282 0 : TAILQ_INSERT_TAIL(&sc->sc_ports_found,
2283 : fport, update);
2284 0 : break;
2285 : case QLE_PORT_DISP_DUP:
2286 0 : free(fport, M_DEVBUF, sizeof *port);
2287 0 : break;
2288 : case QLE_PORT_DISP_SAME:
2289 : DPRINTF(QLE_D_PORT, "%s: existing port "
2290 : " %06x\n", DEVNAME(sc),
2291 : fport->portid);
2292 0 : TAILQ_REMOVE(&sc->sc_ports_gone, port,
2293 : update);
2294 0 : free(fport, M_DEVBUF, sizeof *port);
2295 0 : break;
2296 : }
2297 0 : mtx_leave(&sc->sc_port_mtx);
2298 0 : }
2299 0 : if (lastport == 0xffffffff) {
2300 : DPRINTF(QLE_D_PORT, "%s: finished\n",
2301 : DEVNAME(sc));
2302 0 : qle_update_done(sc,
2303 : QLE_UPDATE_TASK_SCANNING_FABRIC);
2304 0 : qle_update_start(sc,
2305 : QLE_UPDATE_TASK_FABRIC_LOGIN);
2306 0 : }
2307 0 : continue;
2308 : }
2309 :
2310 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_FABRIC_LOGIN) {
2311 0 : mtx_enter(&sc->sc_port_mtx);
2312 0 : port = TAILQ_FIRST(&sc->sc_ports_found);
2313 0 : if (port != NULL) {
2314 0 : TAILQ_REMOVE(&sc->sc_ports_found, port, update);
2315 0 : }
2316 0 : mtx_leave(&sc->sc_port_mtx);
2317 :
2318 0 : if (port != NULL) {
2319 : DPRINTF(QLE_D_PORT, "%s: found port %06x\n",
2320 : DEVNAME(sc), port->portid);
2321 0 : if (qle_fabric_plogi(sc, port) == 0) {
2322 0 : qle_add_fabric_port(sc, port);
2323 0 : } else {
2324 : DPRINTF(QLE_D_PORT, "%s: plogi %06x "
2325 : "failed\n", DEVNAME(sc),
2326 : port->portid);
2327 0 : free(port, M_DEVBUF, sizeof *port);
2328 : }
2329 : } else {
2330 : DPRINTF(QLE_D_PORT, "%s: done with logins\n",
2331 : DEVNAME(sc));
2332 0 : qle_update_done(sc,
2333 : QLE_UPDATE_TASK_FABRIC_LOGIN);
2334 0 : qle_update_start(sc,
2335 : QLE_UPDATE_TASK_ATTACH_TARGET |
2336 : QLE_UPDATE_TASK_DETACH_TARGET);
2337 : }
2338 0 : continue;
2339 : }
2340 :
2341 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_FABRIC_RELOGIN) {
2342 0 : TAILQ_FOREACH(port, &sc->sc_ports, ports) {
2343 0 : if (port->flags & QLE_PORT_FLAG_NEEDS_LOGIN) {
2344 0 : qle_fabric_plogi(sc, port);
2345 0 : break;
2346 : }
2347 : }
2348 :
2349 0 : if (port == NULL)
2350 0 : qle_update_done(sc,
2351 : QLE_UPDATE_TASK_FABRIC_RELOGIN);
2352 0 : continue;
2353 : }
2354 :
2355 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_DETACH_TARGET) {
2356 0 : mtx_enter(&sc->sc_port_mtx);
2357 0 : port = TAILQ_FIRST(&sc->sc_ports_gone);
2358 0 : if (port != NULL) {
2359 0 : sc->sc_targets[port->loopid] = NULL;
2360 0 : TAILQ_REMOVE(&sc->sc_ports_gone, port, update);
2361 0 : TAILQ_REMOVE(&sc->sc_ports, port, ports);
2362 0 : }
2363 0 : mtx_leave(&sc->sc_port_mtx);
2364 :
2365 0 : if (port != NULL) {
2366 : DPRINTF(QLE_D_PORT, "%s: detaching port %06x\n",
2367 : DEVNAME(sc), port->portid);
2368 0 : if (sc->sc_scsibus != NULL)
2369 0 : scsi_detach_target(sc->sc_scsibus,
2370 0 : port->loopid, -1);
2371 :
2372 0 : if (port->location & QLE_LOCATION_FABRIC)
2373 0 : qle_fabric_plogo(sc, port);
2374 :
2375 0 : free(port, M_DEVBUF, sizeof *port);
2376 0 : } else {
2377 : DPRINTF(QLE_D_PORT, "%s: nothing to detach\n",
2378 : DEVNAME(sc));
2379 0 : qle_update_done(sc,
2380 : QLE_UPDATE_TASK_DETACH_TARGET);
2381 : }
2382 0 : continue;
2383 : }
2384 :
2385 0 : if (sc->sc_update_tasks & QLE_UPDATE_TASK_ATTACH_TARGET) {
2386 0 : mtx_enter(&sc->sc_port_mtx);
2387 0 : port = TAILQ_FIRST(&sc->sc_ports_new);
2388 0 : if (port != NULL) {
2389 0 : TAILQ_REMOVE(&sc->sc_ports_new, port, update);
2390 0 : TAILQ_INSERT_TAIL(&sc->sc_ports, port, ports);
2391 0 : }
2392 0 : mtx_leave(&sc->sc_port_mtx);
2393 :
2394 0 : if (port != NULL) {
2395 0 : if (sc->sc_scsibus != NULL)
2396 0 : scsi_probe_target(sc->sc_scsibus,
2397 0 : port->loopid);
2398 : } else {
2399 0 : qle_update_done(sc,
2400 : QLE_UPDATE_TASK_ATTACH_TARGET);
2401 : }
2402 0 : continue;
2403 : }
2404 :
2405 : }
2406 :
2407 : DPRINTF(QLE_D_PORT, "%s: done updating\n", DEVNAME(sc));
2408 0 : }
2409 :
2410 : int
2411 0 : qle_async(struct qle_softc *sc, u_int16_t info)
2412 : {
2413 0 : switch (info) {
2414 : case QLE_ASYNC_SYSTEM_ERROR:
2415 0 : qle_update_start(sc, QLE_UPDATE_TASK_SOFTRESET);
2416 0 : break;
2417 :
2418 : case QLE_ASYNC_REQ_XFER_ERROR:
2419 0 : qle_update_start(sc, QLE_UPDATE_TASK_SOFTRESET);
2420 0 : break;
2421 :
2422 : case QLE_ASYNC_RSP_XFER_ERROR:
2423 0 : qle_update_start(sc, QLE_UPDATE_TASK_SOFTRESET);
2424 0 : break;
2425 :
2426 : case QLE_ASYNC_LIP_OCCURRED:
2427 : DPRINTF(QLE_D_INTR, "%s: lip occurred\n", DEVNAME(sc));
2428 : break;
2429 :
2430 : case QLE_ASYNC_LOOP_UP:
2431 : DPRINTF(QLE_D_PORT, "%s: loop up\n", DEVNAME(sc));
2432 0 : sc->sc_loop_up = 1;
2433 0 : sc->sc_marker_required = 1;
2434 0 : qle_update_defer(sc, QLE_UPDATE_TASK_UPDATE_TOPO |
2435 : QLE_UPDATE_TASK_GET_PORT_LIST);
2436 0 : break;
2437 :
2438 : case QLE_ASYNC_LOOP_DOWN:
2439 : DPRINTF(QLE_D_PORT, "%s: loop down\n", DEVNAME(sc));
2440 0 : sc->sc_loop_up = 0;
2441 0 : qle_update_cancel(sc);
2442 0 : qle_update_start(sc, QLE_UPDATE_TASK_CLEAR_ALL);
2443 0 : break;
2444 :
2445 : case QLE_ASYNC_LIP_RESET:
2446 : DPRINTF(QLE_D_PORT, "%s: lip reset\n", DEVNAME(sc));
2447 0 : sc->sc_marker_required = 1;
2448 0 : qle_update_defer(sc, QLE_UPDATE_TASK_FABRIC_RELOGIN);
2449 0 : break;
2450 :
2451 : case QLE_ASYNC_PORT_DB_CHANGE:
2452 : DPRINTF(QLE_D_PORT, "%s: port db changed %x\n", DEVNAME(sc),
2453 : qle_read_mbox(sc, 1));
2454 0 : qle_update_start(sc, QLE_UPDATE_TASK_GET_PORT_LIST);
2455 0 : break;
2456 :
2457 : case QLE_ASYNC_CHANGE_NOTIFY:
2458 : DPRINTF(QLE_D_PORT, "%s: name server change (%02x:%02x)\n",
2459 : DEVNAME(sc), qle_read_mbox(sc, 1), qle_read_mbox(sc, 2));
2460 0 : qle_update_start(sc, QLE_UPDATE_TASK_GET_PORT_LIST);
2461 0 : break;
2462 :
2463 : case QLE_ASYNC_LIP_F8:
2464 : DPRINTF(QLE_D_INTR, "%s: lip f8\n", DEVNAME(sc));
2465 : break;
2466 :
2467 : case QLE_ASYNC_LOOP_INIT_ERROR:
2468 : DPRINTF(QLE_D_PORT, "%s: loop initialization error: %x\n",
2469 : DEVNAME(sc), qle_read_mbox(sc, 1));
2470 : break;
2471 :
2472 : case QLE_ASYNC_POINT_TO_POINT:
2473 : DPRINTF(QLE_D_PORT, "%s: connected in point-to-point mode\n",
2474 : DEVNAME(sc));
2475 : break;
2476 :
2477 : case QLE_ASYNC_ZIO_RESP_UPDATE:
2478 : /* shouldn't happen, we don't do zio */
2479 : break;
2480 :
2481 : default:
2482 : DPRINTF(QLE_D_INTR, "%s: unknown async %x\n", DEVNAME(sc), info);
2483 : break;
2484 : }
2485 0 : return (1);
2486 : }
2487 :
2488 : void
2489 0 : qle_dump_stuff(struct qle_softc *sc, void *buf, int n)
2490 : {
2491 : #ifdef QLE_DEBUG
2492 : u_int8_t *d = buf;
2493 : int l;
2494 :
2495 : if ((qledebug & QLE_D_IOCB) == 0)
2496 : return;
2497 :
2498 : printf("%s: stuff\n", DEVNAME(sc));
2499 : for (l = 0; l < n; l++) {
2500 : printf(" %2.2x", d[l]);
2501 : if (l % 16 == 15)
2502 : printf("\n");
2503 : }
2504 : if (n % 16 != 0)
2505 : printf("\n");
2506 : #endif
2507 0 : }
2508 :
2509 : void
2510 0 : qle_dump_iocb(struct qle_softc *sc, void *buf)
2511 : {
2512 : #ifdef QLE_DEBUG
2513 : u_int8_t *iocb = buf;
2514 : int l;
2515 : int b;
2516 :
2517 : if ((qledebug & QLE_D_IOCB) == 0)
2518 : return;
2519 :
2520 : printf("%s: iocb:\n", DEVNAME(sc));
2521 : for (l = 0; l < 4; l++) {
2522 : for (b = 0; b < 16; b++) {
2523 : printf(" %2.2x", iocb[(l*16)+b]);
2524 : }
2525 : printf("\n");
2526 : }
2527 : #endif
2528 0 : }
2529 :
2530 : void
2531 0 : qle_dump_iocb_segs(struct qle_softc *sc, void *segs, int n)
2532 : {
2533 : #ifdef QLE_DEBUG
2534 : u_int8_t *buf = segs;
2535 : int s, b;
2536 :
2537 : if ((qledebug & QLE_D_IOCB) == 0)
2538 : return;
2539 :
2540 : printf("%s: iocb segs:\n", DEVNAME(sc));
2541 : for (s = 0; s < n; s++) {
2542 : for (b = 0; b < sizeof(struct qle_iocb_seg); b++) {
2543 : printf(" %2.2x", buf[(s*(sizeof(struct qle_iocb_seg)))
2544 : + b]);
2545 : }
2546 : printf("\n");
2547 : }
2548 : #endif
2549 0 : }
2550 :
2551 : void
2552 0 : qle_put_marker(struct qle_softc *sc, void *buf)
2553 : {
2554 0 : struct qle_iocb_marker *marker = buf;
2555 :
2556 0 : marker->entry_type = QLE_IOCB_MARKER;
2557 0 : marker->entry_count = 1;
2558 0 : marker->seqno = 0;
2559 0 : marker->flags = 0;
2560 :
2561 : /* could be more specific here; isp(4) isn't */
2562 0 : marker->target = 0;
2563 0 : marker->modifier = QLE_IOCB_MARKER_SYNC_ALL;
2564 0 : }
2565 :
2566 : void
2567 0 : qle_sge(struct qle_iocb_seg *seg, u_int64_t addr, u_int32_t len)
2568 : {
2569 0 : htolem32(&seg->seg_addr_lo, addr);
2570 0 : htolem32(&seg->seg_addr_hi, addr >> 32);
2571 0 : htolem32(&seg->seg_len, len);
2572 0 : }
2573 :
2574 : void
2575 0 : qle_put_cmd(struct qle_softc *sc, void *buf, struct scsi_xfer *xs,
2576 : struct qle_ccb *ccb, u_int32_t target_port)
2577 : {
2578 0 : bus_dmamap_t dmap = ccb->ccb_dmamap;
2579 0 : struct qle_iocb_req6 *req = buf;
2580 : struct qle_fcp_cmnd *cmnd;
2581 : u_int64_t fcp_cmnd_offset;
2582 : u_int32_t fcp_dl;
2583 : int seg;
2584 0 : int target = xs->sc_link->target;
2585 0 : int lun = xs->sc_link->lun;
2586 : u_int16_t flags;
2587 :
2588 0 : memset(req, 0, sizeof(*req));
2589 0 : req->entry_type = QLE_IOCB_CMD_TYPE_6;
2590 0 : req->entry_count = 1;
2591 :
2592 0 : req->req_handle = ccb->ccb_id;
2593 0 : htolem16(&req->req_nport_handle, target);
2594 :
2595 : /*
2596 : * timeout is in seconds. make sure it's at least 1 if a timeout
2597 : * was specified in xs
2598 : */
2599 0 : if (xs->timeout != 0)
2600 0 : htolem16(&req->req_timeout, MAX(1, xs->timeout/1000));
2601 :
2602 0 : if (xs->datalen > 0) {
2603 0 : flags = (xs->flags & SCSI_DATA_IN) ?
2604 : QLE_IOCB_CTRL_FLAG_READ : QLE_IOCB_CTRL_FLAG_WRITE;
2605 0 : if (dmap->dm_nsegs == 1) {
2606 0 : qle_sge(&req->req_data_seg, dmap->dm_segs[0].ds_addr,
2607 0 : dmap->dm_segs[0].ds_len);
2608 0 : } else {
2609 0 : flags |= QLE_IOCB_CTRL_FLAG_EXT_SEG;
2610 0 : for (seg = 0; seg < dmap->dm_nsegs; seg++) {
2611 0 : qle_sge(&ccb->ccb_segs[seg],
2612 0 : dmap->dm_segs[seg].ds_addr,
2613 0 : dmap->dm_segs[seg].ds_len);
2614 : }
2615 0 : qle_sge(&ccb->ccb_segs[seg++], 0, 0);
2616 :
2617 0 : bus_dmamap_sync(sc->sc_dmat,
2618 : QLE_DMA_MAP(sc->sc_segments), ccb->ccb_seg_offset,
2619 : seg * sizeof(*ccb->ccb_segs),
2620 : BUS_DMASYNC_PREWRITE);
2621 :
2622 0 : qle_sge(&req->req_data_seg,
2623 0 : QLE_DMA_DVA(sc->sc_segments) + ccb->ccb_seg_offset,
2624 0 : seg * sizeof(struct qle_iocb_seg));
2625 : }
2626 :
2627 0 : htolem16(&req->req_data_seg_count, dmap->dm_nsegs);
2628 0 : htolem32(&req->req_data_len, xs->datalen);
2629 0 : htolem16(&req->req_ctrl_flags, flags);
2630 0 : }
2631 :
2632 0 : htobem16(&req->req_fcp_lun[0], lun);
2633 0 : htobem16(&req->req_fcp_lun[1], lun >> 16);
2634 0 : htolem32(&req->req_target_id, target_port & 0xffffff);
2635 :
2636 0 : fcp_cmnd_offset = ccb->ccb_id * sizeof(*cmnd);
2637 : /* set up FCP_CMND */
2638 0 : cmnd = (struct qle_fcp_cmnd *)QLE_DMA_KVA(sc->sc_fcp_cmnds) +
2639 : ccb->ccb_id;
2640 :
2641 0 : memset(cmnd, 0, sizeof(*cmnd));
2642 0 : htobem16(&cmnd->fcp_lun[0], lun);
2643 0 : htobem16(&cmnd->fcp_lun[1], lun >> 16);
2644 : /* cmnd->fcp_task_attr = TSK_SIMPLE; */
2645 : /* cmnd->fcp_task_mgmt = 0; */
2646 0 : memcpy(cmnd->fcp_cdb, xs->cmd, xs->cmdlen);
2647 :
2648 : /* FCP_DL goes after the cdb */
2649 0 : fcp_dl = htobe32(xs->datalen);
2650 0 : if (xs->cmdlen > 16) {
2651 0 : htolem16(&req->req_fcp_cmnd_len, 12 + xs->cmdlen + 4);
2652 0 : cmnd->fcp_add_cdb_len = xs->cmdlen - 16;
2653 0 : memcpy(cmnd->fcp_cdb + xs->cmdlen, &fcp_dl, sizeof(fcp_dl));
2654 0 : } else {
2655 0 : htolem16(&req->req_fcp_cmnd_len, 12 + 16 + 4);
2656 0 : cmnd->fcp_add_cdb_len = 0;
2657 0 : memcpy(cmnd->fcp_cdb + 16, &fcp_dl, sizeof(fcp_dl));
2658 : }
2659 0 : if (xs->datalen > 0)
2660 0 : cmnd->fcp_add_cdb_len |= (xs->flags & SCSI_DATA_IN) ? 2 : 1;
2661 :
2662 0 : bus_dmamap_sync(sc->sc_dmat,
2663 : QLE_DMA_MAP(sc->sc_fcp_cmnds), fcp_cmnd_offset,
2664 : sizeof(*cmnd), BUS_DMASYNC_PREWRITE);
2665 :
2666 : /* link req to cmnd */
2667 0 : fcp_cmnd_offset += QLE_DMA_DVA(sc->sc_fcp_cmnds);
2668 0 : htolem32(&req->req_fcp_cmnd_addr_lo, fcp_cmnd_offset);
2669 0 : htolem32(&req->req_fcp_cmnd_addr_hi, fcp_cmnd_offset >> 32);
2670 0 : }
2671 :
2672 : int
2673 0 : qle_load_fwchunk(struct qle_softc *sc, struct qle_dmamem *mem,
2674 : const u_int32_t *src)
2675 : {
2676 : u_int32_t dest, done, total;
2677 : int i;
2678 :
2679 0 : dest = src[2];
2680 : done = 0;
2681 0 : total = src[3];
2682 :
2683 0 : while (done < total) {
2684 : u_int32_t *copy;
2685 : u_int32_t words;
2686 :
2687 : /* limit transfer size otherwise it just doesn't work */
2688 0 : words = MIN(total - done, 1 << 10);
2689 0 : copy = QLE_DMA_KVA(mem);
2690 0 : for (i = 0; i < words; i++) {
2691 0 : htolem32(©[i], src[done++]);
2692 : }
2693 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(mem), 0, words * 4,
2694 : BUS_DMASYNC_PREWRITE);
2695 :
2696 0 : sc->sc_mbox[0] = QLE_MBOX_LOAD_RISC_RAM;
2697 0 : sc->sc_mbox[1] = dest;
2698 0 : sc->sc_mbox[4] = words >> 16;
2699 0 : sc->sc_mbox[5] = words & 0xffff;
2700 0 : sc->sc_mbox[8] = dest >> 16;
2701 0 : qle_mbox_putaddr(sc->sc_mbox, mem);
2702 0 : if (qle_mbox(sc, 0x01ff)) {
2703 0 : printf("firmware load failed\n");
2704 0 : return (1);
2705 : }
2706 0 : bus_dmamap_sync(sc->sc_dmat, QLE_DMA_MAP(mem), 0, words * 4,
2707 : BUS_DMASYNC_POSTWRITE);
2708 :
2709 0 : dest += words;
2710 0 : }
2711 :
2712 0 : return (qle_verify_firmware(sc, src[2]));
2713 0 : }
2714 :
2715 : int
2716 0 : qle_load_firmware_chunks(struct qle_softc *sc, const u_int32_t *fw)
2717 : {
2718 : struct qle_dmamem *mem;
2719 : int res = 0;
2720 :
2721 0 : mem = qle_dmamem_alloc(sc, 65536);
2722 0 : for (;;) {
2723 0 : if (qle_load_fwchunk(sc, mem, fw)) {
2724 : res = 1;
2725 0 : break;
2726 : }
2727 0 : if (fw[1] == 0)
2728 : break;
2729 0 : fw += fw[3];
2730 : }
2731 :
2732 0 : qle_dmamem_free(sc, mem);
2733 0 : return (res);
2734 : }
2735 :
2736 : u_int32_t
2737 0 : qle_read_ram_word(struct qle_softc *sc, u_int32_t addr)
2738 : {
2739 0 : sc->sc_mbox[0] = QLE_MBOX_READ_RISC_RAM;
2740 0 : sc->sc_mbox[1] = addr & 0xffff;
2741 0 : sc->sc_mbox[8] = addr >> 16;
2742 0 : if (qle_mbox(sc, 0x0103)) {
2743 0 : return (0);
2744 : }
2745 0 : return ((sc->sc_mbox[3] << 16) | sc->sc_mbox[2]);
2746 0 : }
2747 :
2748 : int
2749 0 : qle_verify_firmware(struct qle_softc *sc, u_int32_t addr)
2750 : {
2751 : /*
2752 : * QLE_MBOX_VERIFY_CSUM requires at least the firmware header
2753 : * to be correct, otherwise it wanders all over ISP memory and
2754 : * gets lost. Check that chunk address (addr+2) is right and
2755 : * size (addr+3) is plausible first.
2756 : */
2757 0 : if ((qle_read_ram_word(sc, addr+2) != addr) ||
2758 0 : (qle_read_ram_word(sc, addr+3) > 0xffff)) {
2759 0 : return (1);
2760 : }
2761 :
2762 0 : sc->sc_mbox[0] = QLE_MBOX_VERIFY_CSUM;
2763 0 : sc->sc_mbox[1] = addr >> 16;
2764 0 : sc->sc_mbox[2] = addr;
2765 0 : if (qle_mbox(sc, 0x0007)) {
2766 0 : return (1);
2767 : }
2768 0 : return (0);
2769 0 : }
2770 :
2771 : int
2772 0 : qle_read_nvram(struct qle_softc *sc)
2773 : {
2774 0 : u_int32_t data[sizeof(sc->sc_nvram) / 4];
2775 : u_int32_t csum, tmp, v;
2776 : int i, base, l;
2777 :
2778 0 : switch (sc->sc_isp_gen) {
2779 : case QLE_GEN_ISP24XX:
2780 : base = 0x7ffe0080;
2781 0 : break;
2782 : case QLE_GEN_ISP25XX:
2783 : base = 0x7ff48080;
2784 0 : break;
2785 : }
2786 0 : base += sc->sc_port * 0x100;
2787 :
2788 : csum = 0;
2789 0 : for (i = 0; i < nitems(data); i++) {
2790 0 : data[i] = 0xffffffff;
2791 0 : qle_write(sc, QLE_FLASH_NVRAM_ADDR, base + i);
2792 0 : for (l = 0; l < 5000; l++) {
2793 0 : delay(10);
2794 0 : tmp = qle_read(sc, QLE_FLASH_NVRAM_ADDR);
2795 0 : if (tmp & (1U << 31)) {
2796 0 : v = qle_read(sc, QLE_FLASH_NVRAM_DATA);
2797 0 : csum += v;
2798 0 : data[i] = letoh32(v);
2799 0 : break;
2800 : }
2801 : }
2802 : }
2803 :
2804 0 : bcopy(data, &sc->sc_nvram, sizeof(sc->sc_nvram));
2805 : /* id field should be 'ISP' */
2806 0 : if (sc->sc_nvram.id[0] != 'I' || sc->sc_nvram.id[1] != 'S' ||
2807 0 : sc->sc_nvram.id[2] != 'P' || csum != 0) {
2808 0 : printf("%s: nvram corrupt\n", DEVNAME(sc));
2809 0 : return (1);
2810 : }
2811 0 : return (0);
2812 0 : }
2813 :
2814 : struct qle_dmamem *
2815 0 : qle_dmamem_alloc(struct qle_softc *sc, size_t size)
2816 : {
2817 : struct qle_dmamem *m;
2818 0 : int nsegs;
2819 :
2820 0 : m = malloc(sizeof(*m), M_DEVBUF, M_NOWAIT | M_ZERO);
2821 0 : if (m == NULL)
2822 0 : return (NULL);
2823 :
2824 0 : m->qdm_size = size;
2825 :
2826 0 : if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
2827 0 : BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &m->qdm_map) != 0)
2828 : goto qdmfree;
2829 :
2830 0 : if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &m->qdm_seg, 1,
2831 0 : &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
2832 : goto destroy;
2833 :
2834 0 : if (bus_dmamem_map(sc->sc_dmat, &m->qdm_seg, nsegs, size, &m->qdm_kva,
2835 0 : BUS_DMA_NOWAIT) != 0)
2836 : goto free;
2837 :
2838 0 : if (bus_dmamap_load(sc->sc_dmat, m->qdm_map, m->qdm_kva, size, NULL,
2839 0 : BUS_DMA_NOWAIT) != 0)
2840 : goto unmap;
2841 :
2842 0 : return (m);
2843 :
2844 : unmap:
2845 0 : bus_dmamem_unmap(sc->sc_dmat, m->qdm_kva, m->qdm_size);
2846 : free:
2847 0 : bus_dmamem_free(sc->sc_dmat, &m->qdm_seg, 1);
2848 : destroy:
2849 0 : bus_dmamap_destroy(sc->sc_dmat, m->qdm_map);
2850 : qdmfree:
2851 0 : free(m, M_DEVBUF, sizeof *m);
2852 :
2853 0 : return (NULL);
2854 0 : }
2855 :
2856 : void
2857 0 : qle_dmamem_free(struct qle_softc *sc, struct qle_dmamem *m)
2858 : {
2859 0 : bus_dmamap_unload(sc->sc_dmat, m->qdm_map);
2860 0 : bus_dmamem_unmap(sc->sc_dmat, m->qdm_kva, m->qdm_size);
2861 0 : bus_dmamem_free(sc->sc_dmat, &m->qdm_seg, 1);
2862 0 : bus_dmamap_destroy(sc->sc_dmat, m->qdm_map);
2863 0 : free(m, M_DEVBUF, sizeof *m);
2864 0 : }
2865 :
2866 : int
2867 0 : qle_alloc_ccbs(struct qle_softc *sc)
2868 : {
2869 : struct qle_ccb *ccb;
2870 : u_int8_t *cmd;
2871 : int i;
2872 :
2873 0 : SIMPLEQ_INIT(&sc->sc_ccb_free);
2874 0 : mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
2875 0 : mtx_init(&sc->sc_queue_mtx, IPL_BIO);
2876 0 : mtx_init(&sc->sc_port_mtx, IPL_BIO);
2877 0 : mtx_init(&sc->sc_mbox_mtx, IPL_BIO);
2878 :
2879 0 : sc->sc_ccbs = mallocarray(sc->sc_maxcmds, sizeof(struct qle_ccb),
2880 : M_DEVBUF, M_WAITOK | M_CANFAIL | M_ZERO);
2881 0 : if (sc->sc_ccbs == NULL) {
2882 0 : printf("%s: unable to allocate ccbs\n", DEVNAME(sc));
2883 0 : return (1);
2884 : }
2885 :
2886 0 : sc->sc_requests = qle_dmamem_alloc(sc, sc->sc_maxcmds *
2887 : QLE_QUEUE_ENTRY_SIZE);
2888 0 : if (sc->sc_requests == NULL) {
2889 0 : printf("%s: unable to allocate ccb dmamem\n", DEVNAME(sc));
2890 0 : goto free_ccbs;
2891 : }
2892 0 : sc->sc_responses = qle_dmamem_alloc(sc, sc->sc_maxcmds *
2893 : QLE_QUEUE_ENTRY_SIZE);
2894 0 : if (sc->sc_responses == NULL) {
2895 0 : printf("%s: unable to allocate rcb dmamem\n", DEVNAME(sc));
2896 0 : goto free_req;
2897 : }
2898 0 : sc->sc_pri_requests = qle_dmamem_alloc(sc, 8 * QLE_QUEUE_ENTRY_SIZE);
2899 0 : if (sc->sc_pri_requests == NULL) {
2900 0 : printf("%s: unable to allocate pri ccb dmamem\n", DEVNAME(sc));
2901 0 : goto free_pri;
2902 : }
2903 0 : sc->sc_segments = qle_dmamem_alloc(sc, sc->sc_maxcmds * QLE_MAX_SEGS *
2904 : sizeof(struct qle_iocb_seg));
2905 0 : if (sc->sc_segments == NULL) {
2906 0 : printf("%s: unable to allocate iocb segments\n", DEVNAME(sc));
2907 0 : goto free_res;
2908 : }
2909 :
2910 0 : sc->sc_fcp_cmnds = qle_dmamem_alloc(sc, sc->sc_maxcmds *
2911 : sizeof(struct qle_fcp_cmnd));
2912 0 : if (sc->sc_fcp_cmnds == NULL) {
2913 0 : printf("%s: unable to allocate FCP_CMNDs\n", DEVNAME(sc));
2914 0 : goto free_seg;
2915 : }
2916 :
2917 0 : cmd = QLE_DMA_KVA(sc->sc_requests);
2918 0 : memset(cmd, 0, QLE_QUEUE_ENTRY_SIZE * sc->sc_maxcmds);
2919 0 : for (i = 0; i < sc->sc_maxcmds; i++) {
2920 0 : ccb = &sc->sc_ccbs[i];
2921 :
2922 0 : if (bus_dmamap_create(sc->sc_dmat, MAXPHYS,
2923 : QLE_MAX_SEGS-1, MAXPHYS, 0,
2924 : BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
2925 0 : &ccb->ccb_dmamap) != 0) {
2926 0 : printf("%s: unable to create dma map\n", DEVNAME(sc));
2927 : goto free_maps;
2928 : }
2929 :
2930 0 : ccb->ccb_sc = sc;
2931 0 : ccb->ccb_id = i;
2932 :
2933 0 : ccb->ccb_seg_offset = i * QLE_MAX_SEGS *
2934 : sizeof(struct qle_iocb_seg);
2935 0 : ccb->ccb_segs = QLE_DMA_KVA(sc->sc_segments) +
2936 : ccb->ccb_seg_offset;
2937 :
2938 0 : qle_put_ccb(sc, ccb);
2939 : }
2940 :
2941 0 : scsi_iopool_init(&sc->sc_iopool, sc, qle_get_ccb, qle_put_ccb);
2942 0 : return (0);
2943 :
2944 : free_maps:
2945 0 : while ((ccb = qle_get_ccb(sc)) != NULL)
2946 0 : bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
2947 :
2948 0 : qle_dmamem_free(sc, sc->sc_fcp_cmnds);
2949 : free_seg:
2950 0 : qle_dmamem_free(sc, sc->sc_segments);
2951 : free_pri:
2952 0 : qle_dmamem_free(sc, sc->sc_pri_requests);
2953 : free_res:
2954 0 : qle_dmamem_free(sc, sc->sc_responses);
2955 : free_req:
2956 0 : qle_dmamem_free(sc, sc->sc_requests);
2957 : free_ccbs:
2958 0 : free(sc->sc_ccbs, M_DEVBUF, 0);
2959 :
2960 0 : return (1);
2961 0 : }
2962 :
2963 : void
2964 0 : qle_free_ccbs(struct qle_softc *sc)
2965 : {
2966 : struct qle_ccb *ccb;
2967 :
2968 0 : scsi_iopool_destroy(&sc->sc_iopool);
2969 0 : while ((ccb = qle_get_ccb(sc)) != NULL)
2970 0 : bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
2971 0 : qle_dmamem_free(sc, sc->sc_segments);
2972 0 : qle_dmamem_free(sc, sc->sc_responses);
2973 0 : qle_dmamem_free(sc, sc->sc_requests);
2974 0 : free(sc->sc_ccbs, M_DEVBUF, 0);
2975 0 : }
2976 :
2977 : void *
2978 0 : qle_get_ccb(void *xsc)
2979 : {
2980 0 : struct qle_softc *sc = xsc;
2981 : struct qle_ccb *ccb;
2982 :
2983 0 : mtx_enter(&sc->sc_ccb_mtx);
2984 0 : ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free);
2985 0 : if (ccb != NULL) {
2986 0 : SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_link);
2987 : }
2988 0 : mtx_leave(&sc->sc_ccb_mtx);
2989 0 : return (ccb);
2990 : }
2991 :
2992 : void
2993 0 : qle_put_ccb(void *xsc, void *io)
2994 : {
2995 0 : struct qle_softc *sc = xsc;
2996 0 : struct qle_ccb *ccb = io;
2997 :
2998 0 : ccb->ccb_xs = NULL;
2999 0 : mtx_enter(&sc->sc_ccb_mtx);
3000 0 : SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_link);
3001 0 : mtx_leave(&sc->sc_ccb_mtx);
3002 0 : }
|