xref: /netbsd-src/sys/arch/sgimips/stand/common/iris_scsi.c (revision 100a3398b8d3c64e571cff36b46c23431b410e09)
1*100a3398Sandvar /*	$NetBSD: iris_scsi.c,v 1.2 2024/02/09 22:08:33 andvar Exp $	*/
2d02e022dStsutsui 
3d02e022dStsutsui /*
4d02e022dStsutsui  * Copyright (c) 2018 Naruaki Etomi
5d02e022dStsutsui  * All rights reserved.
6d02e022dStsutsui  *
7d02e022dStsutsui  * Redistribution and use in source and binary forms, with or without
8d02e022dStsutsui  * modification, are permitted provided that the following conditions
9d02e022dStsutsui  * are met:
10d02e022dStsutsui  * 1. Redistributions of source code must retain the above copyright
11d02e022dStsutsui  *    notice, this list of conditions and the following disclaimer.
12d02e022dStsutsui  * 2. Redistributions in binary form must reproduce the above copyright
13d02e022dStsutsui  *    notice, this list of conditions and the following disclaimer in the
14d02e022dStsutsui  *    documentation and/or other materials provided with the distribution.
15d02e022dStsutsui  *
16d02e022dStsutsui  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17d02e022dStsutsui  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18d02e022dStsutsui  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19d02e022dStsutsui  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20d02e022dStsutsui  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21d02e022dStsutsui  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22d02e022dStsutsui  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23d02e022dStsutsui  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24d02e022dStsutsui  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25d02e022dStsutsui  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26d02e022dStsutsui  */
27d02e022dStsutsui 
28d02e022dStsutsui /*
29d02e022dStsutsui  * Silicon Graphics "IRIS" series MIPS processors machine bootloader.
30d02e022dStsutsui  * WD33C93 SCSI bus driver for standalone programs.
31d02e022dStsutsui  */
32d02e022dStsutsui 
33d02e022dStsutsui #include <sys/cdefs.h>
34d02e022dStsutsui #include <lib/libsa/stand.h>
35d02e022dStsutsui 
36d02e022dStsutsui #ifndef	INDIGO_R3K_MODE
37d02e022dStsutsui #include <dev/arcbios/arcbios.h>
38d02e022dStsutsui #endif
39d02e022dStsutsui 
40d02e022dStsutsui #include "iris_machdep.h"
41d02e022dStsutsui #include "iris_scsivar.h"
42d02e022dStsutsui #include "iris_scsireg.h"
43d02e022dStsutsui #include "iris_scsicmd.h"
44d02e022dStsutsui #include <dev/scsipi/scsi_message.h>
45d02e022dStsutsui 
46d02e022dStsutsui #define SBIC_WAIT(regs, until, timeo) wd33c93_wait(regs, until, timeo)
47d02e022dStsutsui 
48d02e022dStsutsui /*
49d02e022dStsutsui  * Timeouts
50d02e022dStsutsui  */
51d02e022dStsutsui int	wd33c93_cmd_wait	= SBIC_CMD_WAIT;
52d02e022dStsutsui int	wd33c93_data_wait	= SBIC_DATA_WAIT;
53d02e022dStsutsui int	wd33c93_init_wait	= SBIC_INIT_WAIT;
54d02e022dStsutsui 
55d02e022dStsutsui #define STATUS_UNKNOWN	0xff
56d02e022dStsutsui 
57d02e022dStsutsui void	wd33c93_reset(struct wd33c93_softc *);
58d02e022dStsutsui int	wd33c93_wait(struct wd33c93_softc *, uint8_t, int);
59d02e022dStsutsui uint8_t	wd33c93_selectbus(struct wd33c93_softc *, uint8_t *, size_t, uint8_t *,
60d02e022dStsutsui 	    size_t *);
61d02e022dStsutsui void	wd33c93_setsync(struct wd33c93_softc *);
62d02e022dStsutsui int	wd33c93_nextstate(struct wd33c93_softc *, uint8_t *, size_t, uint8_t *,
63d02e022dStsutsui 	    size_t *, uint8_t, uint8_t);
64d02e022dStsutsui size_t	wd33c93_xfout(struct wd33c93_softc *, void *, size_t *);
65d02e022dStsutsui int	wd33c93_intr(struct wd33c93_softc *, uint8_t *, size_t, uint8_t *,
66d02e022dStsutsui 	    size_t *);
67d02e022dStsutsui size_t	wd33c93_xfin(struct wd33c93_softc *, void *, size_t *);
68d02e022dStsutsui void	wd33c93_xferdone(struct wd33c93_softc *);
69d02e022dStsutsui int	wd33c93_abort(struct wd33c93_softc *, uint8_t *, size_t, uint8_t *,
70d02e022dStsutsui 	    size_t *);
71d02e022dStsutsui int	wd33c93_poll(struct wd33c93_softc *, uint8_t *, size_t, uint8_t *,
72d02e022dStsutsui 	    size_t *);
73d02e022dStsutsui void	wd33c93_timeout(struct wd33c93_softc *, uint8_t *, size_t, uint8_t *,
74d02e022dStsutsui 	    size_t *);
75d02e022dStsutsui int	wd33c93_msgin_phase(struct wd33c93_softc *);
76d02e022dStsutsui void	wd33c93_scsistart(struct wd33c93_softc *);
77d02e022dStsutsui void	wd33c93_scsidone(struct wd33c93_softc *);
78d02e022dStsutsui void	wd33c93_error(struct wd33c93_softc *);
79d02e022dStsutsui 
80d02e022dStsutsui /*
81d02e022dStsutsui  * Initialize SPC & Data Structure
82d02e022dStsutsui  */
83d02e022dStsutsui void
wd33c93_init(void * aaddr,void * daddr)84d02e022dStsutsui wd33c93_init(void *aaddr, void *daddr)
85d02e022dStsutsui {
86d02e022dStsutsui 	struct wd33c93_softc *sc;
87d02e022dStsutsui 
88d02e022dStsutsui 	sc = &wd33c93_softc[scsi_ctlr];
89d02e022dStsutsui 
90d02e022dStsutsui 	sc->sc_asr_regh = aaddr;
91d02e022dStsutsui 	sc->sc_data_regh = daddr;
92d02e022dStsutsui 	sc->sc_target = scsi_id;
93d02e022dStsutsui 
94d02e022dStsutsui 	sc->sc_flags = 0;
95d02e022dStsutsui 	sc->sc_state = SBIC_IDLE;
96d02e022dStsutsui 
97d02e022dStsutsui 	wd33c93_reset(sc);
98d02e022dStsutsui }
99d02e022dStsutsui 
100d02e022dStsutsui void
wd33c93_reset(struct wd33c93_softc * sc)101d02e022dStsutsui wd33c93_reset(struct wd33c93_softc *sc)
102d02e022dStsutsui {
103d02e022dStsutsui 	u_int my_id;
104d02e022dStsutsui 	uint8_t csr;
105d02e022dStsutsui 
106d02e022dStsutsui 	SET_SBIC_cmd(sc, SBIC_CMD_ABORT);
107d02e022dStsutsui 	WAIT_CIP(sc);
108d02e022dStsutsui 
109d02e022dStsutsui 	my_id = sc->sc_target & SBIC_ID_MASK;
110d02e022dStsutsui 
111d02e022dStsutsui 	/* Set Clock == 20.0 MHz */
112d02e022dStsutsui 	my_id |= SBIC_ID_FS_8_10;
113d02e022dStsutsui 	sc->sc_syncperiods = 2 * 2 * 1250 / SCSI_CLKFREQ;
114d02e022dStsutsui 
115d02e022dStsutsui 	SET_SBIC_myid(sc, my_id);
116d02e022dStsutsui 
117d02e022dStsutsui 	/* Reset the chip */
118d02e022dStsutsui 	SET_SBIC_cmd(sc, SBIC_CMD_RESET);
119d02e022dStsutsui 	DELAY(25);
120d02e022dStsutsui 	SBIC_WAIT(sc, SBIC_ASR_INT, 0);
121d02e022dStsutsui 
122d02e022dStsutsui 	/* PIO  mode */
123d02e022dStsutsui 	SBIC_TC_PUT(sc, 0);
124d02e022dStsutsui 	SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
125d02e022dStsutsui 
126d02e022dStsutsui 	/* clears interrupt also */
127d02e022dStsutsui 	GET_SBIC_csr(sc, csr);
128d02e022dStsutsui 	__USE(csr);
129d02e022dStsutsui 
130d02e022dStsutsui 	SET_SBIC_rselid(sc, SBIC_RID_ER);
131d02e022dStsutsui 	SET_SBIC_syn(sc, 0);
132d02e022dStsutsui 
133d02e022dStsutsui 	sc->sc_flags = 0;
134d02e022dStsutsui 	sc->sc_state = SBIC_IDLE;
135d02e022dStsutsui }
136d02e022dStsutsui 
137d02e022dStsutsui int
wd33c93_wait(struct wd33c93_softc * sc,uint8_t until,int timeo)138d02e022dStsutsui wd33c93_wait(struct wd33c93_softc *sc, uint8_t until, int timeo)
139d02e022dStsutsui {
140d02e022dStsutsui 	uint8_t val;
141d02e022dStsutsui 
142d02e022dStsutsui 	if (timeo == 0)
143d02e022dStsutsui 		/* some large value.. */
144d02e022dStsutsui 		timeo = 1000000;
145d02e022dStsutsui 
146d02e022dStsutsui 	GET_SBIC_asr(sc, val);
147d02e022dStsutsui 
148d02e022dStsutsui 	while ((val & until) == 0) {
149d02e022dStsutsui 		if (timeo-- == 0) {
150d02e022dStsutsui 			return val;
151d02e022dStsutsui 			break;
152d02e022dStsutsui 		}
153d02e022dStsutsui 		DELAY(1);
154d02e022dStsutsui 		GET_SBIC_asr(sc, val);
155d02e022dStsutsui 	}
156d02e022dStsutsui 	return val;
157d02e022dStsutsui }
158d02e022dStsutsui 
159d02e022dStsutsui /* SCSI command entry point */
160d02e022dStsutsui int
wd33c93_go(struct wd33c93_softc * sc,uint8_t * cbuf,size_t clen,uint8_t * buf,size_t * lenp)161d02e022dStsutsui wd33c93_go(struct wd33c93_softc *sc, uint8_t *cbuf, size_t clen, uint8_t *buf,
162d02e022dStsutsui     size_t *lenp)
163d02e022dStsutsui {
164d02e022dStsutsui 	int	i;
165d02e022dStsutsui 	uint8_t	csr, asr;
166d02e022dStsutsui 
167d02e022dStsutsui 	wd33c93_scsistart(sc);
168d02e022dStsutsui 
169d02e022dStsutsui 	sc->sc_status = STATUS_UNKNOWN;
170d02e022dStsutsui 	sc->sc_flags = 0;
171d02e022dStsutsui 	/* select the SCSI bus (it's an error if bus isn't free) */
172d02e022dStsutsui 	if ((csr = wd33c93_selectbus(sc, cbuf, clen, buf, lenp)) == 0)
173d02e022dStsutsui 		/* Not done: needs to be rescheduled */
174d02e022dStsutsui 		return 1;
175d02e022dStsutsui 
176d02e022dStsutsui 	/*
177d02e022dStsutsui 	 * Lets cycle a while then let the interrupt handler take over.
178d02e022dStsutsui 	 */
179d02e022dStsutsui 	GET_SBIC_asr(sc, asr);
180d02e022dStsutsui 	do {
181d02e022dStsutsui 		/* Handle the new phase */
182d02e022dStsutsui 		i = wd33c93_nextstate(sc, cbuf, clen, buf, lenp, csr, asr);
183d02e022dStsutsui 		WAIT_CIP(sc);		/* XXX */
184d02e022dStsutsui 		if (sc->sc_state == SBIC_CONNECTED) {
185d02e022dStsutsui 			GET_SBIC_asr(sc, asr);
186d02e022dStsutsui 
187d02e022dStsutsui 			if ((asr & SBIC_ASR_LCI) != 0)
188d02e022dStsutsui 				DELAY(5000);
189d02e022dStsutsui 
190d02e022dStsutsui 			if ((asr & SBIC_ASR_INT) != 0)
191d02e022dStsutsui 				GET_SBIC_csr(sc, csr);
192d02e022dStsutsui 		}
193d02e022dStsutsui 
194d02e022dStsutsui 	} while (sc->sc_state == SBIC_CONNECTED &&
195d02e022dStsutsui 	    (asr & (SBIC_ASR_INT|SBIC_ASR_LCI)) != 0);
196d02e022dStsutsui 
197d02e022dStsutsui 	if (i == SBIC_STATE_DONE) {
198d02e022dStsutsui 		if (sc->sc_status == STATUS_UNKNOWN) {
199d02e022dStsutsui 			printf("wd33c93_go: stat == UNKNOWN\n");
200d02e022dStsutsui 			return 1;
201d02e022dStsutsui 		}
202d02e022dStsutsui 	}
203d02e022dStsutsui 
204d02e022dStsutsui 	if (wd33c93_poll(sc, cbuf, clen, buf, lenp)) {
205d02e022dStsutsui 		wd33c93_timeout(sc, cbuf, clen, buf, lenp);
206d02e022dStsutsui 		if (wd33c93_poll(sc, cbuf, clen, buf, lenp)) {
207d02e022dStsutsui 			wd33c93_timeout(sc, cbuf, clen, buf, lenp);
208d02e022dStsutsui 		}
209d02e022dStsutsui 	}
210d02e022dStsutsui 	return 0;
211d02e022dStsutsui }
212d02e022dStsutsui 
213d02e022dStsutsui /*
214d02e022dStsutsui  * select the bus, return when selected or error.
215d02e022dStsutsui  *
216d02e022dStsutsui  * Returns the current CSR following selection and optionally MSG out phase.
217d02e022dStsutsui  * i.e. the returned CSR *should* indicate CMD phase...
218d02e022dStsutsui  * If the return value is 0, some error happened.
219d02e022dStsutsui  */
220d02e022dStsutsui uint8_t
wd33c93_selectbus(struct wd33c93_softc * sc,uint8_t * cbuf,size_t clen,uint8_t * buf,size_t * lenp)221d02e022dStsutsui wd33c93_selectbus(struct wd33c93_softc *sc, uint8_t *cbuf, size_t clen,
222d02e022dStsutsui     uint8_t *buf, size_t *lenp)
223d02e022dStsutsui {
224d02e022dStsutsui 	uint8_t asr, csr, id, lun, target;
225d02e022dStsutsui 	static int i = 0;
226d02e022dStsutsui 
227d02e022dStsutsui 	sc->sc_state = SBIC_SELECTING;
228d02e022dStsutsui 
229d02e022dStsutsui 	target = sc->sc_target;
230d02e022dStsutsui 	lun = SCSI_LUN;
231d02e022dStsutsui 
232d02e022dStsutsui 	/*
233d02e022dStsutsui 	 * issue select
234d02e022dStsutsui 	 */
235d02e022dStsutsui 	SBIC_TC_PUT(sc, 0);
236d02e022dStsutsui 	SET_SBIC_selid(sc, target);
237d02e022dStsutsui 	SET_SBIC_timeo(sc, SBIC_TIMEOUT(250, SCSI_CLKFREQ));
238d02e022dStsutsui 
239d02e022dStsutsui 	GET_SBIC_asr(sc, asr);
240d02e022dStsutsui 
241d02e022dStsutsui 	if ((asr & (SBIC_ASR_INT|SBIC_ASR_BSY)) != 0) {
242d02e022dStsutsui 		return 0;
243d02e022dStsutsui 	}
244d02e022dStsutsui 
245d02e022dStsutsui 	SET_SBIC_cmd(sc, SBIC_CMD_SEL_ATN);
246d02e022dStsutsui 	WAIT_CIP(sc);
247d02e022dStsutsui 
248d02e022dStsutsui 	/*
249d02e022dStsutsui 	 * wait for select (merged from separate function may need
250d02e022dStsutsui 	 * cleanup)
251d02e022dStsutsui 	 */
252d02e022dStsutsui 	do {
253d02e022dStsutsui 		asr = SBIC_WAIT(sc, SBIC_ASR_INT | SBIC_ASR_LCI, 0);
254d02e022dStsutsui 
255d02e022dStsutsui 		if ((asr & SBIC_ASR_LCI) != 0) {
256d02e022dStsutsui 			return 0;
257d02e022dStsutsui 		}
258d02e022dStsutsui 
259d02e022dStsutsui 		/* Clear interrupt */
260d02e022dStsutsui 		GET_SBIC_csr(sc, csr);
261d02e022dStsutsui 
262d02e022dStsutsui 		/* Reselected from under our feet? */
263d02e022dStsutsui 		if (csr == SBIC_CSR_RSLT_NI || csr == SBIC_CSR_RSLT_IFY) {
264d02e022dStsutsui 			/*
265d02e022dStsutsui 			 * We need to handle this now so we don't lock up later
266d02e022dStsutsui 			 */
267d02e022dStsutsui 			wd33c93_nextstate(sc, cbuf, clen, buf, lenp, csr, asr);
268d02e022dStsutsui 			return 0;
269d02e022dStsutsui 		}
270d02e022dStsutsui 		/* Whoops! */
271d02e022dStsutsui 		if (csr == SBIC_CSR_SLT || csr == SBIC_CSR_SLT_ATN) {
272d02e022dStsutsui 			return 0;
273d02e022dStsutsui 		}
274d02e022dStsutsui 	} while (csr != (SBIC_CSR_MIS_2 | MESG_OUT_PHASE) &&
275d02e022dStsutsui 	    csr != (SBIC_CSR_MIS_2 | CMD_PHASE) &&
276d02e022dStsutsui 	    csr != SBIC_CSR_SEL_TIMEO);
277d02e022dStsutsui 
278d02e022dStsutsui 	/* Anyone at home? */
279d02e022dStsutsui 	if (csr == SBIC_CSR_SEL_TIMEO) {
280d02e022dStsutsui 		return 0;
281d02e022dStsutsui 	}
282d02e022dStsutsui 
283d02e022dStsutsui 	/* Assume we're now selected */
284d02e022dStsutsui 	GET_SBIC_selid(sc, id);
285d02e022dStsutsui 
286d02e022dStsutsui 	if (id != target) {
287d02e022dStsutsui 		/* Something went wrong - wrong target was select */
288d02e022dStsutsui 		printf("wd33c93_selectbus: wrong target selected WANTED %d GOT %d \n",
289d02e022dStsutsui 		    target, id);
290d02e022dStsutsui 		printf("Boot failed!  Halting...\n");
291d02e022dStsutsui 		reboot();
292d02e022dStsutsui 	}
293d02e022dStsutsui 
294d02e022dStsutsui 	sc->sc_flags |= SBICF_SELECTED;
295d02e022dStsutsui 	sc->sc_state  = SBIC_CONNECTED;
296d02e022dStsutsui 
297d02e022dStsutsui 	/* setup correct sync mode for this target */
298d02e022dStsutsui 	wd33c93_setsync(sc);
299d02e022dStsutsui 	SET_SBIC_rselid(sc, SBIC_RID_ER);
300d02e022dStsutsui 
301d02e022dStsutsui 	/*
302d02e022dStsutsui 	 * We only really need to do anything when the target goes to MSG out
303d02e022dStsutsui 	 * If the device ignored ATN, it's probably old and brain-dead,
304d02e022dStsutsui 	 * but we'll try to support it anyhow.
305*100a3398Sandvar 	 * If it doesn't support message out, it definitely doesn't
306d02e022dStsutsui 	 * support synchronous transfers, so no point in even asking...
307d02e022dStsutsui 	 */
308d02e022dStsutsui 
309d02e022dStsutsui 	if (csr == (SBIC_CSR_MIS_2 | MESG_OUT_PHASE)) {
310d02e022dStsutsui 		if (i < 6) {
311d02e022dStsutsui 			SEND_BYTE(sc, MSG_IDENTIFY(lun, 0));
312d02e022dStsutsui 			DELAY(200000);
313d02e022dStsutsui 			i++;
314d02e022dStsutsui 		} else {
315d02e022dStsutsui 			/*
316d02e022dStsutsui 		 	 * setup scsi message sync message request
317d02e022dStsutsui 		 	 */
318d02e022dStsutsui 			sc->sc_omsg[0] = MSG_IDENTIFY(lun, 0);
319d02e022dStsutsui 			sc->sc_omsg[1] = MSG_EXTENDED;
320d02e022dStsutsui 			sc->sc_omsg[2] = MSG_EXT_SDTR_LEN;
321d02e022dStsutsui 			sc->sc_omsg[3] = MSG_EXT_SDTR;
322d02e022dStsutsui 			sc->sc_omsg[4] = sc->sc_syncperiods;
323d02e022dStsutsui 			sc->sc_omsg[5] = SBIC_SYN_93AB_MAX_OFFSET;
324d02e022dStsutsui 
325d02e022dStsutsui 			size_t foo = 6;
326d02e022dStsutsui 			size_t *bar;
327d02e022dStsutsui 			bar = &foo;
328d02e022dStsutsui 
329d02e022dStsutsui 			wd33c93_xfout(sc, sc->sc_omsg, bar);
330d02e022dStsutsui 			sc->sc_flags  |= SBICF_SYNCNEGO;
331d02e022dStsutsui 		}
332d02e022dStsutsui 
333d02e022dStsutsui 		SBIC_WAIT(sc, SBIC_ASR_INT , 0);
334d02e022dStsutsui 		GET_SBIC_csr(sc, csr);
335d02e022dStsutsui 	}
336d02e022dStsutsui 	return csr;
337d02e022dStsutsui }
338d02e022dStsutsui 
339d02e022dStsutsui /*
340d02e022dStsutsui  * Setup sync mode for given target
341d02e022dStsutsui  */
342d02e022dStsutsui void
wd33c93_setsync(struct wd33c93_softc * sc)343d02e022dStsutsui wd33c93_setsync(struct wd33c93_softc *sc)
344d02e022dStsutsui {
345d02e022dStsutsui 	uint8_t syncreg;
346d02e022dStsutsui 
347d02e022dStsutsui 	syncreg = SBIC_SYN(0, 0, 0);
348d02e022dStsutsui 
349d02e022dStsutsui 	SET_SBIC_syn(sc, syncreg);
350d02e022dStsutsui }
351d02e022dStsutsui 
352d02e022dStsutsui /*
353d02e022dStsutsui  * wd33c93_nextstate()
354d02e022dStsutsui  * return:
355d02e022dStsutsui  *	SBIC_STATE_DONE		== done
356d02e022dStsutsui  *	SBIC_STATE_RUNNING	== working
357d02e022dStsutsui  *	SBIC_STATE_DISCONNECT	== disconnected
358d02e022dStsutsui  *	SBIC_STATE_ERROR	== error
359d02e022dStsutsui  */
360d02e022dStsutsui int
wd33c93_nextstate(struct wd33c93_softc * sc,uint8_t * cbuf,size_t clen,uint8_t * buf,size_t * lenp,uint8_t csr,uint8_t asr)361d02e022dStsutsui wd33c93_nextstate(struct wd33c93_softc *sc, uint8_t *cbuf, size_t clen,
362d02e022dStsutsui     uint8_t *buf, size_t *lenp, uint8_t csr, uint8_t asr)
363d02e022dStsutsui {
364d02e022dStsutsui 	size_t *clenp;
365d02e022dStsutsui 	size_t resid;
366d02e022dStsutsui 
367d02e022dStsutsui 	switch (csr) {
368d02e022dStsutsui 	case SBIC_CSR_XFERRED | CMD_PHASE:
369d02e022dStsutsui 	case SBIC_CSR_MIS     | CMD_PHASE:
370d02e022dStsutsui 	case SBIC_CSR_MIS_1   | CMD_PHASE:
371d02e022dStsutsui 	case SBIC_CSR_MIS_2   | CMD_PHASE:
372d02e022dStsutsui 		clenp = &clen;
373d02e022dStsutsui 
374d02e022dStsutsui 		if (wd33c93_xfout(sc, cbuf, clenp))
375d02e022dStsutsui 			goto abort;
376d02e022dStsutsui 		break;
377d02e022dStsutsui 
378d02e022dStsutsui 	case SBIC_CSR_XFERRED | STATUS_PHASE:
379d02e022dStsutsui 	case SBIC_CSR_MIS     | STATUS_PHASE:
380d02e022dStsutsui 	case SBIC_CSR_MIS_1   | STATUS_PHASE:
381d02e022dStsutsui 	case SBIC_CSR_MIS_2   | STATUS_PHASE:
382d02e022dStsutsui 		SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
383d02e022dStsutsui 
384d02e022dStsutsui 		/*
385d02e022dStsutsui 		 * this should be the normal i/o completion case.
386d02e022dStsutsui 		 * get the status & cmd complete msg then let the
387d02e022dStsutsui 		 * device driver look at what happened.
388d02e022dStsutsui 		 */
389d02e022dStsutsui 		wd33c93_xferdone(sc);
390d02e022dStsutsui 		wd33c93_scsidone(sc);
391d02e022dStsutsui 
392d02e022dStsutsui 		return SBIC_STATE_DONE;
393d02e022dStsutsui 
394d02e022dStsutsui 	case SBIC_CSR_XFERRED | DATA_IN_PHASE:
395d02e022dStsutsui 	case SBIC_CSR_MIS     | DATA_IN_PHASE:
396d02e022dStsutsui 	case SBIC_CSR_MIS_1   | DATA_IN_PHASE:
397d02e022dStsutsui 	case SBIC_CSR_MIS_2   | DATA_IN_PHASE:
398d02e022dStsutsui 	case SBIC_CSR_XFERRED | DATA_OUT_PHASE:
399d02e022dStsutsui 	case SBIC_CSR_MIS     | DATA_OUT_PHASE:
400d02e022dStsutsui 	case SBIC_CSR_MIS_1   | DATA_OUT_PHASE:
401d02e022dStsutsui 	case SBIC_CSR_MIS_2   | DATA_OUT_PHASE:
402d02e022dStsutsui 		/*
403d02e022dStsutsui 		 * Should we transfer using PIO or DMA ?
404d02e022dStsutsui 		 */
405*100a3398Sandvar 		/* Perform transfer using PIO */
406d02e022dStsutsui 		if (SBIC_PHASE(csr) == DATA_IN_PHASE){
407d02e022dStsutsui 			/* data in */
408d02e022dStsutsui 			resid = wd33c93_xfin(sc, buf, lenp);
409d02e022dStsutsui 			*lenp = resid;
410d02e022dStsutsui 			wd33c93_intr(sc, cbuf, clen, buf, lenp);
411d02e022dStsutsui 		} else {	/* data out */
412d02e022dStsutsui 			resid = wd33c93_xfout(sc, buf, lenp);
413d02e022dStsutsui 			*lenp = resid;
414d02e022dStsutsui 		}
415d02e022dStsutsui 		break;
416d02e022dStsutsui 
417d02e022dStsutsui 	case SBIC_CSR_XFERRED | MESG_IN_PHASE:
418d02e022dStsutsui 	case SBIC_CSR_MIS     | MESG_IN_PHASE:
419d02e022dStsutsui 	case SBIC_CSR_MIS_1   | MESG_IN_PHASE:
420d02e022dStsutsui 	case SBIC_CSR_MIS_2   | MESG_IN_PHASE:
421d02e022dStsutsui 		/* Handle a single message in... */
422d02e022dStsutsui 		return wd33c93_msgin_phase(sc);
423d02e022dStsutsui 
424d02e022dStsutsui 	case SBIC_CSR_MSGIN_W_ACK:
425d02e022dStsutsui 		/*
426d02e022dStsutsui 		 * We should never see this since it's handled in
427d02e022dStsutsui 		 * 'wd33c93_msgin_phase()' but just for the sake of paranoia...
428d02e022dStsutsui 		 */
429d02e022dStsutsui 		SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK);
430d02e022dStsutsui 		break;
431d02e022dStsutsui 
432d02e022dStsutsui 	case SBIC_CSR_XFERRED | MESG_OUT_PHASE:
433d02e022dStsutsui 	case SBIC_CSR_MIS     | MESG_OUT_PHASE:
434d02e022dStsutsui 	case SBIC_CSR_MIS_1   | MESG_OUT_PHASE:
435d02e022dStsutsui 	case SBIC_CSR_MIS_2   | MESG_OUT_PHASE:
436d02e022dStsutsui 		/*
437d02e022dStsutsui 		 * Message out phase.  ATN signal has been asserted
438d02e022dStsutsui 		 */
439d02e022dStsutsui 		return SBIC_STATE_RUNNING;
440d02e022dStsutsui 
441d02e022dStsutsui 	case SBIC_CSR_DISC:
442d02e022dStsutsui 	case SBIC_CSR_DISC_1:
443d02e022dStsutsui 		sc->sc_state = SBIC_IDLE;
444d02e022dStsutsui 		sc->sc_flags = 0;
445d02e022dStsutsui 
446d02e022dStsutsui 		return SBIC_STATE_DISCONNECT;
447d02e022dStsutsui 
448d02e022dStsutsui 	case SBIC_CSR_RSLT_NI:
449d02e022dStsutsui 	case SBIC_CSR_RSLT_IFY:
450d02e022dStsutsui 	{
451d02e022dStsutsui 		sc->sc_state = SBIC_RESELECTED;
452d02e022dStsutsui 
453d02e022dStsutsui 		if (csr == SBIC_CSR_RSLT_IFY)
454d02e022dStsutsui 			SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK);
455d02e022dStsutsui 		break;
456d02e022dStsutsui 	}
457d02e022dStsutsui 
458d02e022dStsutsui 	default:
459d02e022dStsutsui 	abort:
460d02e022dStsutsui 		/* Something unexpected happend -- deal with it. */
461d02e022dStsutsui 		printf("wd33c93_nextstate:abort\n");
462d02e022dStsutsui 		printf("Boot failed!  Halting...\n");
463d02e022dStsutsui 		reboot();
464d02e022dStsutsui 	}
465d02e022dStsutsui 	return SBIC_STATE_RUNNING;
466d02e022dStsutsui }
467d02e022dStsutsui 
468d02e022dStsutsui /*
469d02e022dStsutsui  * Information Transfer *to* a SCSI Target.
470d02e022dStsutsui  *
471d02e022dStsutsui  * Note: Don't expect there to be an interrupt immediately after all
472d02e022dStsutsui  * the data is transferred out. The WD spec sheet says that the Transfer-
473d02e022dStsutsui  * Info command for non-MSG_IN phases only completes when the target
474d02e022dStsutsui  * next asserts 'REQ'. That is, when the SCSI bus changes to a new state.
475d02e022dStsutsui  *
476d02e022dStsutsui  * This can have a nasty effect on commands which take a relatively long
477d02e022dStsutsui  * time to complete, for example a START/STOP unit command may remain in
478d02e022dStsutsui  * CMD phase until the disk has spun up. Only then will the target change
479d02e022dStsutsui  * to STATUS phase. This is really only a problem for immediate commands
480d02e022dStsutsui  * since we don't allow disconnection for them (yet).
481d02e022dStsutsui  */
482d02e022dStsutsui size_t
wd33c93_xfout(struct wd33c93_softc * sc,void * bp,size_t * lenp)483d02e022dStsutsui wd33c93_xfout(struct wd33c93_softc *sc, void *bp, size_t *lenp)
484d02e022dStsutsui {
485d02e022dStsutsui 
486d02e022dStsutsui 	int wait = wd33c93_data_wait;
487d02e022dStsutsui 	uint8_t asr, *buf = bp;
488d02e022dStsutsui 	size_t len = *lenp;
489d02e022dStsutsui 
490d02e022dStsutsui 	/*
491d02e022dStsutsui 	 * sigh.. WD-PROTO strikes again.. sending the command in one go
492d02e022dStsutsui 	 * causes the chip to lock up if talking to certain (misbehaving?)
493d02e022dStsutsui 	 * targets. Anyway, this procedure should work for all targets, but
494d02e022dStsutsui 	 * it's slightly slower due to the overhead
495d02e022dStsutsui 	 */
496d02e022dStsutsui 
497d02e022dStsutsui 	SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
498d02e022dStsutsui 	SBIC_TC_PUT(sc, (unsigned int)len);
499d02e022dStsutsui 
500d02e022dStsutsui 	WAIT_CIP(sc);
501d02e022dStsutsui 	SET_SBIC_cmd(sc, SBIC_CMD_XFER_INFO);
502d02e022dStsutsui 
503d02e022dStsutsui 	/*
504d02e022dStsutsui 	 * Loop for each byte transferred
505d02e022dStsutsui 	 */
506d02e022dStsutsui 	do {
507d02e022dStsutsui 		GET_SBIC_asr(sc, asr);
508d02e022dStsutsui 
509d02e022dStsutsui 		if ((asr & SBIC_ASR_DBR) != 0) {
510d02e022dStsutsui 			if (len != 0) {
511d02e022dStsutsui 				SET_SBIC_data(sc, *buf);
512d02e022dStsutsui 				buf++;
513d02e022dStsutsui 				len--;
514d02e022dStsutsui 			} else {
515d02e022dStsutsui 				SET_SBIC_data(sc, 0);
516d02e022dStsutsui 			}
517d02e022dStsutsui 			wait = wd33c93_data_wait;
518d02e022dStsutsui 		}
519d02e022dStsutsui 	} while (len != 0 && (asr & SBIC_ASR_INT) == 0 && wait-- > 0);
520d02e022dStsutsui 
521d02e022dStsutsui 	/*
522d02e022dStsutsui 	 * Normally, an interrupt will be pending when this routing returns.
523d02e022dStsutsui 	 */
524d02e022dStsutsui 	return len;
525d02e022dStsutsui }
526d02e022dStsutsui 
527d02e022dStsutsui int
wd33c93_intr(struct wd33c93_softc * sc,uint8_t * cbuf,size_t clen,uint8_t * buf,size_t * lenp)528d02e022dStsutsui wd33c93_intr(struct wd33c93_softc *sc, uint8_t *cbuf, size_t clen,
529d02e022dStsutsui     uint8_t *buf, size_t *lenp)
530d02e022dStsutsui {
531d02e022dStsutsui 	uint8_t	asr, csr;
532d02e022dStsutsui 
533d02e022dStsutsui 	/*
534d02e022dStsutsui 	 * pending interrupt?
535d02e022dStsutsui 	 */
536d02e022dStsutsui 	GET_SBIC_asr(sc, asr);
537d02e022dStsutsui 	if ((asr & SBIC_ASR_INT) == 0)
538d02e022dStsutsui 		return 0;
539d02e022dStsutsui 
540d02e022dStsutsui 	GET_SBIC_csr(sc, csr);
541d02e022dStsutsui 
542d02e022dStsutsui 	do {
543d02e022dStsutsui 
544d02e022dStsutsui 		(void)wd33c93_nextstate(sc, cbuf, clen, buf, lenp, csr, asr);
545d02e022dStsutsui 		WAIT_CIP(sc);
546d02e022dStsutsui 		if (sc->sc_state == SBIC_CONNECTED) {
547d02e022dStsutsui 			GET_SBIC_asr(sc, asr);
548d02e022dStsutsui 
549d02e022dStsutsui 			if ((asr & SBIC_ASR_INT) != 0)
550d02e022dStsutsui 				GET_SBIC_csr(sc, csr);
551d02e022dStsutsui 		}
552d02e022dStsutsui 	} while (sc->sc_state == SBIC_CONNECTED &&
553d02e022dStsutsui 	    (asr & (SBIC_ASR_INT|SBIC_ASR_LCI)) != 0);
554d02e022dStsutsui 
555d02e022dStsutsui 	return 1;
556d02e022dStsutsui }
557d02e022dStsutsui 
558d02e022dStsutsui /*
559d02e022dStsutsui  * Information Transfer *from* a Scsi Target
560d02e022dStsutsui  * returns # bytes left to read
561d02e022dStsutsui  */
562d02e022dStsutsui size_t
wd33c93_xfin(struct wd33c93_softc * sc,void * bp,size_t * lenp)563d02e022dStsutsui wd33c93_xfin(struct wd33c93_softc *sc, void *bp, size_t *lenp)
564d02e022dStsutsui {
565d02e022dStsutsui 	size_t len = *lenp;
566d02e022dStsutsui 
567d02e022dStsutsui 	int 	wait = wd33c93_data_wait;
568d02e022dStsutsui 	uint8_t	*buf = bp;
569d02e022dStsutsui 	uint8_t	asr;
570d02e022dStsutsui 
571d02e022dStsutsui 	SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
572d02e022dStsutsui 	SBIC_TC_PUT(sc, (unsigned int)len);
573d02e022dStsutsui 
574d02e022dStsutsui 	WAIT_CIP(sc);
575d02e022dStsutsui 	SET_SBIC_cmd(sc, SBIC_CMD_XFER_INFO);
576d02e022dStsutsui 
577d02e022dStsutsui 	/*
578d02e022dStsutsui 	 * Loop for each byte transferred
579d02e022dStsutsui 	 */
580d02e022dStsutsui 	do {
581d02e022dStsutsui 		GET_SBIC_asr(sc, asr);
582d02e022dStsutsui 
583d02e022dStsutsui 		if ((asr & SBIC_ASR_DBR) != 0) {
584d02e022dStsutsui 			if (len != 0) {
585d02e022dStsutsui 				GET_SBIC_data(sc, *buf);
586d02e022dStsutsui 				buf++;
587d02e022dStsutsui 				len--;
588d02e022dStsutsui 			} else {
589d02e022dStsutsui 				uint8_t foo;
590d02e022dStsutsui 				GET_SBIC_data(sc, foo);
591d02e022dStsutsui 				__USE(foo);
592d02e022dStsutsui 			}
593d02e022dStsutsui 			wait = wd33c93_data_wait;
594d02e022dStsutsui 		}
595d02e022dStsutsui 
596d02e022dStsutsui 	} while ((asr & SBIC_ASR_INT) == 0 && wait-- > 0);
597d02e022dStsutsui 
598d02e022dStsutsui 	SBIC_TC_PUT(sc, 0);
599d02e022dStsutsui 
600d02e022dStsutsui 	/*
601d02e022dStsutsui 	 * this leaves with one csr to be read
602d02e022dStsutsui 	 */
603d02e022dStsutsui 	return len;
604d02e022dStsutsui }
605d02e022dStsutsui 
606d02e022dStsutsui /*
607d02e022dStsutsui  * Finish SCSI xfer command:  After the completion interrupt from
608d02e022dStsutsui  * a read/write operation, sequence through the final phases in
609d02e022dStsutsui  * programmed i/o.
610d02e022dStsutsui  */
611d02e022dStsutsui void
wd33c93_xferdone(struct wd33c93_softc * sc)612d02e022dStsutsui wd33c93_xferdone(struct wd33c93_softc *sc)
613d02e022dStsutsui {
614d02e022dStsutsui 	uint8_t	phase, csr;
615d02e022dStsutsui 
616d02e022dStsutsui 	/*
617d02e022dStsutsui 	 * have the wd33c93 complete on its own
618d02e022dStsutsui 	 */
619d02e022dStsutsui 	SBIC_TC_PUT(sc, 0);
620d02e022dStsutsui 	SET_SBIC_cmd_phase(sc, 0x46);
621d02e022dStsutsui 	SET_SBIC_cmd(sc, SBIC_CMD_SEL_ATN_XFER);
622d02e022dStsutsui 
623d02e022dStsutsui 	do {
624d02e022dStsutsui 		SBIC_WAIT(sc, SBIC_ASR_INT, 0);
625d02e022dStsutsui 		GET_SBIC_csr(sc, csr);
626d02e022dStsutsui 	} while ((csr != SBIC_CSR_DISC) &&
627d02e022dStsutsui 		 (csr != SBIC_CSR_DISC_1) &&
628d02e022dStsutsui 		 (csr != SBIC_CSR_S_XFERRED));
629d02e022dStsutsui 
630d02e022dStsutsui 	sc->sc_flags &= ~SBICF_SELECTED;
631d02e022dStsutsui 	sc->sc_state = SBIC_DISCONNECT;
632d02e022dStsutsui 
633d02e022dStsutsui 	GET_SBIC_cmd_phase(sc, phase);
634d02e022dStsutsui 
635d02e022dStsutsui 	if (phase == 0x60)
636d02e022dStsutsui 		GET_SBIC_tlun(sc, sc->sc_status);
637d02e022dStsutsui 	else
638d02e022dStsutsui 		wd33c93_error(sc);
639d02e022dStsutsui }
640d02e022dStsutsui 
641d02e022dStsutsui int
wd33c93_abort(struct wd33c93_softc * sc,uint8_t * cbuf,size_t clen,uint8_t * buf,size_t * lenp)642d02e022dStsutsui wd33c93_abort(struct wd33c93_softc *sc, uint8_t *cbuf, size_t clen,
643d02e022dStsutsui     uint8_t *buf, size_t *lenp)
644d02e022dStsutsui {
645d02e022dStsutsui 	uint8_t csr, asr;
646d02e022dStsutsui 
647d02e022dStsutsui 	GET_SBIC_asr(sc, asr);
648d02e022dStsutsui 	GET_SBIC_csr(sc, csr);
649d02e022dStsutsui 
650d02e022dStsutsui 	/*
651d02e022dStsutsui 	 * Clean up chip itself
652d02e022dStsutsui 	 */
653d02e022dStsutsui 	wd33c93_timeout(sc, cbuf, clen, buf, lenp);
654d02e022dStsutsui 
655d02e022dStsutsui 	while ((asr & SBIC_ASR_DBR) != 0) {
656d02e022dStsutsui 		/*
657d02e022dStsutsui 		 * wd33c93 is jammed w/data. need to clear it
658d02e022dStsutsui 		 * But we don't know what direction it needs to go
659d02e022dStsutsui 		 */
660d02e022dStsutsui 		GET_SBIC_data(sc, asr);
661d02e022dStsutsui 		GET_SBIC_asr(sc, asr);
662d02e022dStsutsui 		if ((asr & SBIC_ASR_DBR) != 0)
663d02e022dStsutsui 			 /* Not the read direction */
664d02e022dStsutsui 			SET_SBIC_data(sc, asr);
665d02e022dStsutsui 		GET_SBIC_asr(sc, asr);
666d02e022dStsutsui 	}
667d02e022dStsutsui 
668d02e022dStsutsui 	WAIT_CIP(sc);
669d02e022dStsutsui 	SET_SBIC_cmd(sc, SBIC_CMD_ABORT);
670d02e022dStsutsui 	WAIT_CIP(sc);
671d02e022dStsutsui 
672d02e022dStsutsui 	GET_SBIC_asr(sc, asr);
673d02e022dStsutsui 
674d02e022dStsutsui 	if ((asr & (SBIC_ASR_BSY|SBIC_ASR_LCI)) != 0) {
675d02e022dStsutsui 		/*
676d02e022dStsutsui 		 * ok, get more drastic..
677d02e022dStsutsui 		 */
678d02e022dStsutsui 		wd33c93_reset(sc);
679d02e022dStsutsui 	} else {
680d02e022dStsutsui 		SET_SBIC_cmd(sc, SBIC_CMD_DISC);
681d02e022dStsutsui 		WAIT_CIP(sc);
682d02e022dStsutsui 
683d02e022dStsutsui 		do {
684d02e022dStsutsui 			SBIC_WAIT(sc, SBIC_ASR_INT, 0);
685d02e022dStsutsui 			GET_SBIC_asr(sc, asr);
686d02e022dStsutsui 			GET_SBIC_csr(sc, csr);
687d02e022dStsutsui 		} while ((csr != SBIC_CSR_DISC) &&
688d02e022dStsutsui 		    (csr != SBIC_CSR_DISC_1) &&
689d02e022dStsutsui 		    (csr != SBIC_CSR_CMD_INVALID));
690d02e022dStsutsui 
691d02e022dStsutsui 	sc->sc_state = SBIC_ERROR;
692d02e022dStsutsui 	sc->sc_flags = 0;
693d02e022dStsutsui 	}
694d02e022dStsutsui 	return SBIC_STATE_ERROR;
695d02e022dStsutsui }
696d02e022dStsutsui 
697d02e022dStsutsui void
wd33c93_timeout(struct wd33c93_softc * sc,uint8_t * cbuf,size_t clen,uint8_t * buf,size_t * lenp)698d02e022dStsutsui wd33c93_timeout(struct wd33c93_softc *sc, uint8_t *cbuf, size_t clen,
699d02e022dStsutsui     uint8_t *buf, size_t *lenp)
700d02e022dStsutsui {
701d02e022dStsutsui 	uint8_t asr;
702d02e022dStsutsui 
703d02e022dStsutsui 	GET_SBIC_asr(sc, asr);
704d02e022dStsutsui 
705d02e022dStsutsui 	if ((asr & SBIC_ASR_INT) != 0) {
706d02e022dStsutsui 		/* We need to service a missed IRQ */
707d02e022dStsutsui 		wd33c93_intr(sc, cbuf, clen, buf, lenp);
708d02e022dStsutsui 	} else {
709d02e022dStsutsui 		wd33c93_abort(sc, cbuf, clen, buf, lenp);
710d02e022dStsutsui 	}
711d02e022dStsutsui }
712d02e022dStsutsui 
713d02e022dStsutsui /*
714d02e022dStsutsui  * Complete current command using polled I/O.Used when interrupt driven
715d02e022dStsutsui  * I/O is not allowed (ie. during boot and shutdown)
716d02e022dStsutsui  *
717d02e022dStsutsui  * Polled I/O is very processor intensive
718d02e022dStsutsui  */
719d02e022dStsutsui int
wd33c93_poll(struct wd33c93_softc * sc,uint8_t * cbuf,size_t clen,uint8_t * buf,size_t * lenp)720d02e022dStsutsui wd33c93_poll(struct wd33c93_softc *sc, uint8_t *cbuf, size_t clen,
721d02e022dStsutsui     uint8_t *buf, size_t *lenp)
722d02e022dStsutsui {
723d02e022dStsutsui 	uint8_t	asr, csr = 0;
724d02e022dStsutsui 	int	count;
725d02e022dStsutsui 
726d02e022dStsutsui 	SBIC_WAIT(sc, SBIC_ASR_INT, wd33c93_cmd_wait);
727d02e022dStsutsui 	for (count = SBIC_ABORT_TIMEOUT; count;) {
728d02e022dStsutsui 		GET_SBIC_asr(sc, asr);
729d02e022dStsutsui 		if ((asr & SBIC_ASR_LCI) != 0)
730d02e022dStsutsui 			DELAY(5000);
731d02e022dStsutsui 
732d02e022dStsutsui 		if ((asr & SBIC_ASR_INT) != 0) {
733d02e022dStsutsui 			GET_SBIC_csr(sc, csr);
734d02e022dStsutsui 			(void)wd33c93_nextstate(sc, cbuf, clen, buf, lenp, csr,
735d02e022dStsutsui 			    asr);
736d02e022dStsutsui 			WAIT_CIP(sc);
737d02e022dStsutsui 		} else {
738d02e022dStsutsui 			DELAY(5000);
739d02e022dStsutsui 			count--;
740d02e022dStsutsui 		}
741d02e022dStsutsui 
742d02e022dStsutsui 		if ((sc->xs_status & XS_STS_DONE) != 0)
743d02e022dStsutsui 			return 0;
744d02e022dStsutsui 	}
745d02e022dStsutsui 	return 1;
746d02e022dStsutsui }
747d02e022dStsutsui 
748d02e022dStsutsui static inline int
__verify_msg_format(uint8_t * p,int len)749d02e022dStsutsui __verify_msg_format(uint8_t *p, int len)
750d02e022dStsutsui {
751d02e022dStsutsui 
752d02e022dStsutsui 	if (len == 1 && MSG_IS1BYTE(p[0]))
753d02e022dStsutsui 		return 1;
754d02e022dStsutsui 	if (len == 2 && MSG_IS2BYTE(p[0]))
755d02e022dStsutsui 		return 1;
756d02e022dStsutsui 	if (len >= 3 && MSG_ISEXTENDED(p[0]) &&
757d02e022dStsutsui 	    len == p[1] + 2)
758d02e022dStsutsui 		return 1;
759d02e022dStsutsui 	return 0;
760d02e022dStsutsui }
761d02e022dStsutsui 
762d02e022dStsutsui /*
763d02e022dStsutsui  * Handle message_in phase
764d02e022dStsutsui  */
765d02e022dStsutsui int
wd33c93_msgin_phase(struct wd33c93_softc * sc)766d02e022dStsutsui wd33c93_msgin_phase(struct wd33c93_softc *sc)
767d02e022dStsutsui {
768d02e022dStsutsui 	int len;
769d02e022dStsutsui 	uint8_t asr, csr, *msg;
770d02e022dStsutsui 
771d02e022dStsutsui 	GET_SBIC_asr(sc, asr);
772d02e022dStsutsui 	__USE(asr);
773d02e022dStsutsui 
774d02e022dStsutsui 	GET_SBIC_selid(sc, csr);
775d02e022dStsutsui 	SET_SBIC_selid(sc, csr | SBIC_SID_FROM_SCSI);
776d02e022dStsutsui 
777d02e022dStsutsui 	SBIC_TC_PUT(sc, 0);
778d02e022dStsutsui 
779d02e022dStsutsui 	SET_SBIC_control(sc, SBIC_CTL_EDI | SBIC_CTL_IDI);
780d02e022dStsutsui 
781d02e022dStsutsui 	msg = sc->sc_imsg;
782d02e022dStsutsui 	len = 0;
783d02e022dStsutsui 
784d02e022dStsutsui 	do {
785d02e022dStsutsui 		/* Fetch the next byte of the message */
786d02e022dStsutsui 		RECV_BYTE(sc, *msg++);
787d02e022dStsutsui 		len++;
788d02e022dStsutsui 
789d02e022dStsutsui 		/*
790d02e022dStsutsui 		 * get the command completion interrupt, or we
791d02e022dStsutsui 		 * can't send a new command (LCI)
792d02e022dStsutsui 		 */
793d02e022dStsutsui 		SBIC_WAIT(sc, SBIC_ASR_INT, 0);
794d02e022dStsutsui 		GET_SBIC_csr(sc, csr);
795d02e022dStsutsui 
796d02e022dStsutsui 		if (__verify_msg_format(sc->sc_imsg, len))
797d02e022dStsutsui 			/* Complete message received */
798d02e022dStsutsui 			break;
799d02e022dStsutsui 
800d02e022dStsutsui 		/*
801d02e022dStsutsui 		 * Clear ACK, and wait for the interrupt
802d02e022dStsutsui 		 * for the next byte or phase change
803d02e022dStsutsui 		 */
804d02e022dStsutsui 		SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK);
805d02e022dStsutsui 		SBIC_WAIT(sc, SBIC_ASR_INT, 0);
806d02e022dStsutsui 
807d02e022dStsutsui 		GET_SBIC_csr(sc, csr);
808d02e022dStsutsui 	} while (len < SBIC_MAX_MSGLEN);
809d02e022dStsutsui 
810d02e022dStsutsui 	/*
811d02e022dStsutsui 	 * Clear ACK, and wait for the interrupt
812d02e022dStsutsui 	 * for the phase change
813d02e022dStsutsui 	 */
814d02e022dStsutsui 	SET_SBIC_cmd(sc, SBIC_CMD_CLR_ACK);
815d02e022dStsutsui 	SBIC_WAIT(sc, SBIC_ASR_INT, 0);
816d02e022dStsutsui 
817d02e022dStsutsui 	/* Should still have one CSR to read */
818d02e022dStsutsui 	return SBIC_STATE_RUNNING;
819d02e022dStsutsui }
820d02e022dStsutsui 
821d02e022dStsutsui void
wd33c93_scsistart(struct wd33c93_softc * sc)822d02e022dStsutsui wd33c93_scsistart(struct wd33c93_softc *sc)
823d02e022dStsutsui {
824d02e022dStsutsui 
825d02e022dStsutsui 	sc->xs_status = 0;
826d02e022dStsutsui }
827d02e022dStsutsui 
828d02e022dStsutsui void
wd33c93_scsidone(struct wd33c93_softc * sc)829d02e022dStsutsui wd33c93_scsidone(struct wd33c93_softc *sc)
830d02e022dStsutsui {
831d02e022dStsutsui 
832d02e022dStsutsui 	sc->xs_status = XS_STS_DONE;
833d02e022dStsutsui }
834d02e022dStsutsui 
835d02e022dStsutsui void
wd33c93_error(struct wd33c93_softc * sc)836d02e022dStsutsui wd33c93_error(struct wd33c93_softc *sc)
837d02e022dStsutsui {
838d02e022dStsutsui }
839