xref: /openbsd/sys/dev/ic/qlw.c (revision a454aff3)
1*a454aff3Snaddy /*	$OpenBSD: qlw.c,v 1.48 2022/04/16 19:19:59 naddy Exp $ */
2c0265cf2Skettenis 
3c0265cf2Skettenis /*
4c0265cf2Skettenis  * Copyright (c) 2011 David Gwynne <dlg@openbsd.org>
5c0265cf2Skettenis  * Copyright (c) 2013, 2014 Jonathan Matthew <jmatthew@openbsd.org>
6c0265cf2Skettenis  * Copyright (c) 2014 Mark Kettenis <kettenis@openbsd.org>
7c0265cf2Skettenis  *
8c0265cf2Skettenis  * Permission to use, copy, modify, and distribute this software for any
9c0265cf2Skettenis  * purpose with or without fee is hereby granted, provided that the above
10c0265cf2Skettenis  * copyright notice and this permission notice appear in all copies.
11c0265cf2Skettenis  *
12c0265cf2Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13c0265cf2Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14c0265cf2Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15c0265cf2Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16c0265cf2Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17c0265cf2Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18c0265cf2Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19c0265cf2Skettenis  */
20c0265cf2Skettenis 
21c0265cf2Skettenis #include <sys/param.h>
22c0265cf2Skettenis #include <sys/systm.h>
239a1bdb58Svisa #include <sys/atomic.h>
24c0265cf2Skettenis #include <sys/device.h>
25c0265cf2Skettenis #include <sys/ioctl.h>
26c0265cf2Skettenis #include <sys/malloc.h>
27c0265cf2Skettenis #include <sys/kernel.h>
28c0265cf2Skettenis #include <sys/mutex.h>
29c0265cf2Skettenis #include <sys/rwlock.h>
30c0265cf2Skettenis #include <sys/sensors.h>
31c0265cf2Skettenis #include <sys/queue.h>
32c0265cf2Skettenis 
33c0265cf2Skettenis #include <machine/bus.h>
34c0265cf2Skettenis 
35c0265cf2Skettenis #include <scsi/scsi_all.h>
36c0265cf2Skettenis #include <scsi/scsiconf.h>
37c0265cf2Skettenis 
38c0265cf2Skettenis #include <dev/ic/qlwreg.h>
39c0265cf2Skettenis #include <dev/ic/qlwvar.h>
40c0265cf2Skettenis 
41f575935dSmiod #ifndef SMALL_KERNEL
42500422e9Skrw #ifndef QLW_DEBUG
43c0265cf2Skettenis #define QLW_DEBUG
44f575935dSmiod #endif
45500422e9Skrw #endif
46c0265cf2Skettenis 
47c0265cf2Skettenis #ifdef QLW_DEBUG
48c0265cf2Skettenis #define DPRINTF(m, f...) do { if ((qlwdebug & (m)) == (m)) printf(f); } \
49c0265cf2Skettenis     while (0)
50c0265cf2Skettenis #define QLW_D_MBOX		0x01
51c0265cf2Skettenis #define QLW_D_INTR		0x02
52c0265cf2Skettenis #define QLW_D_PORT		0x04
53c0265cf2Skettenis #define QLW_D_IO		0x08
54c0265cf2Skettenis #define QLW_D_IOCB		0x10
55a0291dabSkettenis int qlwdebug = QLW_D_PORT | QLW_D_INTR | QLW_D_MBOX;
56c0265cf2Skettenis #else
57c0265cf2Skettenis #define DPRINTF(m, f...)
58c0265cf2Skettenis #endif
59c0265cf2Skettenis 
60c0265cf2Skettenis struct cfdriver qlw_cd = {
61c0265cf2Skettenis 	NULL,
62c0265cf2Skettenis 	"qlw",
63c0265cf2Skettenis 	DV_DULL
64c0265cf2Skettenis };
65c0265cf2Skettenis 
66c0265cf2Skettenis void		qlw_scsi_cmd(struct scsi_xfer *);
67c0265cf2Skettenis 
68c0265cf2Skettenis u_int16_t	qlw_read(struct qlw_softc *, bus_size_t);
69c0265cf2Skettenis void		qlw_write(struct qlw_softc *, bus_size_t, u_int16_t);
70c0265cf2Skettenis void		qlw_host_cmd(struct qlw_softc *sc, u_int16_t);
71c0265cf2Skettenis 
72c0265cf2Skettenis int		qlw_mbox(struct qlw_softc *, int, int);
73c0265cf2Skettenis void		qlw_mbox_putaddr(u_int16_t *, struct qlw_dmamem *);
74c0265cf2Skettenis u_int16_t	qlw_read_mbox(struct qlw_softc *, int);
75c0265cf2Skettenis void		qlw_write_mbox(struct qlw_softc *, int, u_int16_t);
76c0265cf2Skettenis 
77c0265cf2Skettenis int		qlw_config_bus(struct qlw_softc *, int);
78c0265cf2Skettenis int		qlw_config_target(struct qlw_softc *, int, int);
79c0265cf2Skettenis void		qlw_update_bus(struct qlw_softc *, int);
80c0265cf2Skettenis void		qlw_update_target(struct qlw_softc *, int, int);
81e4195480Sdlg void		qlw_update_task(void *);
82c0265cf2Skettenis 
83c0265cf2Skettenis void		qlw_handle_intr(struct qlw_softc *, u_int16_t, u_int16_t);
84c0265cf2Skettenis void		qlw_set_ints(struct qlw_softc *, int);
85c0265cf2Skettenis int		qlw_read_isr(struct qlw_softc *, u_int16_t *, u_int16_t *);
86c0265cf2Skettenis void		qlw_clear_isr(struct qlw_softc *, u_int16_t);
87c0265cf2Skettenis 
88c0265cf2Skettenis void		qlw_update(struct qlw_softc *, int);
89c0265cf2Skettenis void		qlw_put_marker(struct qlw_softc *, int, void *);
90c0265cf2Skettenis void		qlw_put_cmd(struct qlw_softc *, void *, struct scsi_xfer *,
91c0265cf2Skettenis 		    struct qlw_ccb *);
92c0265cf2Skettenis void		qlw_put_cont(struct qlw_softc *, void *, struct scsi_xfer *,
93c0265cf2Skettenis 		    struct qlw_ccb *, int);
94c0265cf2Skettenis struct qlw_ccb *qlw_handle_resp(struct qlw_softc *, u_int16_t);
95de2fb981Skettenis void		qlw_get_header(struct qlw_softc *, struct qlw_iocb_hdr *,
96de2fb981Skettenis 		    int *, int *);
97de2fb981Skettenis void		qlw_put_header(struct qlw_softc *, struct qlw_iocb_hdr *,
98de2fb981Skettenis 		    int, int);
99de2fb981Skettenis void		qlw_put_data_seg(struct qlw_softc *, struct qlw_iocb_seg *,
100de2fb981Skettenis 		    bus_dmamap_t, int);
101c0265cf2Skettenis 
102c0265cf2Skettenis int		qlw_softreset(struct qlw_softc *);
103fdfcaeaeSkettenis void		qlw_dma_burst_enable(struct qlw_softc *);
104c0265cf2Skettenis 
105c0265cf2Skettenis int		qlw_async(struct qlw_softc *, u_int16_t);
106c0265cf2Skettenis 
107c0265cf2Skettenis int		qlw_load_firmware_words(struct qlw_softc *, const u_int16_t *,
108c0265cf2Skettenis 		    u_int16_t);
109c0265cf2Skettenis int		qlw_load_firmware(struct qlw_softc *);
110c0265cf2Skettenis int		qlw_read_nvram(struct qlw_softc *);
111c0265cf2Skettenis void		qlw_parse_nvram_1040(struct qlw_softc *, int);
112c0265cf2Skettenis void		qlw_parse_nvram_1080(struct qlw_softc *, int);
113c0265cf2Skettenis void		qlw_init_defaults(struct qlw_softc *, int);
114c0265cf2Skettenis 
115c0265cf2Skettenis struct qlw_dmamem *qlw_dmamem_alloc(struct qlw_softc *, size_t);
116c0265cf2Skettenis void		qlw_dmamem_free(struct qlw_softc *, struct qlw_dmamem *);
117c0265cf2Skettenis 
118c0265cf2Skettenis int		qlw_alloc_ccbs(struct qlw_softc *);
119c0265cf2Skettenis void		qlw_free_ccbs(struct qlw_softc *);
120c0265cf2Skettenis void		*qlw_get_ccb(void *);
121c0265cf2Skettenis void		qlw_put_ccb(void *, void *);
122c0265cf2Skettenis 
123f575935dSmiod #ifdef QLW_DEBUG
124a0291dabSkettenis void		qlw_dump_iocb(struct qlw_softc *, void *, int);
125c0265cf2Skettenis void		qlw_dump_iocb_segs(struct qlw_softc *, void *, int);
126f575935dSmiod #else
127f575935dSmiod #define qlw_dump_iocb(sc, h, fl)	do { /* nothing */ } while (0)
128f575935dSmiod #define qlw_dump_iocb_segs(sc, h, fl)	do { /* nothing */ } while (0)
129f575935dSmiod #endif
130c0265cf2Skettenis 
131c0265cf2Skettenis static inline int
qlw_xs_bus(struct qlw_softc * sc,struct scsi_xfer * xs)132c0265cf2Skettenis qlw_xs_bus(struct qlw_softc *sc, struct scsi_xfer *xs)
133c0265cf2Skettenis {
134471fe7efSkrw 	/*
135471fe7efSkrw 	 * sc_scsibus[0] == NULL -> bus 0 probing during config_found().
136471fe7efSkrw 	 * sc_scsibus[0] == xs->sc_link->bus -> bus 0 normal operation.
137471fe7efSkrw 	 * sc_scsibus[1] == NULL -> bus 1 probing during config_found().
138471fe7efSkrw 	 * sc_scsibus[1] == xs->sc_link->bus -> bus 1 normal operation.
139471fe7efSkrw 	 */
140471fe7efSkrw 	if ((sc->sc_scsibus[0] == NULL) ||
141471fe7efSkrw 	    (xs->sc_link->bus == sc->sc_scsibus[0]))
142471fe7efSkrw 		return 0;
143471fe7efSkrw 	else
144471fe7efSkrw 		return 1;
145c0265cf2Skettenis }
146c0265cf2Skettenis 
147e753b624Skettenis static inline u_int16_t
qlw_swap16(struct qlw_softc * sc,u_int16_t value)148de2fb981Skettenis qlw_swap16(struct qlw_softc *sc, u_int16_t value)
149de2fb981Skettenis {
150de2fb981Skettenis 	if (sc->sc_isp_gen == QLW_GEN_ISP1000)
151de2fb981Skettenis 		return htobe16(value);
152de2fb981Skettenis 	else
153de2fb981Skettenis 		return htole16(value);
154de2fb981Skettenis }
155de2fb981Skettenis 
156de2fb981Skettenis static inline u_int32_t
qlw_swap32(struct qlw_softc * sc,u_int32_t value)157de2fb981Skettenis qlw_swap32(struct qlw_softc *sc, u_int32_t value)
158de2fb981Skettenis {
159de2fb981Skettenis 	if (sc->sc_isp_gen == QLW_GEN_ISP1000)
160de2fb981Skettenis 		return htobe32(value);
161de2fb981Skettenis 	else
162de2fb981Skettenis 		return htole32(value);
163de2fb981Skettenis }
164de2fb981Skettenis 
165de2fb981Skettenis static inline u_int16_t
qlw_queue_read(struct qlw_softc * sc,bus_size_t offset)166e753b624Skettenis qlw_queue_read(struct qlw_softc *sc, bus_size_t offset)
167e753b624Skettenis {
168e753b624Skettenis 	return qlw_read(sc, sc->sc_mbox_base + offset);
169e753b624Skettenis }
170e753b624Skettenis 
171e753b624Skettenis static inline void
qlw_queue_write(struct qlw_softc * sc,bus_size_t offset,u_int16_t value)172e753b624Skettenis qlw_queue_write(struct qlw_softc *sc, bus_size_t offset, u_int16_t value)
173e753b624Skettenis {
174e753b624Skettenis 	qlw_write(sc, sc->sc_mbox_base + offset, value);
175e753b624Skettenis }
176c0265cf2Skettenis 
177*a454aff3Snaddy const struct scsi_adapter qlw_switch = {
1783c596f75Skrw 	qlw_scsi_cmd, NULL, NULL, NULL, NULL
179c0265cf2Skettenis };
180c0265cf2Skettenis 
181c0265cf2Skettenis int
qlw_attach(struct qlw_softc * sc)182c0265cf2Skettenis qlw_attach(struct qlw_softc *sc)
183c0265cf2Skettenis {
184c0265cf2Skettenis 	struct scsibus_attach_args saa;
185c0265cf2Skettenis 	void (*parse_nvram)(struct qlw_softc *, int);
186c0265cf2Skettenis 	int reset_delay;
187c0265cf2Skettenis 	int bus;
188c0265cf2Skettenis 
189e4195480Sdlg 	task_set(&sc->sc_update_task, qlw_update_task, sc);
19077bba8c0Skettenis 
191c0265cf2Skettenis 	switch (sc->sc_isp_gen) {
192e753b624Skettenis 	case QLW_GEN_ISP1000:
193e753b624Skettenis 		sc->sc_nvram_size = 0;
194e753b624Skettenis 		break;
195c0265cf2Skettenis 	case QLW_GEN_ISP1040:
196c0265cf2Skettenis 		sc->sc_nvram_size = 128;
197c0265cf2Skettenis 		sc->sc_nvram_minversion = 2;
198c0265cf2Skettenis 		parse_nvram = qlw_parse_nvram_1040;
199c0265cf2Skettenis 		break;
200c0265cf2Skettenis 	case QLW_GEN_ISP1080:
201c0265cf2Skettenis 	case QLW_GEN_ISP12160:
202c0265cf2Skettenis 		sc->sc_nvram_size = 256;
203c0265cf2Skettenis 		sc->sc_nvram_minversion = 1;
204c0265cf2Skettenis 		parse_nvram = qlw_parse_nvram_1080;
205c0265cf2Skettenis 		break;
206c0265cf2Skettenis 
207c0265cf2Skettenis 	default:
208c0265cf2Skettenis 		printf("unknown isp type\n");
209c0265cf2Skettenis 		return (ENXIO);
210c0265cf2Skettenis 	}
211c0265cf2Skettenis 
212c0265cf2Skettenis 	/* after reset, mbox registers 1-3 should contain the string "ISP   " */
213c0265cf2Skettenis 	if (qlw_read_mbox(sc, 1) != 0x4953 ||
214c0265cf2Skettenis 	    qlw_read_mbox(sc, 2) != 0x5020 ||
215c0265cf2Skettenis 	    qlw_read_mbox(sc, 3) != 0x2020) {
216c0265cf2Skettenis 		/* try releasing the risc processor */
217c0265cf2Skettenis 		qlw_host_cmd(sc, QLW_HOST_CMD_RELEASE);
218c0265cf2Skettenis 	}
219c0265cf2Skettenis 
220c0265cf2Skettenis 	qlw_host_cmd(sc, QLW_HOST_CMD_PAUSE);
221c0265cf2Skettenis 	if (qlw_softreset(sc) != 0) {
222c0265cf2Skettenis 		printf("softreset failed\n");
223c0265cf2Skettenis 		return (ENXIO);
224c0265cf2Skettenis 	}
225c0265cf2Skettenis 
226c0265cf2Skettenis 	for (bus = 0; bus < sc->sc_numbusses; bus++)
227c0265cf2Skettenis 		qlw_init_defaults(sc, bus);
228c0265cf2Skettenis 
229c0265cf2Skettenis 	if (qlw_read_nvram(sc) == 0) {
230c0265cf2Skettenis 		for (bus = 0; bus < sc->sc_numbusses; bus++)
231c0265cf2Skettenis 			parse_nvram(sc, bus);
232c0265cf2Skettenis 	}
233c0265cf2Skettenis 
234c0265cf2Skettenis #ifndef ISP_NOFIRMWARE
235d596111dSkettenis 	if (sc->sc_firmware && qlw_load_firmware(sc)) {
236c0265cf2Skettenis 		printf("firmware load failed\n");
237c0265cf2Skettenis 		return (ENXIO);
238c0265cf2Skettenis 	}
239c0265cf2Skettenis #endif
240c0265cf2Skettenis 
241c0265cf2Skettenis 	/* execute firmware */
242c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_EXEC_FIRMWARE;
243c0265cf2Skettenis 	sc->sc_mbox[1] = QLW_CODE_ORG;
244c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0003, 0x0001)) {
245c0265cf2Skettenis 		printf("ISP couldn't exec firmware: %x\n", sc->sc_mbox[0]);
246c0265cf2Skettenis 		return (ENXIO);
247c0265cf2Skettenis 	}
248c0265cf2Skettenis 
249c0265cf2Skettenis 	delay(250000);		/* from isp(4) */
250c0265cf2Skettenis 
251c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_ABOUT_FIRMWARE;
252c0265cf2Skettenis 	if (qlw_mbox(sc, QLW_MBOX_ABOUT_FIRMWARE_IN,
253c0265cf2Skettenis 	    QLW_MBOX_ABOUT_FIRMWARE_OUT)) {
254c0265cf2Skettenis 		printf("ISP not talking after firmware exec: %x\n",
255c0265cf2Skettenis 		    sc->sc_mbox[0]);
256c0265cf2Skettenis 		return (ENXIO);
257c0265cf2Skettenis 	}
258542641bcSkettenis 	/* The ISP1000 firmware we use doesn't return a version number. */
259542641bcSkettenis 	if (sc->sc_isp_gen == QLW_GEN_ISP1000 && sc->sc_firmware) {
260542641bcSkettenis 		sc->sc_mbox[1] = 1;
261542641bcSkettenis 		sc->sc_mbox[2] = 37;
262542641bcSkettenis 		sc->sc_mbox[3] = 0;
263542641bcSkettenis 		sc->sc_mbox[6] = 0;
264542641bcSkettenis 	}
265c0265cf2Skettenis 	printf("%s: firmware rev %d.%d.%d, attrs 0x%x\n", DEVNAME(sc),
266c0265cf2Skettenis 	    sc->sc_mbox[1], sc->sc_mbox[2], sc->sc_mbox[3], sc->sc_mbox[6]);
267c0265cf2Skettenis 
268c0265cf2Skettenis 	/* work out how many ccbs to allocate */
269c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_GET_FIRMWARE_STATUS;
270c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0001, 0x0007)) {
271c0265cf2Skettenis 		printf("couldn't get firmware status: %x\n", sc->sc_mbox[0]);
272c0265cf2Skettenis 		return (ENXIO);
273c0265cf2Skettenis 	}
27451fb3575Skettenis 	sc->sc_maxrequests = sc->sc_mbox[2];
27551fb3575Skettenis 	if (sc->sc_maxrequests > 512)
27651fb3575Skettenis 		sc->sc_maxrequests = 512;
277c0265cf2Skettenis 	for (bus = 0; bus < sc->sc_numbusses; bus++) {
27851fb3575Skettenis 		if (sc->sc_max_queue_depth[bus] > sc->sc_maxrequests)
27951fb3575Skettenis 			sc->sc_max_queue_depth[bus] = sc->sc_maxrequests;
280c0265cf2Skettenis 	}
281c0265cf2Skettenis 
28251fb3575Skettenis 	/*
28351fb3575Skettenis 	 * On some 1020/1040 variants the response queue is limited to
28451fb3575Skettenis 	 * 256 entries.  We don't really need all that many anyway.
28551fb3575Skettenis 	 */
28651fb3575Skettenis 	sc->sc_maxresponses = sc->sc_maxrequests / 2;
28751fb3575Skettenis 	if (sc->sc_maxresponses < 64)
28851fb3575Skettenis 		sc->sc_maxresponses = 64;
28951fb3575Skettenis 
29092d24382Skettenis 	/* We may need up to 3 request entries per SCSI command. */
29151fb3575Skettenis 	sc->sc_maxccbs = sc->sc_maxrequests / 3;
29292d24382Skettenis 
293fdfcaeaeSkettenis 	/* Allegedly the FIFO is busted on the 1040A. */
294fdfcaeaeSkettenis 	if (sc->sc_isp_type == QLW_ISP1040A)
295fdfcaeaeSkettenis 		sc->sc_isp_config &= ~QLW_PCI_FIFO_MASK;
296fdfcaeaeSkettenis 	qlw_write(sc, QLW_CFG1, sc->sc_isp_config);
297fdfcaeaeSkettenis 
298fdfcaeaeSkettenis 	if (sc->sc_isp_config & QLW_BURST_ENABLE)
299fdfcaeaeSkettenis 		qlw_dma_burst_enable(sc);
300c0265cf2Skettenis 
301c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_FIRMWARE_FEATURES;
302d28ac15bSkettenis 	sc->sc_mbox[1] = 0;
303d28ac15bSkettenis 	if (sc->sc_fw_features & QLW_FW_FEATURE_LVD_NOTIFY)
304d28ac15bSkettenis 		sc->sc_mbox[1] |= QLW_FW_FEATURE_LVD_NOTIFY;
30542ac58b3Skettenis 	if (sc->sc_mbox[1] != 0 && qlw_mbox(sc, 0x0003, 0x0001)) {
306c0265cf2Skettenis 		printf("couldn't set firmware features: %x\n", sc->sc_mbox[0]);
307c0265cf2Skettenis 		return (ENXIO);
308c0265cf2Skettenis 	}
309c0265cf2Skettenis 
310c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_CLOCK_RATE;
311c0265cf2Skettenis 	sc->sc_mbox[1] = sc->sc_clock;
312c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0003, 0x0001)) {
313ed5a1e2cSkettenis 		printf("couldn't set clock rate: %x\n", sc->sc_mbox[0]);
314c0265cf2Skettenis 		return (ENXIO);
315c0265cf2Skettenis 	}
316c0265cf2Skettenis 
317c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_RETRY_COUNT;
318c0265cf2Skettenis 	sc->sc_mbox[1] = sc->sc_retry_count[0];
319c0265cf2Skettenis 	sc->sc_mbox[2] = sc->sc_retry_delay[0];
320c0265cf2Skettenis 	sc->sc_mbox[6] = sc->sc_retry_count[1];
321c0265cf2Skettenis 	sc->sc_mbox[7] = sc->sc_retry_delay[1];
322c0265cf2Skettenis 	if (qlw_mbox(sc, 0x00c7, 0x0001)) {
323c0265cf2Skettenis 		printf("couldn't set retry count: %x\n", sc->sc_mbox[0]);
324c0265cf2Skettenis 		return (ENXIO);
325c0265cf2Skettenis 	}
326c0265cf2Skettenis 
327c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_ASYNC_DATA_SETUP;
328c0265cf2Skettenis 	sc->sc_mbox[1] = sc->sc_async_data_setup[0];
329c0265cf2Skettenis 	sc->sc_mbox[2] = sc->sc_async_data_setup[1];
330c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0007, 0x0001)) {
331c0265cf2Skettenis 		printf("couldn't set async data setup: %x\n", sc->sc_mbox[0]);
332c0265cf2Skettenis 		return (ENXIO);
333c0265cf2Skettenis 	}
334c0265cf2Skettenis 
335c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_ACTIVE_NEGATION;
336c0265cf2Skettenis 	sc->sc_mbox[1] = sc->sc_req_ack_active_neg[0] << 5;
337c0265cf2Skettenis 	sc->sc_mbox[1] |= sc->sc_data_line_active_neg[0] << 4;
338c0265cf2Skettenis 	sc->sc_mbox[2] = sc->sc_req_ack_active_neg[1] << 5;
339c0265cf2Skettenis 	sc->sc_mbox[2] |= sc->sc_data_line_active_neg[1] << 4;
340c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0007, 0x0001)) {
341c0265cf2Skettenis 		printf("couldn't set active negation: %x\n", sc->sc_mbox[0]);
342c0265cf2Skettenis 		return (ENXIO);
343c0265cf2Skettenis 	}
344c0265cf2Skettenis 
345c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_TAG_AGE_LIMIT;
346d28ac15bSkettenis 	sc->sc_mbox[1] = sc->sc_tag_age_limit[0];
347d28ac15bSkettenis 	sc->sc_mbox[2] = sc->sc_tag_age_limit[1];
348c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0007, 0x0001)) {
349c0265cf2Skettenis 		printf("couldn't set tag age limit: %x\n", sc->sc_mbox[0]);
350c0265cf2Skettenis 		return (ENXIO);
351c0265cf2Skettenis 	}
352c0265cf2Skettenis 
353c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_SELECTION_TIMEOUT;
354c0265cf2Skettenis 	sc->sc_mbox[1] = sc->sc_selection_timeout[0];
355c0265cf2Skettenis 	sc->sc_mbox[2] = sc->sc_selection_timeout[1];
356c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0007, 0x0001)) {
357c0265cf2Skettenis 		printf("couldn't set selection timeout: %x\n", sc->sc_mbox[0]);
358c0265cf2Skettenis 		return (ENXIO);
359c0265cf2Skettenis 	}
360c0265cf2Skettenis 
361c0265cf2Skettenis 	for (bus = 0; bus < sc->sc_numbusses; bus++) {
362c0265cf2Skettenis 		if (qlw_config_bus(sc, bus))
363c0265cf2Skettenis 			return (ENXIO);
364c0265cf2Skettenis 	}
365c0265cf2Skettenis 
366c0265cf2Skettenis 	if (qlw_alloc_ccbs(sc)) {
367c0265cf2Skettenis 		/* error already printed */
368c0265cf2Skettenis 		return (ENOMEM);
369c0265cf2Skettenis 	}
370c0265cf2Skettenis 
371de121c55Skettenis 	sc->sc_mbox[0] = QLW_MBOX_INIT_REQ_QUEUE;
37251fb3575Skettenis 	sc->sc_mbox[1] = sc->sc_maxrequests;
373c0265cf2Skettenis 	qlw_mbox_putaddr(sc->sc_mbox, sc->sc_requests);
374c0265cf2Skettenis 	sc->sc_mbox[4] = 0;
375c0265cf2Skettenis 	if (qlw_mbox(sc, 0x00df, 0x0001)) {
376c0265cf2Skettenis 		printf("couldn't init request queue: %x\n", sc->sc_mbox[0]);
377c0265cf2Skettenis 		goto free_ccbs;
378c0265cf2Skettenis 	}
379c0265cf2Skettenis 
380de121c55Skettenis 	sc->sc_mbox[0] = QLW_MBOX_INIT_RSP_QUEUE;
38151fb3575Skettenis 	sc->sc_mbox[1] = sc->sc_maxresponses;
382c0265cf2Skettenis 	qlw_mbox_putaddr(sc->sc_mbox, sc->sc_responses);
383c0265cf2Skettenis 	sc->sc_mbox[5] = 0;
384c0265cf2Skettenis 	if (qlw_mbox(sc, 0x00ef, 0x0001)) {
385c0265cf2Skettenis 		printf("couldn't init response queue: %x\n", sc->sc_mbox[0]);
386c0265cf2Skettenis 		goto free_ccbs;
387c0265cf2Skettenis 	}
388c0265cf2Skettenis 
389c0265cf2Skettenis 	reset_delay = 0;
390c0265cf2Skettenis 	for (bus = 0; bus < sc->sc_numbusses; bus++) {
391c0265cf2Skettenis 		sc->sc_mbox[0] = QLW_MBOX_BUS_RESET;
392c0265cf2Skettenis 		sc->sc_mbox[1] = sc->sc_reset_delay[bus];
393c0265cf2Skettenis 		sc->sc_mbox[2] = bus;
394c0265cf2Skettenis 		if (qlw_mbox(sc, 0x0007, 0x0001)) {
395c0265cf2Skettenis 			printf("couldn't reset bus: %x\n", sc->sc_mbox[0]);
396c0265cf2Skettenis 			goto free_ccbs;
397c0265cf2Skettenis 		}
398c0265cf2Skettenis 		sc->sc_marker_required[bus] = 1;
39977bba8c0Skettenis 		sc->sc_update_required[bus] = 0xffff;
400c0265cf2Skettenis 
401c0265cf2Skettenis 		if (sc->sc_reset_delay[bus] > reset_delay)
402c0265cf2Skettenis 			reset_delay = sc->sc_reset_delay[bus];
403c0265cf2Skettenis 	}
404c0265cf2Skettenis 
405c0265cf2Skettenis 	/* wait for the busses to settle */
406c0265cf2Skettenis 	delay(reset_delay * 1000000);
407c0265cf2Skettenis 
408ead808c4Skrw 	saa.saa_adapter = &qlw_switch;
409ead808c4Skrw 	saa.saa_adapter_softc = sc;
410ead808c4Skrw 	saa.saa_adapter_buswidth = QLW_MAX_TARGETS;
411ead808c4Skrw 	saa.saa_luns = QLW_MAX_LUNS;
412e5eae15dSkrw 	saa.saa_pool = &sc->sc_iopool;
413e5eae15dSkrw 	saa.saa_quirks = saa.saa_flags = 0;
414e5eae15dSkrw 	saa.saa_wwpn = saa.saa_wwnn = 0;
415c0265cf2Skettenis 	for (bus = 0; bus < sc->sc_numbusses; bus++) {
416ead808c4Skrw 		saa.saa_adapter_target = sc->sc_initiator[bus];
417e5eae15dSkrw 		saa.saa_openings = sc->sc_max_queue_depth[bus];
418c0265cf2Skettenis 
419c0265cf2Skettenis 		sc->sc_scsibus[bus] = (struct scsibus_softc *)
420c0265cf2Skettenis 		    config_found(&sc->sc_dev, &saa, scsiprint);
421c0265cf2Skettenis 
422c0265cf2Skettenis 		qlw_update_bus(sc, bus);
423c0265cf2Skettenis 	}
424c0265cf2Skettenis 
425c0265cf2Skettenis 	sc->sc_running = 1;
426c0265cf2Skettenis 	return(0);
427c0265cf2Skettenis 
428c0265cf2Skettenis free_ccbs:
429c0265cf2Skettenis 	qlw_free_ccbs(sc);
430c0265cf2Skettenis 	return (ENXIO);
431c0265cf2Skettenis }
432c0265cf2Skettenis 
433c0265cf2Skettenis int
qlw_detach(struct qlw_softc * sc,int flags)434c0265cf2Skettenis qlw_detach(struct qlw_softc *sc, int flags)
435c0265cf2Skettenis {
436c0265cf2Skettenis 	return (0);
437c0265cf2Skettenis }
438c0265cf2Skettenis 
439c0265cf2Skettenis int
qlw_config_bus(struct qlw_softc * sc,int bus)440c0265cf2Skettenis qlw_config_bus(struct qlw_softc *sc, int bus)
441c0265cf2Skettenis {
442c0265cf2Skettenis 	int target, err;
443c0265cf2Skettenis 
444c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_INITIATOR_ID;
44542de16feSkettenis 	sc->sc_mbox[1] = (bus << 7) | sc->sc_initiator[bus];
446c0265cf2Skettenis 
447c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0003, 0x0001)) {
448c0265cf2Skettenis 		printf("couldn't set initiator id: %x\n", sc->sc_mbox[0]);
449c0265cf2Skettenis 		return (ENXIO);
450c0265cf2Skettenis 	}
451c0265cf2Skettenis 
452c0265cf2Skettenis 	for (target = 0; target < QLW_MAX_TARGETS; target++) {
453c0265cf2Skettenis 		err = qlw_config_target(sc, bus, target);
454c0265cf2Skettenis 		if (err)
455c0265cf2Skettenis 			return (err);
456c0265cf2Skettenis 	}
457c0265cf2Skettenis 
458c0265cf2Skettenis 	return (0);
459c0265cf2Skettenis }
460c0265cf2Skettenis 
461c0265cf2Skettenis int
qlw_config_target(struct qlw_softc * sc,int bus,int target)462c0265cf2Skettenis qlw_config_target(struct qlw_softc *sc, int bus, int target)
463c0265cf2Skettenis {
464c0265cf2Skettenis 	int lun;
465c0265cf2Skettenis 
466c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_TARGET_PARAMETERS;
467c0265cf2Skettenis 	sc->sc_mbox[1] = (((bus << 7) | target) << 8);
468c0265cf2Skettenis 	sc->sc_mbox[2] = sc->sc_target[bus][target].qt_params;
469c0265cf2Skettenis 	sc->sc_mbox[2] &= QLW_TARGET_SAFE;
470c0265cf2Skettenis 	sc->sc_mbox[2] |= QLW_TARGET_NARROW | QLW_TARGET_ASYNC;
471c0265cf2Skettenis 	sc->sc_mbox[3] = 0;
472c0265cf2Skettenis 
473c0265cf2Skettenis 	if (qlw_mbox(sc, 0x000f, 0x0001)) {
474c0265cf2Skettenis 		printf("couldn't set target parameters: %x\n", sc->sc_mbox[0]);
475c0265cf2Skettenis 		return (ENXIO);
476c0265cf2Skettenis 	}
477c0265cf2Skettenis 
478c0265cf2Skettenis 	for (lun = 0; lun < QLW_MAX_LUNS; lun++) {
479c0265cf2Skettenis 		sc->sc_mbox[0] = QLW_MBOX_SET_DEVICE_QUEUE;
480c0265cf2Skettenis 		sc->sc_mbox[1] = (((bus << 7) | target) << 8) | lun;
481c0265cf2Skettenis 		sc->sc_mbox[2] = sc->sc_max_queue_depth[bus];
482c0265cf2Skettenis 		sc->sc_mbox[3] = sc->sc_target[bus][target].qt_exec_throttle;
483c0265cf2Skettenis 		if (qlw_mbox(sc, 0x000f, 0x0001)) {
484c0265cf2Skettenis 			printf("couldn't set lun parameters: %x\n",
485c0265cf2Skettenis 			    sc->sc_mbox[0]);
486c0265cf2Skettenis 			return (ENXIO);
487c0265cf2Skettenis 		}
488c0265cf2Skettenis 	}
489c0265cf2Skettenis 
490c0265cf2Skettenis 	return (0);
491c0265cf2Skettenis }
492c0265cf2Skettenis 
493c0265cf2Skettenis void
qlw_update_bus(struct qlw_softc * sc,int bus)494c0265cf2Skettenis qlw_update_bus(struct qlw_softc *sc, int bus)
495c0265cf2Skettenis {
496c0265cf2Skettenis 	int target;
497c0265cf2Skettenis 
498c0265cf2Skettenis 	for (target = 0; target < QLW_MAX_TARGETS; target++)
499c0265cf2Skettenis 		qlw_update_target(sc, bus, target);
500c0265cf2Skettenis }
501c0265cf2Skettenis 
502c0265cf2Skettenis void
qlw_update_target(struct qlw_softc * sc,int bus,int target)503c0265cf2Skettenis qlw_update_target(struct qlw_softc *sc, int bus, int target)
504c0265cf2Skettenis {
505c0265cf2Skettenis 	struct scsi_link *link;
506c0265cf2Skettenis 	int lun;
507c0265cf2Skettenis 
50877bba8c0Skettenis 	if ((sc->sc_update_required[bus] & (1 << target)) == 0)
50977bba8c0Skettenis 		return;
51077bba8c0Skettenis 	atomic_clearbits_int(&sc->sc_update_required[bus], (1 << target));
51177bba8c0Skettenis 
512c0265cf2Skettenis 	link = scsi_get_link(sc->sc_scsibus[bus], target, 0);
513c0265cf2Skettenis 	if (link == NULL)
514c0265cf2Skettenis 		return;
515c0265cf2Skettenis 
516c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_SET_TARGET_PARAMETERS;
517c0265cf2Skettenis 	sc->sc_mbox[1] = (((bus << 7) | target) << 8);
518c0265cf2Skettenis 	sc->sc_mbox[2] = sc->sc_target[bus][target].qt_params;
519c0265cf2Skettenis 	sc->sc_mbox[2] |= QLW_TARGET_RENEG;
520c0265cf2Skettenis 	sc->sc_mbox[2] &= ~QLW_TARGET_QFRZ;
521d1e71aa9Skettenis 	if (link->quirks & SDEV_NOSYNC)
522c0265cf2Skettenis 		sc->sc_mbox[2] &= ~QLW_TARGET_SYNC;
523d1e71aa9Skettenis 	if (link->quirks & SDEV_NOWIDE)
524c0265cf2Skettenis 		sc->sc_mbox[2] &= ~QLW_TARGET_WIDE;
525d1e71aa9Skettenis 	if (link->quirks & SDEV_NOTAGS)
526c0265cf2Skettenis 		sc->sc_mbox[2] &= ~QLW_TARGET_TAGS;
527c0265cf2Skettenis 
528c0265cf2Skettenis 	sc->sc_mbox[3] = sc->sc_target[bus][target].qt_sync_period;
529c0265cf2Skettenis 	sc->sc_mbox[3] |= (sc->sc_target[bus][target].qt_sync_offset << 8);
530c0265cf2Skettenis 
531c0265cf2Skettenis 	if (qlw_mbox(sc, 0x000f, 0x0001)) {
532c0265cf2Skettenis 		printf("couldn't set target parameters: %x\n", sc->sc_mbox[0]);
533c0265cf2Skettenis 		return;
534c0265cf2Skettenis 	}
535c0265cf2Skettenis 
536c0265cf2Skettenis 	/* XXX do PPR detection */
537c0265cf2Skettenis 
538c0265cf2Skettenis 	for (lun = 0; lun < QLW_MAX_LUNS; lun++) {
539c0265cf2Skettenis 		sc->sc_mbox[0] = QLW_MBOX_SET_DEVICE_QUEUE;
540c0265cf2Skettenis 		sc->sc_mbox[1] = (((bus << 7) | target) << 8) | lun;
541c0265cf2Skettenis 		sc->sc_mbox[2] = sc->sc_max_queue_depth[bus];
542c0265cf2Skettenis 		sc->sc_mbox[3] = sc->sc_target[bus][target].qt_exec_throttle;
543c0265cf2Skettenis 		if (qlw_mbox(sc, 0x000f, 0x0001)) {
544c0265cf2Skettenis 			printf("couldn't set lun parameters: %x\n",
545c0265cf2Skettenis 			    sc->sc_mbox[0]);
546c0265cf2Skettenis 			return;
547c0265cf2Skettenis 		}
548c0265cf2Skettenis 	}
549c0265cf2Skettenis }
550c0265cf2Skettenis 
55177bba8c0Skettenis void
qlw_update_task(void * xsc)552e4195480Sdlg qlw_update_task(void *xsc)
55377bba8c0Skettenis {
554e4195480Sdlg 	struct qlw_softc *sc = xsc;
55577bba8c0Skettenis 	int bus;
55677bba8c0Skettenis 
55777bba8c0Skettenis 	for (bus = 0; bus < sc->sc_numbusses; bus++)
55877bba8c0Skettenis 		qlw_update_bus(sc, bus);
55977bba8c0Skettenis }
56077bba8c0Skettenis 
561c0265cf2Skettenis struct qlw_ccb *
qlw_handle_resp(struct qlw_softc * sc,u_int16_t id)562c0265cf2Skettenis qlw_handle_resp(struct qlw_softc *sc, u_int16_t id)
563c0265cf2Skettenis {
564c0265cf2Skettenis 	struct qlw_ccb *ccb;
565de2fb981Skettenis 	struct qlw_iocb_hdr *hdr;
566de2fb981Skettenis 	struct qlw_iocb_status *status;
567c0265cf2Skettenis 	struct scsi_xfer *xs;
568c0265cf2Skettenis 	u_int32_t handle;
569de2fb981Skettenis 	int entry_type;
570de2fb981Skettenis 	int flags;
57177bba8c0Skettenis 	int bus;
572c0265cf2Skettenis 
573c0265cf2Skettenis 	ccb = NULL;
574de2fb981Skettenis 	hdr = QLW_DMA_KVA(sc->sc_responses) + (id * QLW_QUEUE_ENTRY_SIZE);
575c0265cf2Skettenis 
576c0265cf2Skettenis 	bus_dmamap_sync(sc->sc_dmat,
577c0265cf2Skettenis 	    QLW_DMA_MAP(sc->sc_responses), id * QLW_QUEUE_ENTRY_SIZE,
578c0265cf2Skettenis 	    QLW_QUEUE_ENTRY_SIZE, BUS_DMASYNC_POSTREAD);
579c0265cf2Skettenis 
580de2fb981Skettenis 	qlw_get_header(sc, hdr, &entry_type, &flags);
581de2fb981Skettenis 	switch (entry_type) {
582c0265cf2Skettenis 	case QLW_IOCB_STATUS:
583de2fb981Skettenis 		status = (struct qlw_iocb_status *)hdr;
584de2fb981Skettenis 		handle = qlw_swap32(sc, status->handle);
58592d24382Skettenis 		if (handle > sc->sc_maxccbs) {
586c0265cf2Skettenis 			panic("bad completed command handle: %d (> %d)",
58792d24382Skettenis 			    handle, sc->sc_maxccbs);
588c0265cf2Skettenis 		}
589c0265cf2Skettenis 
590c0265cf2Skettenis 		ccb = &sc->sc_ccbs[handle];
591c0265cf2Skettenis 		xs = ccb->ccb_xs;
592c0265cf2Skettenis 		if (xs == NULL) {
593c0265cf2Skettenis 			DPRINTF(QLW_D_INTR, "%s: got status for inactive"
594c0265cf2Skettenis 			    " ccb %d\n", DEVNAME(sc), handle);
595a0291dabSkettenis 			qlw_dump_iocb(sc, hdr, QLW_D_INTR);
596c0265cf2Skettenis 			ccb = NULL;
597c0265cf2Skettenis 			break;
598c0265cf2Skettenis 		}
599c0265cf2Skettenis 		if (xs->io != ccb) {
600c0265cf2Skettenis 			panic("completed command handle doesn't match xs "
601c0265cf2Skettenis 			    "(handle %d, ccb %p, xs->io %p)", handle, ccb,
602c0265cf2Skettenis 			    xs->io);
603c0265cf2Skettenis 		}
604c0265cf2Skettenis 
605c0265cf2Skettenis 		if (xs->datalen > 0) {
606c0265cf2Skettenis 			bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0,
607c0265cf2Skettenis 			    ccb->ccb_dmamap->dm_mapsize,
608c0265cf2Skettenis 			    (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
609c0265cf2Skettenis 			    BUS_DMASYNC_POSTWRITE);
610c0265cf2Skettenis 			bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap);
611c0265cf2Skettenis 		}
612c0265cf2Skettenis 
61377bba8c0Skettenis 		bus = qlw_xs_bus(sc, xs);
614de2fb981Skettenis 		xs->status = qlw_swap16(sc, status->scsi_status);
615de2fb981Skettenis 		switch (qlw_swap16(sc, status->completion)) {
616c0265cf2Skettenis 		case QLW_IOCB_STATUS_COMPLETE:
617de2fb981Skettenis 			if (qlw_swap16(sc, status->scsi_status) &
618c0265cf2Skettenis 			    QLW_SCSI_STATUS_SENSE_VALID) {
619c0265cf2Skettenis 				memcpy(&xs->sense, status->sense_data,
620c0265cf2Skettenis 				    sizeof(xs->sense));
621c0265cf2Skettenis 				xs->error = XS_SENSE;
622c0265cf2Skettenis 			} else {
623c0265cf2Skettenis 				xs->error = XS_NOERROR;
624c0265cf2Skettenis 			}
625c0265cf2Skettenis 			xs->resid = 0;
626c0265cf2Skettenis 			break;
627c0265cf2Skettenis 
628c0265cf2Skettenis 		case QLW_IOCB_STATUS_INCOMPLETE:
629de2fb981Skettenis 			if (flags & QLW_STATE_GOT_TARGET) {
630c0265cf2Skettenis 				xs->error = XS_DRIVER_STUFFUP;
631c0265cf2Skettenis 			} else {
632c0265cf2Skettenis 				xs->error = XS_SELTIMEOUT;
633c0265cf2Skettenis 			}
634c0265cf2Skettenis 			break;
635c0265cf2Skettenis 
636c0265cf2Skettenis 		case QLW_IOCB_STATUS_DMA_ERROR:
637c0265cf2Skettenis 			DPRINTF(QLW_D_INTR, "%s: dma error\n", DEVNAME(sc));
638c0265cf2Skettenis 			/* set resid apparently? */
639c0265cf2Skettenis 			break;
640c0265cf2Skettenis 
641c0265cf2Skettenis 		case QLW_IOCB_STATUS_RESET:
642a0291dabSkettenis 			DPRINTF(QLW_D_INTR, "%s: reset destroyed command\n",
643c0265cf2Skettenis 			    DEVNAME(sc));
64477bba8c0Skettenis 			sc->sc_marker_required[bus] = 1;
645c0265cf2Skettenis 			xs->error = XS_RESET;
646c0265cf2Skettenis 			break;
647c0265cf2Skettenis 
648c0265cf2Skettenis 		case QLW_IOCB_STATUS_ABORTED:
649a0291dabSkettenis 			DPRINTF(QLW_D_INTR, "%s: aborted\n", DEVNAME(sc));
65077bba8c0Skettenis 			sc->sc_marker_required[bus] = 1;
651c0265cf2Skettenis 			xs->error = XS_DRIVER_STUFFUP;
652c0265cf2Skettenis 			break;
653c0265cf2Skettenis 
654c0265cf2Skettenis 		case QLW_IOCB_STATUS_TIMEOUT:
655a0291dabSkettenis 			DPRINTF(QLW_D_INTR, "%s: command timed out\n",
656c0265cf2Skettenis 			    DEVNAME(sc));
657c0265cf2Skettenis 			xs->error = XS_TIMEOUT;
658c0265cf2Skettenis 			break;
659c0265cf2Skettenis 
660c0265cf2Skettenis 		case QLW_IOCB_STATUS_DATA_OVERRUN:
661c0265cf2Skettenis 		case QLW_IOCB_STATUS_DATA_UNDERRUN:
662de2fb981Skettenis 			xs->resid = qlw_swap32(sc, status->resid);
663c0265cf2Skettenis 			xs->error = XS_NOERROR;
664c0265cf2Skettenis 			break;
665c0265cf2Skettenis 
666c0265cf2Skettenis 		case QLW_IOCB_STATUS_QUEUE_FULL:
667a0291dabSkettenis 			DPRINTF(QLW_D_INTR, "%s: queue full\n", DEVNAME(sc));
668c0265cf2Skettenis 			xs->error = XS_BUSY;
669c0265cf2Skettenis 			break;
670c0265cf2Skettenis 
67177bba8c0Skettenis 		case QLW_IOCB_STATUS_WIDE_FAILED:
672a0291dabSkettenis 			DPRINTF(QLW_D_INTR, "%s: wide failed\n", DEVNAME(sc));
673f226851bSkrw 			xs->sc_link->quirks |= SDEV_NOWIDE;
67477bba8c0Skettenis 			atomic_setbits_int(&sc->sc_update_required[bus],
67577bba8c0Skettenis 			    1 << xs->sc_link->target);
67677bba8c0Skettenis 			task_add(systq, &sc->sc_update_task);
677de2fb981Skettenis 			xs->resid = qlw_swap32(sc, status->resid);
67877bba8c0Skettenis 			xs->error = XS_NOERROR;
67977bba8c0Skettenis 			break;
68077bba8c0Skettenis 
68177bba8c0Skettenis 		case QLW_IOCB_STATUS_SYNCXFER_FAILED:
682a0291dabSkettenis 			DPRINTF(QLW_D_INTR, "%s: sync failed\n", DEVNAME(sc));
683f226851bSkrw 			xs->sc_link->quirks |= SDEV_NOSYNC;
68477bba8c0Skettenis 			atomic_setbits_int(&sc->sc_update_required[bus],
68577bba8c0Skettenis 			    1 << xs->sc_link->target);
68677bba8c0Skettenis 			task_add(systq, &sc->sc_update_task);
687de2fb981Skettenis 			xs->resid = qlw_swap32(sc, status->resid);
68877bba8c0Skettenis 			xs->error = XS_NOERROR;
68977bba8c0Skettenis 			break;
69077bba8c0Skettenis 
691c0265cf2Skettenis 		default:
692c0265cf2Skettenis 			DPRINTF(QLW_D_INTR, "%s: unexpected completion"
693c0265cf2Skettenis 			    " status %x\n", DEVNAME(sc),
694de2fb981Skettenis 			    qlw_swap16(sc, status->completion));
695a0291dabSkettenis 			qlw_dump_iocb(sc, hdr, QLW_D_INTR);
696c0265cf2Skettenis 			xs->error = XS_DRIVER_STUFFUP;
697c0265cf2Skettenis 			break;
698c0265cf2Skettenis 		}
699c0265cf2Skettenis 		break;
700c0265cf2Skettenis 
701c0265cf2Skettenis 	default:
702c0265cf2Skettenis 		DPRINTF(QLW_D_INTR, "%s: unexpected response entry type %x\n",
703de2fb981Skettenis 		    DEVNAME(sc), entry_type);
704a0291dabSkettenis 		qlw_dump_iocb(sc, hdr, QLW_D_INTR);
705c0265cf2Skettenis 		break;
706c0265cf2Skettenis 	}
707c0265cf2Skettenis 
708c0265cf2Skettenis 	return (ccb);
709c0265cf2Skettenis }
710c0265cf2Skettenis 
711c0265cf2Skettenis void
qlw_handle_intr(struct qlw_softc * sc,u_int16_t isr,u_int16_t info)712c0265cf2Skettenis qlw_handle_intr(struct qlw_softc *sc, u_int16_t isr, u_int16_t info)
713c0265cf2Skettenis {
714c0265cf2Skettenis 	int i;
715c0265cf2Skettenis 	u_int16_t rspin;
716c0265cf2Skettenis 	struct qlw_ccb *ccb;
717c0265cf2Skettenis 
718c0265cf2Skettenis 	switch (isr) {
719c0265cf2Skettenis 	case QLW_INT_TYPE_ASYNC:
720c0265cf2Skettenis 		qlw_async(sc, info);
721f9dd2fdbSkettenis 		qlw_clear_isr(sc, isr);
722c0265cf2Skettenis 		break;
723c0265cf2Skettenis 
724c0265cf2Skettenis 	case QLW_INT_TYPE_IO:
725f9dd2fdbSkettenis 		qlw_clear_isr(sc, isr);
726c0265cf2Skettenis 		rspin = qlw_queue_read(sc, QLW_RESP_IN);
727c0265cf2Skettenis 		if (rspin == sc->sc_last_resp_id) {
728c0265cf2Skettenis 			/* seems to happen a lot on 2200s when mbox commands
729c0265cf2Skettenis 			 * complete but it doesn't want to give us the register
730c0265cf2Skettenis 			 * semaphore, or something.
731c0265cf2Skettenis 			 *
732c0265cf2Skettenis 			 * if we're waiting on a mailbox command, don't ack
733c0265cf2Skettenis 			 * the interrupt yet.
734c0265cf2Skettenis 			 */
735c0265cf2Skettenis 			if (sc->sc_mbox_pending) {
736c0265cf2Skettenis 				DPRINTF(QLW_D_MBOX, "%s: ignoring premature"
737c0265cf2Skettenis 				    " mbox int\n", DEVNAME(sc));
738c0265cf2Skettenis 				return;
739c0265cf2Skettenis 			}
740c0265cf2Skettenis 
741c0265cf2Skettenis 			break;
742c0265cf2Skettenis 		}
743c0265cf2Skettenis 
744c0265cf2Skettenis 		if (sc->sc_responses == NULL)
745c0265cf2Skettenis 			break;
746c0265cf2Skettenis 
747c0265cf2Skettenis 		DPRINTF(QLW_D_IO, "%s: response queue %x=>%x\n",
748c0265cf2Skettenis 		    DEVNAME(sc), sc->sc_last_resp_id, rspin);
749c0265cf2Skettenis 
750c0265cf2Skettenis 		do {
751c0265cf2Skettenis 			ccb = qlw_handle_resp(sc, sc->sc_last_resp_id);
752c0265cf2Skettenis 			if (ccb)
753c0265cf2Skettenis 				scsi_done(ccb->ccb_xs);
754c0265cf2Skettenis 
755c0265cf2Skettenis 			sc->sc_last_resp_id++;
75651fb3575Skettenis 			sc->sc_last_resp_id %= sc->sc_maxresponses;
757c0265cf2Skettenis 		} while (sc->sc_last_resp_id != rspin);
758c0265cf2Skettenis 
759c0265cf2Skettenis 		qlw_queue_write(sc, QLW_RESP_OUT, rspin);
760c0265cf2Skettenis 		break;
761c0265cf2Skettenis 
762c0265cf2Skettenis 	case QLW_INT_TYPE_MBOX:
763c0265cf2Skettenis 		if (sc->sc_mbox_pending) {
764c0265cf2Skettenis 			if (info == QLW_MBOX_COMPLETE) {
765c0265cf2Skettenis 				for (i = 1; i < nitems(sc->sc_mbox); i++) {
766c0265cf2Skettenis 					sc->sc_mbox[i] = qlw_read_mbox(sc, i);
767c0265cf2Skettenis 				}
768c0265cf2Skettenis 			} else {
769c0265cf2Skettenis 				sc->sc_mbox[0] = info;
770c0265cf2Skettenis 			}
771c0265cf2Skettenis 			wakeup(sc->sc_mbox);
772c0265cf2Skettenis 		} else {
773c0265cf2Skettenis 			DPRINTF(QLW_D_MBOX, "%s: unexpected mbox interrupt:"
774c0265cf2Skettenis 			    " %x\n", DEVNAME(sc), info);
775c0265cf2Skettenis 		}
776f9dd2fdbSkettenis 		qlw_clear_isr(sc, isr);
777c0265cf2Skettenis 		break;
778c0265cf2Skettenis 
779c0265cf2Skettenis 	default:
780c0265cf2Skettenis 		/* maybe log something? */
781c0265cf2Skettenis 		break;
782c0265cf2Skettenis 	}
783c0265cf2Skettenis }
784c0265cf2Skettenis 
785c0265cf2Skettenis int
qlw_intr(void * xsc)786c0265cf2Skettenis qlw_intr(void *xsc)
787c0265cf2Skettenis {
788c0265cf2Skettenis 	struct qlw_softc *sc = xsc;
789c0265cf2Skettenis 	u_int16_t isr;
790c0265cf2Skettenis 	u_int16_t info;
791c0265cf2Skettenis 
792c0265cf2Skettenis 	if (qlw_read_isr(sc, &isr, &info) == 0)
793c0265cf2Skettenis 		return (0);
794c0265cf2Skettenis 
795c0265cf2Skettenis 	qlw_handle_intr(sc, isr, info);
796c0265cf2Skettenis 	return (1);
797c0265cf2Skettenis }
798c0265cf2Skettenis 
799c0265cf2Skettenis void
qlw_scsi_cmd(struct scsi_xfer * xs)800c0265cf2Skettenis qlw_scsi_cmd(struct scsi_xfer *xs)
801c0265cf2Skettenis {
802c0265cf2Skettenis 	struct scsi_link	*link = xs->sc_link;
8030b29cb40Skrw 	struct qlw_softc	*sc = link->bus->sb_adapter_softc;
804c0265cf2Skettenis 	struct qlw_ccb		*ccb;
805c0265cf2Skettenis 	struct qlw_iocb_req0	*iocb;
806c0265cf2Skettenis 	struct qlw_ccb_list	list;
807399e7f01Skettenis 	u_int16_t		req, rspin;
808399e7f01Skettenis 	int			offset, error, done;
809c0265cf2Skettenis 	bus_dmamap_t		dmap;
810c0265cf2Skettenis 	int			bus;
811c0265cf2Skettenis 	int			seg;
812c0265cf2Skettenis 
813de2fb981Skettenis 	if (xs->cmdlen > sizeof(iocb->cdb)) {
814c0265cf2Skettenis 		DPRINTF(QLW_D_IO, "%s: cdb too big (%d)\n", DEVNAME(sc),
815c0265cf2Skettenis 		    xs->cmdlen);
816c0265cf2Skettenis 		memset(&xs->sense, 0, sizeof(xs->sense));
817c0265cf2Skettenis 		xs->sense.error_code = SSD_ERRCODE_VALID | SSD_ERRCODE_CURRENT;
818c0265cf2Skettenis 		xs->sense.flags = SKEY_ILLEGAL_REQUEST;
819c0265cf2Skettenis 		xs->sense.add_sense_code = 0x20;
820c0265cf2Skettenis 		xs->error = XS_SENSE;
821c0265cf2Skettenis 		scsi_done(xs);
822c0265cf2Skettenis 		return;
823c0265cf2Skettenis 	}
824c0265cf2Skettenis 
825c0265cf2Skettenis 	ccb = xs->io;
826c0265cf2Skettenis 	dmap = ccb->ccb_dmamap;
827c0265cf2Skettenis 	if (xs->datalen > 0) {
828c0265cf2Skettenis 		error = bus_dmamap_load(sc->sc_dmat, dmap, xs->data,
829c0265cf2Skettenis 		    xs->datalen, NULL, (xs->flags & SCSI_NOSLEEP) ?
830c0265cf2Skettenis 		    BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
831c0265cf2Skettenis 		if (error) {
832c0265cf2Skettenis 			xs->error = XS_DRIVER_STUFFUP;
833c0265cf2Skettenis 			scsi_done(xs);
834c0265cf2Skettenis 			return;
835c0265cf2Skettenis 		}
836c0265cf2Skettenis 
837c0265cf2Skettenis 		bus_dmamap_sync(sc->sc_dmat, dmap, 0,
838c0265cf2Skettenis 		    dmap->dm_mapsize,
839c0265cf2Skettenis 		    (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
840c0265cf2Skettenis 		    BUS_DMASYNC_PREWRITE);
841c0265cf2Skettenis 	}
842c0265cf2Skettenis 
843c0265cf2Skettenis 	mtx_enter(&sc->sc_queue_mtx);
844c0265cf2Skettenis 
845c0265cf2Skettenis 	/* put in a sync marker if required */
846c0265cf2Skettenis 	bus = qlw_xs_bus(sc, xs);
847c0265cf2Skettenis 	if (sc->sc_marker_required[bus]) {
848c0265cf2Skettenis 		req = sc->sc_next_req_id++;
84951fb3575Skettenis 		if (sc->sc_next_req_id == sc->sc_maxrequests)
850c0265cf2Skettenis 			sc->sc_next_req_id = 0;
851c0265cf2Skettenis 
852c0265cf2Skettenis 		DPRINTF(QLW_D_IO, "%s: writing marker at request %d\n",
853c0265cf2Skettenis 		    DEVNAME(sc), req);
854c0265cf2Skettenis 		offset = (req * QLW_QUEUE_ENTRY_SIZE);
855c0265cf2Skettenis 		iocb = QLW_DMA_KVA(sc->sc_requests) + offset;
856c0265cf2Skettenis 		bus_dmamap_sync(sc->sc_dmat, QLW_DMA_MAP(sc->sc_requests),
857c0265cf2Skettenis 		    offset, QLW_QUEUE_ENTRY_SIZE, BUS_DMASYNC_POSTWRITE);
858c0265cf2Skettenis 		qlw_put_marker(sc, bus, iocb);
859c0265cf2Skettenis 		bus_dmamap_sync(sc->sc_dmat, QLW_DMA_MAP(sc->sc_requests),
860c0265cf2Skettenis 		    offset, QLW_QUEUE_ENTRY_SIZE, BUS_DMASYNC_PREWRITE);
861c0265cf2Skettenis 		qlw_queue_write(sc, QLW_REQ_IN, sc->sc_next_req_id);
862c0265cf2Skettenis 		sc->sc_marker_required[bus] = 0;
863c0265cf2Skettenis 	}
864c0265cf2Skettenis 
865c0265cf2Skettenis 	req = sc->sc_next_req_id++;
86651fb3575Skettenis 	if (sc->sc_next_req_id == sc->sc_maxrequests)
867c0265cf2Skettenis 		sc->sc_next_req_id = 0;
868c0265cf2Skettenis 
869c0265cf2Skettenis 	offset = (req * QLW_QUEUE_ENTRY_SIZE);
870c0265cf2Skettenis 	iocb = QLW_DMA_KVA(sc->sc_requests) + offset;
871c0265cf2Skettenis 	bus_dmamap_sync(sc->sc_dmat, QLW_DMA_MAP(sc->sc_requests), offset,
872c0265cf2Skettenis 	    QLW_QUEUE_ENTRY_SIZE, BUS_DMASYNC_POSTWRITE);
873c0265cf2Skettenis 
874c0265cf2Skettenis 	ccb->ccb_xs = xs;
875c0265cf2Skettenis 
876c0265cf2Skettenis 	DPRINTF(QLW_D_IO, "%s: writing cmd at request %d\n", DEVNAME(sc), req);
877c0265cf2Skettenis 	qlw_put_cmd(sc, iocb, xs, ccb);
878c0265cf2Skettenis 	seg = QLW_IOCB_SEGS_PER_CMD;
879c0265cf2Skettenis 
880c0265cf2Skettenis 	bus_dmamap_sync(sc->sc_dmat, QLW_DMA_MAP(sc->sc_requests), offset,
881c0265cf2Skettenis 	    QLW_QUEUE_ENTRY_SIZE, BUS_DMASYNC_PREWRITE);
882c0265cf2Skettenis 
883c0265cf2Skettenis 	while (seg < ccb->ccb_dmamap->dm_nsegs) {
884c0265cf2Skettenis 		req = sc->sc_next_req_id++;
88551fb3575Skettenis 		if (sc->sc_next_req_id == sc->sc_maxrequests)
886c0265cf2Skettenis 			sc->sc_next_req_id = 0;
887c0265cf2Skettenis 
888c0265cf2Skettenis 		offset = (req * QLW_QUEUE_ENTRY_SIZE);
889c0265cf2Skettenis 		iocb = QLW_DMA_KVA(sc->sc_requests) + offset;
890c0265cf2Skettenis 		bus_dmamap_sync(sc->sc_dmat, QLW_DMA_MAP(sc->sc_requests), offset,
891c0265cf2Skettenis 		    QLW_QUEUE_ENTRY_SIZE, BUS_DMASYNC_POSTWRITE);
892c0265cf2Skettenis 
893c0265cf2Skettenis 		DPRINTF(QLW_D_IO, "%s: writing cont at request %d\n", DEVNAME(sc), req);
894c0265cf2Skettenis 		qlw_put_cont(sc, iocb, xs, ccb, seg);
895c0265cf2Skettenis 		seg += QLW_IOCB_SEGS_PER_CONT;
896c0265cf2Skettenis 
897c0265cf2Skettenis 		bus_dmamap_sync(sc->sc_dmat, QLW_DMA_MAP(sc->sc_requests), offset,
898c0265cf2Skettenis 		    QLW_QUEUE_ENTRY_SIZE, BUS_DMASYNC_PREWRITE);
899c0265cf2Skettenis 	}
900c0265cf2Skettenis 
901c0265cf2Skettenis 	qlw_queue_write(sc, QLW_REQ_IN, sc->sc_next_req_id);
902c0265cf2Skettenis 
903c0265cf2Skettenis 	if (!ISSET(xs->flags, SCSI_POLL)) {
904c0265cf2Skettenis 		mtx_leave(&sc->sc_queue_mtx);
905c0265cf2Skettenis 		return;
906c0265cf2Skettenis 	}
907c0265cf2Skettenis 
908399e7f01Skettenis 	done = 0;
909c0265cf2Skettenis 	SIMPLEQ_INIT(&list);
910c0265cf2Skettenis 	do {
911c0265cf2Skettenis 		u_int16_t isr, info;
912c0265cf2Skettenis 
913c0265cf2Skettenis 		delay(100);
914c0265cf2Skettenis 
915c0265cf2Skettenis 		if (qlw_read_isr(sc, &isr, &info) == 0) {
916c0265cf2Skettenis 			continue;
917c0265cf2Skettenis 		}
918c0265cf2Skettenis 
919c0265cf2Skettenis 		if (isr != QLW_INT_TYPE_IO) {
920c0265cf2Skettenis 			qlw_handle_intr(sc, isr, info);
921c0265cf2Skettenis 			continue;
922c0265cf2Skettenis 		}
923c0265cf2Skettenis 
9245d210cb9Skettenis 		qlw_clear_isr(sc, isr);
9255d210cb9Skettenis 
926c0265cf2Skettenis 		rspin = qlw_queue_read(sc, QLW_RESP_IN);
927399e7f01Skettenis 		while (rspin != sc->sc_last_resp_id) {
928c0265cf2Skettenis 			ccb = qlw_handle_resp(sc, sc->sc_last_resp_id);
929c0265cf2Skettenis 
930c0265cf2Skettenis 			sc->sc_last_resp_id++;
93151fb3575Skettenis 			if (sc->sc_last_resp_id == sc->sc_maxresponses)
932c0265cf2Skettenis 				sc->sc_last_resp_id = 0;
933c0265cf2Skettenis 
934399e7f01Skettenis 			if (ccb != NULL)
935399e7f01Skettenis 				SIMPLEQ_INSERT_TAIL(&list, ccb, ccb_link);
936399e7f01Skettenis 			if (ccb == xs->io)
937399e7f01Skettenis 				done = 1;
938c0265cf2Skettenis 		}
939399e7f01Skettenis 		qlw_queue_write(sc, QLW_RESP_OUT, rspin);
940399e7f01Skettenis 	} while (done == 0);
941c0265cf2Skettenis 
942399e7f01Skettenis 	mtx_leave(&sc->sc_queue_mtx);
943399e7f01Skettenis 
944399e7f01Skettenis 	while ((ccb = SIMPLEQ_FIRST(&list)) != NULL) {
945399e7f01Skettenis 		SIMPLEQ_REMOVE_HEAD(&list, ccb_link);
946399e7f01Skettenis 		scsi_done(ccb->ccb_xs);
947399e7f01Skettenis 	}
948c0265cf2Skettenis }
949c0265cf2Skettenis 
950c0265cf2Skettenis u_int16_t
qlw_read(struct qlw_softc * sc,bus_size_t offset)951c0265cf2Skettenis qlw_read(struct qlw_softc *sc, bus_size_t offset)
952c0265cf2Skettenis {
953c0265cf2Skettenis 	u_int16_t v;
954c0265cf2Skettenis 	v = bus_space_read_2(sc->sc_iot, sc->sc_ioh, offset);
955c0265cf2Skettenis 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, offset, 2,
956c0265cf2Skettenis 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
957c0265cf2Skettenis 	return (v);
958c0265cf2Skettenis }
959c0265cf2Skettenis 
960c0265cf2Skettenis void
qlw_write(struct qlw_softc * sc,bus_size_t offset,u_int16_t value)961c0265cf2Skettenis qlw_write(struct qlw_softc *sc, bus_size_t offset, u_int16_t value)
962c0265cf2Skettenis {
963c0265cf2Skettenis 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, offset, value);
964c0265cf2Skettenis 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, offset, 2,
965c0265cf2Skettenis 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
966c0265cf2Skettenis }
967c0265cf2Skettenis 
968c0265cf2Skettenis u_int16_t
qlw_read_mbox(struct qlw_softc * sc,int mbox)969c0265cf2Skettenis qlw_read_mbox(struct qlw_softc *sc, int mbox)
970c0265cf2Skettenis {
971c0265cf2Skettenis 	/* could range-check mboxes according to chip type? */
972e753b624Skettenis 	return (qlw_read(sc, sc->sc_mbox_base + (mbox * 2)));
973c0265cf2Skettenis }
974c0265cf2Skettenis 
975c0265cf2Skettenis void
qlw_write_mbox(struct qlw_softc * sc,int mbox,u_int16_t value)976c0265cf2Skettenis qlw_write_mbox(struct qlw_softc *sc, int mbox, u_int16_t value)
977c0265cf2Skettenis {
978e753b624Skettenis 	qlw_write(sc, sc->sc_mbox_base + (mbox * 2), value);
979c0265cf2Skettenis }
980c0265cf2Skettenis 
981c0265cf2Skettenis void
qlw_host_cmd(struct qlw_softc * sc,u_int16_t cmd)982c0265cf2Skettenis qlw_host_cmd(struct qlw_softc *sc, u_int16_t cmd)
983c0265cf2Skettenis {
984e753b624Skettenis 	qlw_write(sc, sc->sc_host_cmd_ctrl, cmd << QLW_HOST_CMD_SHIFT);
985c0265cf2Skettenis }
986c0265cf2Skettenis 
987c0265cf2Skettenis #define MBOX_COMMAND_TIMEOUT	4000
988c0265cf2Skettenis 
989c0265cf2Skettenis int
qlw_mbox(struct qlw_softc * sc,int maskin,int maskout)990c0265cf2Skettenis qlw_mbox(struct qlw_softc *sc, int maskin, int maskout)
991c0265cf2Skettenis {
992c0265cf2Skettenis 	int i;
993c0265cf2Skettenis 	int result = 0;
994c0265cf2Skettenis 	int rv;
995c0265cf2Skettenis 
996c0265cf2Skettenis 	sc->sc_mbox_pending = 1;
997c0265cf2Skettenis 	for (i = 0; i < nitems(sc->sc_mbox); i++) {
998c0265cf2Skettenis 		if (maskin & (1 << i)) {
999c0265cf2Skettenis 			qlw_write_mbox(sc, i, sc->sc_mbox[i]);
1000c0265cf2Skettenis 		}
1001c0265cf2Skettenis 	}
1002c0265cf2Skettenis 	qlw_host_cmd(sc, QLW_HOST_CMD_SET_HOST_INT);
1003c0265cf2Skettenis 
1004c0265cf2Skettenis 	if (sc->sc_running == 0) {
1005c0265cf2Skettenis 		for (i = 0; i < MBOX_COMMAND_TIMEOUT && result == 0; i++) {
1006c0265cf2Skettenis 			u_int16_t isr, info;
1007c0265cf2Skettenis 
1008c0265cf2Skettenis 			delay(100);
1009c0265cf2Skettenis 
1010c0265cf2Skettenis 			if (qlw_read_isr(sc, &isr, &info) == 0)
1011c0265cf2Skettenis 				continue;
1012c0265cf2Skettenis 
1013c0265cf2Skettenis 			switch (isr) {
1014c0265cf2Skettenis 			case QLW_INT_TYPE_MBOX:
1015c0265cf2Skettenis 				result = info;
1016c0265cf2Skettenis 				break;
1017c0265cf2Skettenis 
1018c0265cf2Skettenis 			default:
1019c0265cf2Skettenis 				qlw_handle_intr(sc, isr, info);
1020c0265cf2Skettenis 				break;
1021c0265cf2Skettenis 			}
1022c0265cf2Skettenis 		}
1023c0265cf2Skettenis 	} else {
102403604742Smpi 		tsleep_nsec(sc->sc_mbox, PRIBIO, "qlw_mbox", INFSLP);
1025c0265cf2Skettenis 		result = sc->sc_mbox[0];
1026c0265cf2Skettenis 	}
1027c0265cf2Skettenis 
1028c0265cf2Skettenis 	switch (result) {
1029c0265cf2Skettenis 	case QLW_MBOX_COMPLETE:
1030c0265cf2Skettenis 		for (i = 1; i < nitems(sc->sc_mbox); i++) {
1031c0265cf2Skettenis 			sc->sc_mbox[i] = (maskout & (1 << i)) ?
1032c0265cf2Skettenis 			    qlw_read_mbox(sc, i) : 0;
1033c0265cf2Skettenis 		}
1034c0265cf2Skettenis 		rv = 0;
1035c0265cf2Skettenis 		break;
1036c0265cf2Skettenis 
1037c0265cf2Skettenis 	case 0:
1038c0265cf2Skettenis 		/* timed out; do something? */
1039c0265cf2Skettenis 		DPRINTF(QLW_D_MBOX, "%s: mbox timed out\n", DEVNAME(sc));
1040c0265cf2Skettenis 		rv = 1;
1041c0265cf2Skettenis 		break;
1042c0265cf2Skettenis 
1043c0265cf2Skettenis 	default:
1044c0265cf2Skettenis 		sc->sc_mbox[0] = result;
1045c0265cf2Skettenis 		rv = result;
1046c0265cf2Skettenis 		break;
1047c0265cf2Skettenis 	}
1048c0265cf2Skettenis 
1049c0265cf2Skettenis 	qlw_clear_isr(sc, QLW_INT_TYPE_MBOX);
1050c0265cf2Skettenis 	sc->sc_mbox_pending = 0;
1051c0265cf2Skettenis 	return (rv);
1052c0265cf2Skettenis }
1053c0265cf2Skettenis 
1054c0265cf2Skettenis void
qlw_mbox_putaddr(u_int16_t * mbox,struct qlw_dmamem * mem)1055c0265cf2Skettenis qlw_mbox_putaddr(u_int16_t *mbox, struct qlw_dmamem *mem)
1056c0265cf2Skettenis {
1057c0265cf2Skettenis 	mbox[2] = (QLW_DMA_DVA(mem) >> 16) & 0xffff;
1058c0265cf2Skettenis 	mbox[3] = (QLW_DMA_DVA(mem) >> 0) & 0xffff;
1059c0265cf2Skettenis 	mbox[6] = (QLW_DMA_DVA(mem) >> 48) & 0xffff;
1060c0265cf2Skettenis 	mbox[7] = (QLW_DMA_DVA(mem) >> 32) & 0xffff;
1061c0265cf2Skettenis }
1062c0265cf2Skettenis 
1063c0265cf2Skettenis void
qlw_set_ints(struct qlw_softc * sc,int enabled)1064c0265cf2Skettenis qlw_set_ints(struct qlw_softc *sc, int enabled)
1065c0265cf2Skettenis {
1066c0265cf2Skettenis 	u_int16_t v = enabled ? (QLW_INT_REQ | QLW_RISC_INT_REQ) : 0;
1067c0265cf2Skettenis 	qlw_write(sc, QLW_INT_CTRL, v);
1068c0265cf2Skettenis }
1069c0265cf2Skettenis 
1070c0265cf2Skettenis int
qlw_read_isr(struct qlw_softc * sc,u_int16_t * isr,u_int16_t * info)1071c0265cf2Skettenis qlw_read_isr(struct qlw_softc *sc, u_int16_t *isr, u_int16_t *info)
1072c0265cf2Skettenis {
1073c0265cf2Skettenis 	u_int16_t int_status;
1074c0265cf2Skettenis 
1075c0265cf2Skettenis 	if (qlw_read(sc, QLW_SEMA) & QLW_SEMA_LOCK) {
1076c0265cf2Skettenis 		*info = qlw_read_mbox(sc, 0);
1077c0265cf2Skettenis 		if (*info & QLW_MBOX_HAS_STATUS)
1078c0265cf2Skettenis 			*isr = QLW_INT_TYPE_MBOX;
1079c0265cf2Skettenis 		else
1080c0265cf2Skettenis 			*isr = QLW_INT_TYPE_ASYNC;
1081c0265cf2Skettenis 	} else {
1082c0265cf2Skettenis 		int_status = qlw_read(sc, QLW_INT_STATUS);
1083c0265cf2Skettenis 		if ((int_status & (QLW_INT_REQ | QLW_RISC_INT_REQ)) == 0)
1084c0265cf2Skettenis 			return (0);
1085c0265cf2Skettenis 
1086c0265cf2Skettenis 		*isr = QLW_INT_TYPE_IO;
1087c0265cf2Skettenis 	}
1088c0265cf2Skettenis 
1089c0265cf2Skettenis 	return (1);
1090c0265cf2Skettenis }
1091c0265cf2Skettenis 
1092c0265cf2Skettenis void
qlw_clear_isr(struct qlw_softc * sc,u_int16_t isr)1093c0265cf2Skettenis qlw_clear_isr(struct qlw_softc *sc, u_int16_t isr)
1094c0265cf2Skettenis {
1095c0265cf2Skettenis 	qlw_host_cmd(sc, QLW_HOST_CMD_CLR_RISC_INT);
1096c0265cf2Skettenis 	switch (isr) {
1097c0265cf2Skettenis 	case QLW_INT_TYPE_MBOX:
1098c0265cf2Skettenis 	case QLW_INT_TYPE_ASYNC:
1099c0265cf2Skettenis 		qlw_write(sc, QLW_SEMA, 0);
1100c0265cf2Skettenis 		break;
1101c0265cf2Skettenis 	default:
1102c0265cf2Skettenis 		break;
1103c0265cf2Skettenis 	}
1104c0265cf2Skettenis }
1105c0265cf2Skettenis 
1106c0265cf2Skettenis int
qlw_softreset(struct qlw_softc * sc)1107c0265cf2Skettenis qlw_softreset(struct qlw_softc *sc)
1108c0265cf2Skettenis {
1109c0265cf2Skettenis 	int i;
1110c0265cf2Skettenis 
1111c0265cf2Skettenis 	qlw_set_ints(sc, 0);
1112c0265cf2Skettenis 
1113c0265cf2Skettenis 	/* reset */
1114c0265cf2Skettenis 	qlw_write(sc, QLW_INT_CTRL, QLW_RESET);
1115c0265cf2Skettenis 	delay(100);
1116c0265cf2Skettenis 	/* clear data and control dma engines? */
1117c0265cf2Skettenis 
1118c0265cf2Skettenis 	/* wait for soft reset to clear */
1119c0265cf2Skettenis 	for (i = 0; i < 1000; i++) {
1120c0265cf2Skettenis 		if ((qlw_read(sc, QLW_INT_CTRL) & QLW_RESET) == 0)
1121c0265cf2Skettenis 			break;
1122c0265cf2Skettenis 
1123c0265cf2Skettenis 		delay(100);
1124c0265cf2Skettenis 	}
1125c0265cf2Skettenis 
1126c0265cf2Skettenis 	if (i == 1000) {
1127c0265cf2Skettenis 		DPRINTF(QLW_D_INTR, "%s: reset didn't clear\n", DEVNAME(sc));
1128c0265cf2Skettenis 		qlw_set_ints(sc, 0);
1129c0265cf2Skettenis 		return (ENXIO);
1130c0265cf2Skettenis 	}
1131c0265cf2Skettenis 
1132c0265cf2Skettenis 	qlw_write(sc, QLW_CFG1, 0);
1133c0265cf2Skettenis 
1134c0265cf2Skettenis 	/* reset risc processor */
1135c0265cf2Skettenis 	qlw_host_cmd(sc, QLW_HOST_CMD_RESET);
1136c0265cf2Skettenis 	delay(100);
1137c0265cf2Skettenis 	qlw_write(sc, QLW_SEMA, 0);
1138c0265cf2Skettenis 	qlw_host_cmd(sc, QLW_HOST_CMD_RELEASE);
1139c0265cf2Skettenis 
1140c0265cf2Skettenis 	/* reset queue pointers */
1141c0265cf2Skettenis 	qlw_queue_write(sc, QLW_REQ_IN, 0);
1142c0265cf2Skettenis 	qlw_queue_write(sc, QLW_REQ_OUT, 0);
1143c0265cf2Skettenis 	qlw_queue_write(sc, QLW_RESP_IN, 0);
1144c0265cf2Skettenis 	qlw_queue_write(sc, QLW_RESP_OUT, 0);
1145c0265cf2Skettenis 
1146c0265cf2Skettenis 	qlw_set_ints(sc, 1);
1147c0265cf2Skettenis 	qlw_host_cmd(sc, QLW_HOST_CMD_BIOS);
1148c0265cf2Skettenis 
1149c0265cf2Skettenis 	/* do a basic mailbox operation to check we're alive */
1150c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_NOP;
1151c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0001, 0x0001)) {
1152c0265cf2Skettenis 		DPRINTF(QLW_D_INTR, "%s: ISP not responding after reset\n",
1153c0265cf2Skettenis 		    DEVNAME(sc));
1154c0265cf2Skettenis 		return (ENXIO);
1155c0265cf2Skettenis 	}
1156c0265cf2Skettenis 
1157c0265cf2Skettenis 	return (0);
1158c0265cf2Skettenis }
1159c0265cf2Skettenis 
1160c0265cf2Skettenis void
qlw_dma_burst_enable(struct qlw_softc * sc)1161fdfcaeaeSkettenis qlw_dma_burst_enable(struct qlw_softc *sc)
1162fdfcaeaeSkettenis {
1163e753b624Skettenis 	if (sc->sc_isp_gen == QLW_GEN_ISP1000 ||
1164e753b624Skettenis 	    sc->sc_isp_gen == QLW_GEN_ISP1040) {
1165fdfcaeaeSkettenis 		qlw_write(sc, QLW_CDMA_CFG,
1166fdfcaeaeSkettenis 		    qlw_read(sc, QLW_CDMA_CFG) | QLW_DMA_BURST_ENABLE);
1167fdfcaeaeSkettenis 		qlw_write(sc, QLW_DDMA_CFG,
1168fdfcaeaeSkettenis 		    qlw_read(sc, QLW_DDMA_CFG) | QLW_DMA_BURST_ENABLE);
1169fdfcaeaeSkettenis 	} else {
1170fdfcaeaeSkettenis 		qlw_host_cmd(sc, QLW_HOST_CMD_PAUSE);
1171fdfcaeaeSkettenis 		qlw_write(sc, QLW_CFG1,
1172fdfcaeaeSkettenis 		    qlw_read(sc, QLW_CFG1) | QLW_DMA_BANK);
1173fdfcaeaeSkettenis 		qlw_write(sc, QLW_CDMA_CFG_1080,
1174fdfcaeaeSkettenis 		    qlw_read(sc, QLW_CDMA_CFG_1080) | QLW_DMA_BURST_ENABLE);
1175fdfcaeaeSkettenis 		qlw_write(sc, QLW_DDMA_CFG_1080,
1176fdfcaeaeSkettenis 		    qlw_read(sc, QLW_DDMA_CFG_1080) | QLW_DMA_BURST_ENABLE);
1177fdfcaeaeSkettenis 		qlw_write(sc, QLW_CFG1,
1178fdfcaeaeSkettenis 		    qlw_read(sc, QLW_CFG1) & ~QLW_DMA_BANK);
1179fdfcaeaeSkettenis 		qlw_host_cmd(sc, QLW_HOST_CMD_RELEASE);
1180fdfcaeaeSkettenis 	}
1181fdfcaeaeSkettenis }
1182fdfcaeaeSkettenis 
1183fdfcaeaeSkettenis void
qlw_update(struct qlw_softc * sc,int task)1184c0265cf2Skettenis qlw_update(struct qlw_softc *sc, int task)
1185c0265cf2Skettenis {
1186c0265cf2Skettenis 	/* do things */
1187c0265cf2Skettenis }
1188c0265cf2Skettenis 
1189c0265cf2Skettenis int
qlw_async(struct qlw_softc * sc,u_int16_t info)1190c0265cf2Skettenis qlw_async(struct qlw_softc *sc, u_int16_t info)
1191c0265cf2Skettenis {
1192c0265cf2Skettenis 	int bus;
1193c0265cf2Skettenis 
1194c0265cf2Skettenis 	switch (info) {
1195c0265cf2Skettenis 	case QLW_ASYNC_BUS_RESET:
1196c0265cf2Skettenis 		DPRINTF(QLW_D_PORT, "%s: bus reset\n", DEVNAME(sc));
1197c0265cf2Skettenis 		bus = qlw_read_mbox(sc, 6);
1198c0265cf2Skettenis 		sc->sc_marker_required[bus] = 1;
1199c0265cf2Skettenis 		break;
1200c0265cf2Skettenis 
1201c0265cf2Skettenis #if 0
1202c0265cf2Skettenis 	case QLW_ASYNC_SYSTEM_ERROR:
1203c0265cf2Skettenis 		qla_update(sc, QLW_UPDATE_SOFTRESET);
1204c0265cf2Skettenis 		break;
1205c0265cf2Skettenis 
1206c0265cf2Skettenis 	case QLW_ASYNC_REQ_XFER_ERROR:
1207c0265cf2Skettenis 		qla_update(sc, QLW_UPDATE_SOFTRESET);
1208c0265cf2Skettenis 		break;
1209c0265cf2Skettenis 
1210c0265cf2Skettenis 	case QLW_ASYNC_RSP_XFER_ERROR:
1211c0265cf2Skettenis 		qla_update(sc, QLW_UPDATE_SOFTRESET);
1212c0265cf2Skettenis 		break;
1213c0265cf2Skettenis #endif
1214c0265cf2Skettenis 
1215c0265cf2Skettenis 	case QLW_ASYNC_SCSI_CMD_COMPLETE:
1216c0265cf2Skettenis 		/* shouldn't happen, we disable fast posting */
1217c0265cf2Skettenis 		break;
1218c0265cf2Skettenis 
1219c0265cf2Skettenis 	case QLW_ASYNC_CTIO_COMPLETE:
1220c0265cf2Skettenis 		/* definitely shouldn't happen, we don't do target mode */
1221c0265cf2Skettenis 		break;
1222c0265cf2Skettenis 
1223c0265cf2Skettenis 	default:
1224c0265cf2Skettenis 		DPRINTF(QLW_D_INTR, "%s: unknown async %x\n", DEVNAME(sc),
1225c0265cf2Skettenis 		    info);
1226c0265cf2Skettenis 		break;
1227c0265cf2Skettenis 	}
1228c0265cf2Skettenis 	return (1);
1229c0265cf2Skettenis }
1230c0265cf2Skettenis 
1231f575935dSmiod #ifdef QLW_DEBUG
1232c0265cf2Skettenis void
qlw_dump_iocb(struct qlw_softc * sc,void * buf,int flags)1233a0291dabSkettenis qlw_dump_iocb(struct qlw_softc *sc, void *buf, int flags)
1234c0265cf2Skettenis {
1235c0265cf2Skettenis 	u_int8_t *iocb = buf;
1236c0265cf2Skettenis 	int l;
1237c0265cf2Skettenis 	int b;
1238c0265cf2Skettenis 
1239a0291dabSkettenis 	if ((qlwdebug & flags) == 0)
1240c0265cf2Skettenis 		return;
1241c0265cf2Skettenis 
1242c0265cf2Skettenis 	printf("%s: iocb:\n", DEVNAME(sc));
1243c0265cf2Skettenis 	for (l = 0; l < 4; l++) {
1244c0265cf2Skettenis 		for (b = 0; b < 16; b++) {
1245c0265cf2Skettenis 			printf(" %2.2x", iocb[(l*16)+b]);
1246c0265cf2Skettenis 		}
1247c0265cf2Skettenis 		printf("\n");
1248c0265cf2Skettenis 	}
1249c0265cf2Skettenis }
1250c0265cf2Skettenis 
1251c0265cf2Skettenis void
qlw_dump_iocb_segs(struct qlw_softc * sc,void * segs,int n)1252c0265cf2Skettenis qlw_dump_iocb_segs(struct qlw_softc *sc, void *segs, int n)
1253c0265cf2Skettenis {
1254c0265cf2Skettenis 	u_int8_t *buf = segs;
1255c0265cf2Skettenis 	int s, b;
1256c0265cf2Skettenis 	if ((qlwdebug & QLW_D_IOCB) == 0)
1257c0265cf2Skettenis 		return;
1258c0265cf2Skettenis 
1259c0265cf2Skettenis 	printf("%s: iocb segs:\n", DEVNAME(sc));
1260c0265cf2Skettenis 	for (s = 0; s < n; s++) {
1261c0265cf2Skettenis 		for (b = 0; b < sizeof(struct qlw_iocb_seg); b++) {
1262c0265cf2Skettenis 			printf(" %2.2x", buf[(s*(sizeof(struct qlw_iocb_seg)))
1263c0265cf2Skettenis 			    + b]);
1264c0265cf2Skettenis 		}
1265c0265cf2Skettenis 		printf("\n");
1266c0265cf2Skettenis 	}
1267c0265cf2Skettenis }
1268f575935dSmiod #endif
1269c0265cf2Skettenis 
1270de2fb981Skettenis /*
1271de2fb981Skettenis  * The PCI bus is little-endian whereas SBus is big-endian.  This
1272de2fb981Skettenis  * leads to some differences in byte twisting of DMA transfers of
1273de2fb981Skettenis  * request and response queue entries.  Most fields can be treated as
1274de2fb981Skettenis  * 16-bit or 32-bit with the endianness of the bus, but the header
1275de2fb981Skettenis  * fields end up being swapped by the ISP1000's SBus interface.
1276de2fb981Skettenis  */
1277de2fb981Skettenis 
1278de2fb981Skettenis void
qlw_get_header(struct qlw_softc * sc,struct qlw_iocb_hdr * hdr,int * type,int * flags)1279de2fb981Skettenis qlw_get_header(struct qlw_softc *sc, struct qlw_iocb_hdr *hdr,
1280de2fb981Skettenis     int *type, int *flags)
1281de2fb981Skettenis {
1282de2fb981Skettenis 	if (sc->sc_isp_gen == QLW_GEN_ISP1000) {
1283de2fb981Skettenis 		*type = hdr->entry_count;
1284de2fb981Skettenis 		*flags = hdr->seqno;
1285de2fb981Skettenis 	} else {
1286de2fb981Skettenis 		*type = hdr->entry_type;
1287de2fb981Skettenis 		*flags = hdr->flags;
1288de2fb981Skettenis 	}
1289de2fb981Skettenis }
1290de2fb981Skettenis 
1291de2fb981Skettenis void
qlw_put_header(struct qlw_softc * sc,struct qlw_iocb_hdr * hdr,int type,int count)1292de2fb981Skettenis qlw_put_header(struct qlw_softc *sc, struct qlw_iocb_hdr *hdr,
1293de2fb981Skettenis     int type, int count)
1294de2fb981Skettenis {
1295de2fb981Skettenis 	if (sc->sc_isp_gen == QLW_GEN_ISP1000) {
1296de2fb981Skettenis 		hdr->entry_type = count;
1297de2fb981Skettenis 		hdr->entry_count = type;
1298de2fb981Skettenis 		hdr->seqno = 0;
1299de2fb981Skettenis 		hdr->flags = 0;
1300de2fb981Skettenis 	} else {
1301de2fb981Skettenis 		hdr->entry_type = type;
1302de2fb981Skettenis 		hdr->entry_count = count;
1303de2fb981Skettenis 		hdr->seqno = 0;
1304de2fb981Skettenis 		hdr->flags = 0;
1305de2fb981Skettenis 	}
1306de2fb981Skettenis }
1307de2fb981Skettenis 
1308de2fb981Skettenis void
qlw_put_data_seg(struct qlw_softc * sc,struct qlw_iocb_seg * seg,bus_dmamap_t dmap,int num)1309de2fb981Skettenis qlw_put_data_seg(struct qlw_softc *sc, struct qlw_iocb_seg *seg,
1310de2fb981Skettenis     bus_dmamap_t dmap, int num)
1311de2fb981Skettenis {
1312de2fb981Skettenis 	seg->seg_addr = qlw_swap32(sc, dmap->dm_segs[num].ds_addr);
1313de2fb981Skettenis 	seg->seg_len = qlw_swap32(sc, dmap->dm_segs[num].ds_len);
1314de2fb981Skettenis }
1315de2fb981Skettenis 
1316c0265cf2Skettenis void
qlw_put_marker(struct qlw_softc * sc,int bus,void * buf)1317c0265cf2Skettenis qlw_put_marker(struct qlw_softc *sc, int bus, void *buf)
1318c0265cf2Skettenis {
1319c0265cf2Skettenis 	struct qlw_iocb_marker *marker = buf;
1320c0265cf2Skettenis 
1321de2fb981Skettenis 	qlw_put_header(sc, &marker->hdr, QLW_IOCB_MARKER, 1);
1322c0265cf2Skettenis 
1323c0265cf2Skettenis 	/* could be more specific here; isp(4) isn't */
1324de2fb981Skettenis 	marker->device = qlw_swap16(sc, (bus << 7) << 8);
1325de2fb981Skettenis 	marker->modifier = qlw_swap16(sc, QLW_IOCB_MARKER_SYNC_ALL);
1326a0291dabSkettenis 	qlw_dump_iocb(sc, buf, QLW_D_IOCB);
1327c0265cf2Skettenis }
1328c0265cf2Skettenis 
1329c0265cf2Skettenis void
qlw_put_cmd(struct qlw_softc * sc,void * buf,struct scsi_xfer * xs,struct qlw_ccb * ccb)1330c0265cf2Skettenis qlw_put_cmd(struct qlw_softc *sc, void *buf, struct scsi_xfer *xs,
1331c0265cf2Skettenis     struct qlw_ccb *ccb)
1332c0265cf2Skettenis {
1333c0265cf2Skettenis 	struct qlw_iocb_req0 *req = buf;
1334de2fb981Skettenis 	int entry_count = 1;
1335c0265cf2Skettenis 	u_int16_t dir;
1336c0265cf2Skettenis 	int seg, nsegs;
1337de2fb981Skettenis 	int seg_count;
1338de2fb981Skettenis 	int timeout = 0;
1339de2fb981Skettenis 	int bus, target, lun;
1340c0265cf2Skettenis 
1341c0265cf2Skettenis 	if (xs->datalen == 0) {
1342c0265cf2Skettenis 		dir = QLW_IOCB_CMD_NO_DATA;
1343de2fb981Skettenis 		seg_count = 1;
1344c0265cf2Skettenis 	} else {
1345c0265cf2Skettenis 		dir = xs->flags & SCSI_DATA_IN ? QLW_IOCB_CMD_READ_DATA :
1346c0265cf2Skettenis 		    QLW_IOCB_CMD_WRITE_DATA;
1347de2fb981Skettenis 		seg_count = ccb->ccb_dmamap->dm_nsegs;
1348c0265cf2Skettenis 		nsegs = ccb->ccb_dmamap->dm_nsegs - QLW_IOCB_SEGS_PER_CMD;
1349c0265cf2Skettenis 		while (nsegs > 0) {
1350de2fb981Skettenis 			entry_count++;
1351c0265cf2Skettenis 			nsegs -= QLW_IOCB_SEGS_PER_CONT;
1352c0265cf2Skettenis 		}
1353c0265cf2Skettenis 		for (seg = 0; seg < ccb->ccb_dmamap->dm_nsegs; seg++) {
1354c0265cf2Skettenis 			if (seg >= QLW_IOCB_SEGS_PER_CMD)
1355c0265cf2Skettenis 				break;
1356de2fb981Skettenis 			qlw_put_data_seg(sc, &req->segs[seg],
1357c0265cf2Skettenis 			    ccb->ccb_dmamap, seg);
1358c0265cf2Skettenis 		}
1359c0265cf2Skettenis 	}
1360c0265cf2Skettenis 
13617caa9f4cSkettenis 	if (sc->sc_running && (xs->sc_link->quirks & SDEV_NOTAGS) == 0)
13627caa9f4cSkettenis 		dir |= QLW_IOCB_CMD_SIMPLE_QUEUE;
13637caa9f4cSkettenis 
1364de2fb981Skettenis 	qlw_put_header(sc, &req->hdr, QLW_IOCB_CMD_TYPE_0, entry_count);
1365c0265cf2Skettenis 
1366c0265cf2Skettenis 	/*
1367c0265cf2Skettenis 	 * timeout is in seconds.  make sure it's at least 1 if a timeout
1368c0265cf2Skettenis 	 * was specified in xs
1369c0265cf2Skettenis 	 */
1370c0265cf2Skettenis 	if (xs->timeout != 0)
1371de2fb981Skettenis 		timeout = MAX(1, xs->timeout/1000);
1372c0265cf2Skettenis 
1373de2fb981Skettenis 	req->flags = qlw_swap16(sc, dir);
1374de2fb981Skettenis 	req->seg_count = qlw_swap16(sc, seg_count);
1375de2fb981Skettenis 	req->timeout = qlw_swap16(sc, timeout);
1376c0265cf2Skettenis 
1377de2fb981Skettenis 	bus = qlw_xs_bus(sc, xs);
1378de2fb981Skettenis 	target = xs->sc_link->target;
1379de2fb981Skettenis 	lun = xs->sc_link->lun;
1380de2fb981Skettenis 	req->device = qlw_swap16(sc, (((bus << 7) | target) << 8) | lun);
1381c0265cf2Skettenis 
1382664c6166Skrw 	memcpy(req->cdb, &xs->cmd, xs->cmdlen);
1383de2fb981Skettenis 	req->ccblen = qlw_swap16(sc, xs->cmdlen);
1384de2fb981Skettenis 
1385de2fb981Skettenis 	req->handle = qlw_swap32(sc, ccb->ccb_id);
1386c0265cf2Skettenis 
1387a0291dabSkettenis 	qlw_dump_iocb(sc, buf, QLW_D_IOCB);
1388c0265cf2Skettenis }
1389c0265cf2Skettenis 
1390c0265cf2Skettenis void
qlw_put_cont(struct qlw_softc * sc,void * buf,struct scsi_xfer * xs,struct qlw_ccb * ccb,int seg0)1391c0265cf2Skettenis qlw_put_cont(struct qlw_softc *sc, void *buf, struct scsi_xfer *xs,
1392c0265cf2Skettenis     struct qlw_ccb *ccb, int seg0)
1393c0265cf2Skettenis {
1394c0265cf2Skettenis 	struct qlw_iocb_cont0 *cont = buf;
1395c0265cf2Skettenis 	int seg;
1396c0265cf2Skettenis 
1397de2fb981Skettenis 	qlw_put_header(sc, &cont->hdr, QLW_IOCB_CONT_TYPE_0, 1);
1398c0265cf2Skettenis 
1399c0265cf2Skettenis 	for (seg = seg0; seg < ccb->ccb_dmamap->dm_nsegs; seg++) {
1400c0265cf2Skettenis 		if ((seg - seg0) >= QLW_IOCB_SEGS_PER_CONT)
1401c0265cf2Skettenis 			break;
1402de2fb981Skettenis 		qlw_put_data_seg(sc, &cont->segs[seg - seg0],
1403c0265cf2Skettenis 		    ccb->ccb_dmamap, seg);
1404c0265cf2Skettenis 	}
1405c0265cf2Skettenis }
1406c0265cf2Skettenis 
1407c0265cf2Skettenis #ifndef ISP_NOFIRMWARE
1408c0265cf2Skettenis int
qlw_load_firmware_words(struct qlw_softc * sc,const u_int16_t * src,u_int16_t dest)1409c0265cf2Skettenis qlw_load_firmware_words(struct qlw_softc *sc, const u_int16_t *src,
1410c0265cf2Skettenis     u_int16_t dest)
1411c0265cf2Skettenis {
1412c0265cf2Skettenis 	u_int16_t i;
1413c0265cf2Skettenis 
1414c0265cf2Skettenis 	for (i = 0; i < src[3]; i++) {
1415c0265cf2Skettenis 		sc->sc_mbox[0] = QLW_MBOX_WRITE_RAM_WORD;
1416c0265cf2Skettenis 		sc->sc_mbox[1] = i + dest;
1417c0265cf2Skettenis 		sc->sc_mbox[2] = src[i];
1418c0265cf2Skettenis 		if (qlw_mbox(sc, 0x07, 0x01)) {
1419c0265cf2Skettenis 			printf("firmware load failed\n");
1420c0265cf2Skettenis 			return (1);
1421c0265cf2Skettenis 		}
1422c0265cf2Skettenis 	}
1423c0265cf2Skettenis 
1424c0265cf2Skettenis 	sc->sc_mbox[0] = QLW_MBOX_VERIFY_CSUM;
1425c0265cf2Skettenis 	sc->sc_mbox[1] = dest;
1426c0265cf2Skettenis 	if (qlw_mbox(sc, 0x0003, 0x0003)) {
1427c0265cf2Skettenis 		printf("verification of chunk at %x failed: %x\n",
1428c0265cf2Skettenis 		    dest, sc->sc_mbox[1]);
1429c0265cf2Skettenis 		return (1);
1430c0265cf2Skettenis 	}
1431c0265cf2Skettenis 
1432c0265cf2Skettenis 	return (0);
1433c0265cf2Skettenis }
1434c0265cf2Skettenis 
1435c0265cf2Skettenis int
qlw_load_firmware(struct qlw_softc * sc)1436c0265cf2Skettenis qlw_load_firmware(struct qlw_softc *sc)
1437c0265cf2Skettenis {
1438c0265cf2Skettenis 	return qlw_load_firmware_words(sc, sc->sc_firmware, QLW_CODE_ORG);
1439c0265cf2Skettenis }
1440c0265cf2Skettenis 
1441c0265cf2Skettenis #endif	/* !ISP_NOFIRMWARE */
1442c0265cf2Skettenis 
1443c0265cf2Skettenis int
qlw_read_nvram(struct qlw_softc * sc)1444c0265cf2Skettenis qlw_read_nvram(struct qlw_softc *sc)
1445c0265cf2Skettenis {
1446c0265cf2Skettenis 	u_int16_t data[sizeof(sc->sc_nvram) >> 1];
1447c0265cf2Skettenis 	u_int16_t req, cmd, val;
1448c0265cf2Skettenis 	u_int8_t csum;
1449c0265cf2Skettenis 	int i, bit;
1450c0265cf2Skettenis 	int reqcmd;
1451c0265cf2Skettenis 	int nbits;
1452c0265cf2Skettenis 
1453e753b624Skettenis 	if (sc->sc_nvram_size == 0)
1454e753b624Skettenis 		return (1);
1455e753b624Skettenis 
1456c0265cf2Skettenis 	if (sc->sc_nvram_size == 128) {
1457c0265cf2Skettenis 		reqcmd = (QLW_NVRAM_CMD_READ << 6);
1458c0265cf2Skettenis 		nbits = 8;
1459c0265cf2Skettenis 	} else {
1460c0265cf2Skettenis 		reqcmd = (QLW_NVRAM_CMD_READ << 8);
1461c0265cf2Skettenis 		nbits = 10;
1462c0265cf2Skettenis 	}
1463c0265cf2Skettenis 
1464c0265cf2Skettenis 	qlw_write(sc, QLW_NVRAM, QLW_NVRAM_CHIP_SEL);
1465c0265cf2Skettenis 	delay(10);
1466c0265cf2Skettenis 	qlw_write(sc, QLW_NVRAM, QLW_NVRAM_CHIP_SEL | QLW_NVRAM_CLOCK);
1467c0265cf2Skettenis 	delay(10);
1468c0265cf2Skettenis 
1469c0265cf2Skettenis 	for (i = 0; i < (sc->sc_nvram_size >> 1); i++) {
1470c0265cf2Skettenis 		req = i | reqcmd;
1471c0265cf2Skettenis 
1472c0265cf2Skettenis 		/* write each bit out through the nvram register */
1473c0265cf2Skettenis 		for (bit = nbits; bit >= 0; bit--) {
1474c0265cf2Skettenis 			cmd = QLW_NVRAM_CHIP_SEL;
1475c0265cf2Skettenis 			if ((req >> bit) & 1) {
1476c0265cf2Skettenis 				cmd |= QLW_NVRAM_DATA_OUT;
1477c0265cf2Skettenis 			}
1478c0265cf2Skettenis 			qlw_write(sc, QLW_NVRAM, cmd);
1479c0265cf2Skettenis 			delay(10);
1480c0265cf2Skettenis 			qlw_read(sc, QLW_NVRAM);
1481c0265cf2Skettenis 
1482c0265cf2Skettenis 			qlw_write(sc, QLW_NVRAM, cmd | QLW_NVRAM_CLOCK);
1483c0265cf2Skettenis 			delay(10);
1484c0265cf2Skettenis 			qlw_read(sc, QLW_NVRAM);
1485c0265cf2Skettenis 
1486c0265cf2Skettenis 			qlw_write(sc, QLW_NVRAM, cmd);
1487c0265cf2Skettenis 			delay(10);
1488c0265cf2Skettenis 			qlw_read(sc, QLW_NVRAM);
1489c0265cf2Skettenis 		}
1490c0265cf2Skettenis 
1491c0265cf2Skettenis 		/* read the result back */
1492c0265cf2Skettenis 		val = 0;
1493c0265cf2Skettenis 		for (bit = 0; bit < 16; bit++) {
1494c0265cf2Skettenis 			val <<= 1;
1495c0265cf2Skettenis 			qlw_write(sc, QLW_NVRAM, QLW_NVRAM_CHIP_SEL |
1496c0265cf2Skettenis 			    QLW_NVRAM_CLOCK);
1497c0265cf2Skettenis 			delay(10);
1498c0265cf2Skettenis 			if (qlw_read(sc, QLW_NVRAM) & QLW_NVRAM_DATA_IN)
1499c0265cf2Skettenis 				val |= 1;
1500c0265cf2Skettenis 			delay(10);
1501c0265cf2Skettenis 
1502c0265cf2Skettenis 			qlw_write(sc, QLW_NVRAM, QLW_NVRAM_CHIP_SEL);
1503c0265cf2Skettenis 			delay(10);
1504c0265cf2Skettenis 			qlw_read(sc, QLW_NVRAM);
1505c0265cf2Skettenis 		}
1506c0265cf2Skettenis 
1507c0265cf2Skettenis 		qlw_write(sc, QLW_NVRAM, 0);
1508c0265cf2Skettenis 		delay(10);
1509c0265cf2Skettenis 		qlw_read(sc, QLW_NVRAM);
1510c0265cf2Skettenis 
1511c0265cf2Skettenis 		data[i] = letoh16(val);
1512c0265cf2Skettenis 	}
1513c0265cf2Skettenis 
1514c0265cf2Skettenis 	csum = 0;
1515c0265cf2Skettenis 	for (i = 0; i < (sc->sc_nvram_size >> 1); i++) {
1516c0265cf2Skettenis 		csum += data[i] & 0xff;
1517c0265cf2Skettenis 		csum += data[i] >> 8;
1518c0265cf2Skettenis 	}
1519c0265cf2Skettenis 
1520607c4deaSderaadt 	memcpy(&sc->sc_nvram, data, sizeof(sc->sc_nvram));
1521c0265cf2Skettenis 	/* id field should be 'ISP ', version should high enough */
1522c0265cf2Skettenis 	if (sc->sc_nvram.id[0] != 'I' || sc->sc_nvram.id[1] != 'S' ||
1523c0265cf2Skettenis 	    sc->sc_nvram.id[2] != 'P' || sc->sc_nvram.id[3] != ' ' ||
1524c0265cf2Skettenis 	    sc->sc_nvram.nvram_version < sc->sc_nvram_minversion ||
1525c0265cf2Skettenis 	    (csum != 0)) {
1526c0265cf2Skettenis 		printf("%s: nvram corrupt\n", DEVNAME(sc));
1527c0265cf2Skettenis 		return (1);
1528c0265cf2Skettenis 	}
1529c0265cf2Skettenis 	return (0);
1530c0265cf2Skettenis }
1531c0265cf2Skettenis 
1532c0265cf2Skettenis void
qlw_parse_nvram_1040(struct qlw_softc * sc,int bus)1533c0265cf2Skettenis qlw_parse_nvram_1040(struct qlw_softc *sc, int bus)
1534c0265cf2Skettenis {
1535c0265cf2Skettenis 	struct qlw_nvram_1040 *nv = (struct qlw_nvram_1040 *)&sc->sc_nvram;
1536c0265cf2Skettenis 	int target;
1537c0265cf2Skettenis 
1538c0265cf2Skettenis 	KASSERT(bus == 0);
1539c0265cf2Skettenis 
15401d0a0664Skettenis 	if (!ISSET(sc->sc_flags, QLW_FLAG_INITIATOR))
154142de16feSkettenis 		sc->sc_initiator[0] = (nv->config1 >> 4);
15421d0a0664Skettenis 
1543c0265cf2Skettenis 	sc->sc_retry_count[0] = nv->retry_count;
1544c0265cf2Skettenis 	sc->sc_retry_delay[0] = nv->retry_delay;
1545c0265cf2Skettenis 	sc->sc_reset_delay[0] = nv->reset_delay;
1546d28ac15bSkettenis 	sc->sc_tag_age_limit[0] = nv->tag_age_limit;
1547c0265cf2Skettenis 	sc->sc_selection_timeout[0] = letoh16(nv->selection_timeout);
1548c0265cf2Skettenis 	sc->sc_max_queue_depth[0] = letoh16(nv->max_queue_depth);
1549c0265cf2Skettenis 	sc->sc_async_data_setup[0] = (nv->config2 & 0x0f);
1550c0265cf2Skettenis 	sc->sc_req_ack_active_neg[0] = ((nv->config2 & 0x10) >> 4);
1551c0265cf2Skettenis 	sc->sc_data_line_active_neg[0] = ((nv->config2 & 0x20) >> 5);
1552c0265cf2Skettenis 
1553c0265cf2Skettenis 	for (target = 0; target < QLW_MAX_TARGETS; target++) {
1554c0265cf2Skettenis 		struct qlw_target *qt = &sc->sc_target[0][target];
1555c0265cf2Skettenis 
1556c0265cf2Skettenis 		qt->qt_params = (nv->target[target].parameter << 8);
1557c0265cf2Skettenis 		qt->qt_exec_throttle = nv->target[target].execution_throttle;
1558c0265cf2Skettenis 		qt->qt_sync_period = nv->target[target].sync_period;
1559c0265cf2Skettenis 		qt->qt_sync_offset = nv->target[target].flags & 0x0f;
1560c0265cf2Skettenis 	}
1561c0265cf2Skettenis }
1562c0265cf2Skettenis 
1563c0265cf2Skettenis void
qlw_parse_nvram_1080(struct qlw_softc * sc,int bus)1564c0265cf2Skettenis qlw_parse_nvram_1080(struct qlw_softc *sc, int bus)
1565c0265cf2Skettenis {
1566c0265cf2Skettenis 	struct qlw_nvram_1080 *nvram = (struct qlw_nvram_1080 *)&sc->sc_nvram;
1567c0265cf2Skettenis 	struct qlw_nvram_bus *nv = &nvram->bus[bus];
1568c0265cf2Skettenis 	int target;
1569c0265cf2Skettenis 
1570fdfcaeaeSkettenis 	sc->sc_isp_config = nvram->isp_config;
1571d28ac15bSkettenis 	sc->sc_fw_features = nvram->fw_features;
1572fdfcaeaeSkettenis 
15731d0a0664Skettenis 	if (!ISSET(sc->sc_flags, QLW_FLAG_INITIATOR))
157442de16feSkettenis 		sc->sc_initiator[bus] = (nv->config1 & 0x0f);
15751d0a0664Skettenis 
1576c0265cf2Skettenis 	sc->sc_retry_count[bus] = nv->retry_count;
1577c0265cf2Skettenis 	sc->sc_retry_delay[bus] = nv->retry_delay;
1578c0265cf2Skettenis 	sc->sc_reset_delay[bus] = nv->reset_delay;
1579c0265cf2Skettenis 	sc->sc_selection_timeout[bus] = letoh16(nv->selection_timeout);
1580c0265cf2Skettenis 	sc->sc_max_queue_depth[bus] = letoh16(nv->max_queue_depth);
1581c0265cf2Skettenis 	sc->sc_async_data_setup[bus] = (nv->config2 & 0x0f);
1582c0265cf2Skettenis 	sc->sc_req_ack_active_neg[bus] = ((nv->config2 & 0x10) >> 4);
1583c0265cf2Skettenis 	sc->sc_data_line_active_neg[bus] = ((nv->config2 & 0x20) >> 5);
1584c0265cf2Skettenis 
1585c0265cf2Skettenis 	for (target = 0; target < QLW_MAX_TARGETS; target++) {
1586c0265cf2Skettenis 		struct qlw_target *qt = &sc->sc_target[bus][target];
1587c0265cf2Skettenis 
1588c0265cf2Skettenis 		qt->qt_params = (nv->target[target].parameter << 8);
1589c0265cf2Skettenis 		qt->qt_exec_throttle = nv->target[target].execution_throttle;
1590c0265cf2Skettenis 		qt->qt_sync_period = nv->target[target].sync_period;
1591c0265cf2Skettenis 		if (sc->sc_isp_gen == QLW_GEN_ISP12160)
1592c0265cf2Skettenis 			qt->qt_sync_offset = nv->target[target].flags & 0x1f;
1593c0265cf2Skettenis 		else
1594c0265cf2Skettenis 			qt->qt_sync_offset = nv->target[target].flags & 0x0f;
1595c0265cf2Skettenis 	}
1596c0265cf2Skettenis }
1597c0265cf2Skettenis 
1598c0265cf2Skettenis void
qlw_init_defaults(struct qlw_softc * sc,int bus)1599c0265cf2Skettenis qlw_init_defaults(struct qlw_softc *sc, int bus)
1600c0265cf2Skettenis {
1601c0265cf2Skettenis 	int target;
1602c0265cf2Skettenis 
1603fdfcaeaeSkettenis 	switch (sc->sc_isp_gen) {
1604e753b624Skettenis 	case QLW_GEN_ISP1000:
1605e753b624Skettenis 		break;
1606fdfcaeaeSkettenis 	case QLW_GEN_ISP1040:
1607fdfcaeaeSkettenis 		sc->sc_isp_config = QLW_BURST_ENABLE | QLW_PCI_FIFO_64;
1608fdfcaeaeSkettenis 		break;
1609fdfcaeaeSkettenis 	case QLW_GEN_ISP1080:
1610fdfcaeaeSkettenis 	case QLW_GEN_ISP12160:
1611fdfcaeaeSkettenis 		sc->sc_isp_config = QLW_BURST_ENABLE | QLW_PCI_FIFO_128;
1612d28ac15bSkettenis 		sc->sc_fw_features = QLW_FW_FEATURE_LVD_NOTIFY;
1613fdfcaeaeSkettenis 		break;
1614fdfcaeaeSkettenis 	}
1615fdfcaeaeSkettenis 
1616c0265cf2Skettenis 	sc->sc_retry_count[bus] = 0;
1617c0265cf2Skettenis 	sc->sc_retry_delay[bus] = 0;
1618c0265cf2Skettenis 	sc->sc_reset_delay[bus] = 3;
1619d28ac15bSkettenis 	sc->sc_tag_age_limit[bus] = 8;
1620c0265cf2Skettenis 	sc->sc_selection_timeout[bus] = 250;
1621c0265cf2Skettenis 	sc->sc_max_queue_depth[bus] = 32;
1622c0265cf2Skettenis 	if (sc->sc_clock > 40)
1623c0265cf2Skettenis 		sc->sc_async_data_setup[bus] = 9;
1624c0265cf2Skettenis 	else
1625c0265cf2Skettenis 		sc->sc_async_data_setup[bus] = 6;
1626c0265cf2Skettenis 	sc->sc_req_ack_active_neg[bus] = 1;
1627c0265cf2Skettenis 	sc->sc_data_line_active_neg[bus] = 1;
1628c0265cf2Skettenis 
1629c0265cf2Skettenis 	for (target = 0; target < QLW_MAX_TARGETS; target++) {
1630c0265cf2Skettenis 		struct qlw_target *qt = &sc->sc_target[bus][target];
1631c0265cf2Skettenis 
1632c0265cf2Skettenis 		qt->qt_params = QLW_TARGET_DEFAULT;
1633c0265cf2Skettenis 		qt->qt_exec_throttle = 16;
1634c0265cf2Skettenis 		qt->qt_sync_period = 10;
1635c0265cf2Skettenis 		qt->qt_sync_offset = 12;
1636c0265cf2Skettenis 	}
1637c0265cf2Skettenis }
1638c0265cf2Skettenis 
1639c0265cf2Skettenis struct qlw_dmamem *
qlw_dmamem_alloc(struct qlw_softc * sc,size_t size)1640c0265cf2Skettenis qlw_dmamem_alloc(struct qlw_softc *sc, size_t size)
1641c0265cf2Skettenis {
1642c0265cf2Skettenis 	struct qlw_dmamem *m;
1643c0265cf2Skettenis 	int nsegs;
1644c0265cf2Skettenis 
1645c0265cf2Skettenis 	m = malloc(sizeof(*m), M_DEVBUF, M_NOWAIT | M_ZERO);
1646c0265cf2Skettenis 	if (m == NULL)
1647c0265cf2Skettenis 		return (NULL);
1648c0265cf2Skettenis 
1649c0265cf2Skettenis 	m->qdm_size = size;
1650c0265cf2Skettenis 
1651c0265cf2Skettenis 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1652c0265cf2Skettenis 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &m->qdm_map) != 0)
1653c0265cf2Skettenis 		goto qdmfree;
1654c0265cf2Skettenis 
1655c0265cf2Skettenis 	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &m->qdm_seg, 1,
1656c0265cf2Skettenis 	    &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
1657c0265cf2Skettenis 		goto destroy;
1658c0265cf2Skettenis 
1659c0265cf2Skettenis 	if (bus_dmamem_map(sc->sc_dmat, &m->qdm_seg, nsegs, size, &m->qdm_kva,
1660c0265cf2Skettenis 	    BUS_DMA_NOWAIT) != 0)
1661c0265cf2Skettenis 		goto free;
1662c0265cf2Skettenis 
1663c0265cf2Skettenis 	if (bus_dmamap_load(sc->sc_dmat, m->qdm_map, m->qdm_kva, size, NULL,
1664c0265cf2Skettenis 	    BUS_DMA_NOWAIT) != 0)
1665c0265cf2Skettenis 		goto unmap;
1666c0265cf2Skettenis 
1667c0265cf2Skettenis 	return (m);
1668c0265cf2Skettenis 
1669c0265cf2Skettenis unmap:
1670c0265cf2Skettenis 	bus_dmamem_unmap(sc->sc_dmat, m->qdm_kva, m->qdm_size);
1671c0265cf2Skettenis free:
1672c0265cf2Skettenis 	bus_dmamem_free(sc->sc_dmat, &m->qdm_seg, 1);
1673c0265cf2Skettenis destroy:
1674c0265cf2Skettenis 	bus_dmamap_destroy(sc->sc_dmat, m->qdm_map);
1675c0265cf2Skettenis qdmfree:
1676bae2bd50Sderaadt 	free(m, M_DEVBUF, sizeof(*m));
1677c0265cf2Skettenis 
1678c0265cf2Skettenis 	return (NULL);
1679c0265cf2Skettenis }
1680c0265cf2Skettenis 
1681c0265cf2Skettenis void
qlw_dmamem_free(struct qlw_softc * sc,struct qlw_dmamem * m)1682c0265cf2Skettenis qlw_dmamem_free(struct qlw_softc *sc, struct qlw_dmamem *m)
1683c0265cf2Skettenis {
1684c0265cf2Skettenis 	bus_dmamap_unload(sc->sc_dmat, m->qdm_map);
1685c0265cf2Skettenis 	bus_dmamem_unmap(sc->sc_dmat, m->qdm_kva, m->qdm_size);
1686c0265cf2Skettenis 	bus_dmamem_free(sc->sc_dmat, &m->qdm_seg, 1);
1687c0265cf2Skettenis 	bus_dmamap_destroy(sc->sc_dmat, m->qdm_map);
1688bae2bd50Sderaadt 	free(m, M_DEVBUF, sizeof(*m));
1689c0265cf2Skettenis }
1690c0265cf2Skettenis 
1691c0265cf2Skettenis int
qlw_alloc_ccbs(struct qlw_softc * sc)1692c0265cf2Skettenis qlw_alloc_ccbs(struct qlw_softc *sc)
1693c0265cf2Skettenis {
1694c0265cf2Skettenis 	struct qlw_ccb		*ccb;
1695c0265cf2Skettenis 	u_int8_t		*cmd;
1696c0265cf2Skettenis 	int			i;
1697c0265cf2Skettenis 
1698c0265cf2Skettenis 	SIMPLEQ_INIT(&sc->sc_ccb_free);
1699c0265cf2Skettenis 	mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
1700c0265cf2Skettenis 	mtx_init(&sc->sc_queue_mtx, IPL_BIO);
1701c0265cf2Skettenis 
17029f6fb5c7Sderaadt 	sc->sc_ccbs = mallocarray(sc->sc_maxccbs, sizeof(struct qlw_ccb),
1703c0265cf2Skettenis 	    M_DEVBUF, M_WAITOK | M_CANFAIL | M_ZERO);
1704c0265cf2Skettenis 	if (sc->sc_ccbs == NULL) {
1705c0265cf2Skettenis 		printf("%s: unable to allocate ccbs\n", DEVNAME(sc));
1706c0265cf2Skettenis 		return (1);
1707c0265cf2Skettenis 	}
1708c0265cf2Skettenis 
170951fb3575Skettenis 	sc->sc_requests = qlw_dmamem_alloc(sc, sc->sc_maxrequests *
1710c0265cf2Skettenis 	    QLW_QUEUE_ENTRY_SIZE);
1711c0265cf2Skettenis 	if (sc->sc_requests == NULL) {
1712c0265cf2Skettenis 		printf("%s: unable to allocate ccb dmamem\n", DEVNAME(sc));
1713c0265cf2Skettenis 		goto free_ccbs;
1714c0265cf2Skettenis 	}
171551fb3575Skettenis 	sc->sc_responses = qlw_dmamem_alloc(sc, sc->sc_maxresponses *
1716c0265cf2Skettenis 	    QLW_QUEUE_ENTRY_SIZE);
1717c0265cf2Skettenis 	if (sc->sc_responses == NULL) {
1718c0265cf2Skettenis 		printf("%s: unable to allocate rcb dmamem\n", DEVNAME(sc));
1719c0265cf2Skettenis 		goto free_req;
1720c0265cf2Skettenis 	}
1721c0265cf2Skettenis 
1722c0265cf2Skettenis 	cmd = QLW_DMA_KVA(sc->sc_requests);
172392d24382Skettenis 	memset(cmd, 0, QLW_QUEUE_ENTRY_SIZE * sc->sc_maxccbs);
172492d24382Skettenis 	for (i = 0; i < sc->sc_maxccbs; i++) {
1725c0265cf2Skettenis 		ccb = &sc->sc_ccbs[i];
1726c0265cf2Skettenis 
1727c0265cf2Skettenis 		if (bus_dmamap_create(sc->sc_dmat, MAXPHYS,
1728c0265cf2Skettenis 		    QLW_MAX_SEGS, MAXPHYS, 0,
1729c0265cf2Skettenis 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1730c0265cf2Skettenis 		    &ccb->ccb_dmamap) != 0) {
1731c0265cf2Skettenis 			printf("%s: unable to create dma map\n", DEVNAME(sc));
1732c0265cf2Skettenis 			goto free_maps;
1733c0265cf2Skettenis 		}
1734c0265cf2Skettenis 
1735c0265cf2Skettenis 		ccb->ccb_sc = sc;
1736c0265cf2Skettenis 		ccb->ccb_id = i;
1737c0265cf2Skettenis 
1738c0265cf2Skettenis 		qlw_put_ccb(sc, ccb);
1739c0265cf2Skettenis 	}
1740c0265cf2Skettenis 
1741c0265cf2Skettenis 	scsi_iopool_init(&sc->sc_iopool, sc, qlw_get_ccb, qlw_put_ccb);
1742c0265cf2Skettenis 	return (0);
1743c0265cf2Skettenis 
1744c0265cf2Skettenis free_maps:
1745c0265cf2Skettenis 	while ((ccb = qlw_get_ccb(sc)) != NULL)
1746c0265cf2Skettenis 		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
1747c0265cf2Skettenis 
1748c0265cf2Skettenis 	qlw_dmamem_free(sc, sc->sc_responses);
1749c0265cf2Skettenis free_req:
1750c0265cf2Skettenis 	qlw_dmamem_free(sc, sc->sc_requests);
1751c0265cf2Skettenis free_ccbs:
1752aa3cabd0Stedu 	free(sc->sc_ccbs, M_DEVBUF, 0);
1753c0265cf2Skettenis 
1754c0265cf2Skettenis 	return (1);
1755c0265cf2Skettenis }
1756c0265cf2Skettenis 
1757c0265cf2Skettenis void
qlw_free_ccbs(struct qlw_softc * sc)1758c0265cf2Skettenis qlw_free_ccbs(struct qlw_softc *sc)
1759c0265cf2Skettenis {
1760c0265cf2Skettenis 	struct qlw_ccb		*ccb;
1761c0265cf2Skettenis 
1762c0265cf2Skettenis 	scsi_iopool_destroy(&sc->sc_iopool);
1763c0265cf2Skettenis 	while ((ccb = qlw_get_ccb(sc)) != NULL)
1764c0265cf2Skettenis 		bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap);
1765c0265cf2Skettenis 	qlw_dmamem_free(sc, sc->sc_responses);
1766c0265cf2Skettenis 	qlw_dmamem_free(sc, sc->sc_requests);
1767aa3cabd0Stedu 	free(sc->sc_ccbs, M_DEVBUF, 0);
1768c0265cf2Skettenis }
1769c0265cf2Skettenis 
1770c0265cf2Skettenis void *
qlw_get_ccb(void * xsc)1771c0265cf2Skettenis qlw_get_ccb(void *xsc)
1772c0265cf2Skettenis {
1773c0265cf2Skettenis 	struct qlw_softc	*sc = xsc;
1774c0265cf2Skettenis 	struct qlw_ccb		*ccb;
1775c0265cf2Skettenis 
1776c0265cf2Skettenis 	mtx_enter(&sc->sc_ccb_mtx);
1777c0265cf2Skettenis 	ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free);
1778c0265cf2Skettenis 	if (ccb != NULL) {
1779c0265cf2Skettenis 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_link);
1780c0265cf2Skettenis 	}
1781c0265cf2Skettenis 	mtx_leave(&sc->sc_ccb_mtx);
1782c0265cf2Skettenis 	return (ccb);
1783c0265cf2Skettenis }
1784c0265cf2Skettenis 
1785c0265cf2Skettenis void
qlw_put_ccb(void * xsc,void * io)1786c0265cf2Skettenis qlw_put_ccb(void *xsc, void *io)
1787c0265cf2Skettenis {
1788c0265cf2Skettenis 	struct qlw_softc	*sc = xsc;
1789c0265cf2Skettenis 	struct qlw_ccb		*ccb = io;
1790c0265cf2Skettenis 
1791c0265cf2Skettenis 	ccb->ccb_xs = NULL;
1792c0265cf2Skettenis 	mtx_enter(&sc->sc_ccb_mtx);
1793c0265cf2Skettenis 	SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_link);
1794c0265cf2Skettenis 	mtx_leave(&sc->sc_ccb_mtx);
1795c0265cf2Skettenis }
1796