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