]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/ncv/ncr53c500.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / ncv / ncr53c500.c
1 /*      $NecBSD: ncr53c500.c,v 1.30.12.3 2001/06/26 07:31:41 honda Exp $        */
2 /*      $NetBSD$        */
3
4 #define NCV_DEBUG
5 #define NCV_STATICS
6 #define NCV_IO_CONTROL_FLAGS    (0)
7
8 /*-
9  * [NetBSD for NEC PC-98 series]
10  *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
11  *      NetBSD/pc98 porting staff. All rights reserved.
12  *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
13  *      Naofumi HONDA. All rights reserved.
14  * 
15  *  Redistribution and use in source and binary forms, with or without
16  *  modification, are permitted provided that the following conditions
17  *  are met:
18  *  1. Redistributions of source code must retain the above copyright
19  *     notice, this list of conditions and the following disclaimer.
20  *  2. Redistributions in binary form must reproduce the above copyright
21  *     notice, this list of conditions and the following disclaimer in the
22  *     documentation and/or other materials provided with the distribution.
23  *  3. The name of the author may not be used to endorse or promote products
24  *     derived from this software without specific prior written permission.
25  * 
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
30  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #if defined(__FreeBSD__) && __FreeBSD_version >= 500001
46 #include <sys/bio.h>
47 #endif  /* __FreeBSD__ */
48 #include <sys/buf.h>
49 #include <sys/queue.h>
50 #include <sys/malloc.h>
51 #include <sys/errno.h>
52
53 #ifdef __NetBSD__
54 #include <sys/device.h>
55 #include <machine/bus.h>
56 #include <machine/intr.h>
57
58 #include <dev/scsipi/scsi_all.h>
59 #include <dev/scsipi/scsipi_all.h>
60 #include <dev/scsipi/scsiconf.h>
61 #include <dev/scsipi/scsi_disk.h>
62
63 #include <machine/dvcfg.h>
64 #include <machine/physio_proc.h>
65
66 #include <i386/Cbus/dev/scsi_low.h>
67
68 #include <i386/Cbus/dev/ncr53c500reg.h>
69 #include <i386/Cbus/dev/ncr53c500hw.h>
70 #include <i386/Cbus/dev/ncr53c500var.h>
71
72 #include <i386/Cbus/dev/ncr53c500hwtab.h>
73 #endif /* __NetBSD__ */
74
75 #ifdef __FreeBSD__
76 #include <machine/cpu.h>
77 #include <machine/bus.h>
78
79 #include <compat/netbsd/dvcfg.h>
80 #include <compat/netbsd/physio_proc.h>
81
82 #include <cam/scsi/scsi_low.h>
83
84 #include <dev/ncv/ncr53c500reg.h>
85 #include <dev/ncv/ncr53c500hw.h>
86 #include <dev/ncv/ncr53c500var.h>
87
88 #include <dev/ncv/ncr53c500hwtab.h>
89 #endif /* __FreeBSD__ */
90
91 #define NCV_MAX_DATA_SIZE       (64 * 1024)
92 #define NCV_DELAY_MAX           (2 * 1000 * 1000)
93 #define NCV_DELAY_INTERVAL      (1)
94 #define NCV_PADDING_SIZE        (32)
95
96 /***************************************************
97  * IO control
98  ***************************************************/
99 #define NCV_READ_INTERRUPTS_DRIVEN      0x0001
100 #define NCV_WRITE_INTERRUPTS_DRIVEN     0x0002
101 #define NCV_ENABLE_FAST_SCSI            0x0010
102 #define NCV_FAST_INTERRUPTS             0x0100
103
104 u_int ncv_io_control = NCV_IO_CONTROL_FLAGS;
105 int ncv_data_read_bytes = 4096;
106 int ncv_data_write_bytes = 4096;
107
108 /***************************************************
109  * DEBUG
110  ***************************************************/
111 #ifdef  NCV_DEBUG
112 static int ncv_debug;
113 #endif  /* NCV_DEBUG */
114
115 #ifdef  NCV_STATICS
116 static struct ncv_statics {
117         int disconnect;
118         int reselect;
119 } ncv_statics;
120 #endif  /* NCV_STATICS */
121
122 /***************************************************
123  * DEVICE STRUCTURE
124  ***************************************************/
125 extern struct cfdriver ncv_cd;
126
127 /**************************************************************
128  * DECLARE
129  **************************************************************/
130 /* static */
131 static void ncv_pio_read(struct ncv_softc *, u_int8_t *, u_int);
132 static void ncv_pio_write(struct ncv_softc *, u_int8_t *, u_int);
133 static int ncv_msg(struct ncv_softc *, struct targ_info *, u_int);
134 static int ncv_reselected(struct ncv_softc *);
135 static int ncv_disconnected(struct ncv_softc *, struct targ_info *);
136
137 static __inline void ncvhw_set_count(bus_space_tag_t, bus_space_handle_t, int);
138 static __inline u_int ncvhw_get_count(bus_space_tag_t, bus_space_handle_t);
139 static __inline void ncvhw_select_register_0(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
140 static __inline void ncvhw_select_register_1(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
141 static __inline void ncvhw_fpush(bus_space_tag_t, bus_space_handle_t, u_int8_t *, int);
142
143 static void ncv_pdma_end(struct ncv_softc *sc, struct targ_info *);
144 static int ncv_world_start(struct ncv_softc *, int);
145 static void ncvhw_bus_reset(struct ncv_softc *);
146 static void ncvhw_reset(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
147 static int ncvhw_check(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
148 static void ncvhw_init(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
149 static int ncvhw_start_selection(struct ncv_softc *sc, struct slccb *);
150 static void ncvhw_attention(struct ncv_softc *);
151 static int ncv_ccb_nexus_establish(struct ncv_softc *);
152 static int ncv_lun_nexus_establish(struct ncv_softc *);
153 static int ncv_target_nexus_establish(struct ncv_softc *);
154 static int ncv_targ_init(struct ncv_softc *, struct targ_info *, int);
155 static int ncv_catch_intr(struct ncv_softc *);
156 #ifdef  NCV_POWER_CONTROL
157 static int ncvhw_power(struct ncv_softc *, u_int);
158 #endif  /* NCV_POWER_CONTROL */
159 static __inline void ncv_setup_and_start_pio(struct ncv_softc *, u_int);
160
161 struct scsi_low_funcs ncv_funcs = {
162         SC_LOW_INIT_T ncv_world_start,
163         SC_LOW_BUSRST_T ncvhw_bus_reset,
164         SC_LOW_TARG_INIT_T ncv_targ_init,
165         SC_LOW_LUN_INIT_T NULL,
166
167         SC_LOW_SELECT_T ncvhw_start_selection,
168         SC_LOW_NEXUS_T ncv_lun_nexus_establish,
169         SC_LOW_NEXUS_T ncv_ccb_nexus_establish,
170
171         SC_LOW_ATTEN_T ncvhw_attention,
172         SC_LOW_MSG_T ncv_msg,
173
174         SC_LOW_TIMEOUT_T NULL,
175         SC_LOW_POLL_T ncvintr,
176
177         NULL,   /* SC_LOW_POWER_T ncvhw_power, */
178 };
179
180 /**************************************************************
181  * hwfuncs
182  **************************************************************/
183 static __inline void
184 ncvhw_select_register_0(iot, ioh, hw)
185         bus_space_tag_t iot;
186         bus_space_handle_t ioh;
187         struct ncv_hw *hw;
188 {
189
190         bus_space_write_1(iot, ioh, cr0_cfg4, hw->hw_cfg4);
191 }
192
193 static __inline void
194 ncvhw_select_register_1(iot, ioh, hw)
195         bus_space_tag_t iot;
196         bus_space_handle_t ioh;
197         struct ncv_hw *hw;
198 {
199
200         bus_space_write_1(iot, ioh, cr1_cfg5, hw->hw_cfg5);
201 }
202
203 static __inline void
204 ncvhw_fpush(iot, ioh, buf, len)
205         bus_space_tag_t iot;
206         bus_space_handle_t ioh;
207         u_int8_t *buf;
208         int len;
209 {
210         int ptr;
211
212         for (ptr = 0; ptr < len; ptr ++)
213                 bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]);
214 }
215
216 static __inline void
217 ncvhw_set_count(iot, ioh, count)
218         bus_space_tag_t iot;
219         bus_space_handle_t ioh;
220         int count;
221 {
222
223         bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count);
224         bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY));
225         bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2)));
226 }
227
228 static __inline u_int
229 ncvhw_get_count(iot, ioh)
230         bus_space_tag_t iot;
231         bus_space_handle_t ioh;
232 {
233         u_int count;
234
235         count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb);
236         count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY;
237         count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2);
238         return count;
239 }
240
241 static int
242 ncvhw_check(iot, ioh, hw)
243         bus_space_tag_t iot;
244         bus_space_handle_t ioh;
245         struct ncv_hw *hw;
246 {
247         u_int8_t stat;
248
249         ncvhw_select_register_0(iot, ioh, hw);
250         bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
251         if (bus_space_read_1(iot, ioh, cr0_cmd) != (CMD_NOP | CMD_DMA))
252         {
253 #ifdef  NCV_DEBUG
254                 printf("ncv: cr0_cmd CMD_NOP|CMD_DMA failed\n");
255 #endif  /* NCV_DEBUG */
256                 return ENODEV;
257         }
258
259         bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
260         if (bus_space_read_1(iot, ioh, cr0_cmd) != CMD_NOP)
261         {
262 #ifdef  NCV_DEBUG
263                 printf("ncv: cr0_cmd CMD_NOP failed\n");
264 #endif  /* NCV_DEBUG */
265                 return ENODEV;
266         }
267
268         /* hardware reset */
269         ncvhw_reset(iot, ioh, hw);
270         ncvhw_init(iot, ioh, hw);
271
272         /* bus reset */
273         ncvhw_select_register_0(iot, ioh, hw);
274         bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
275         bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI);
276         bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
277         SCSI_LOW_DELAY(100 * 1000);
278
279         /* check response */
280         bus_space_read_1(iot, ioh, cr0_stat);
281         stat = bus_space_read_1(iot, ioh, cr0_istat);
282         SCSI_LOW_DELAY(1000);
283
284         if (((stat & INTR_SBR) == 0) ||
285             (bus_space_read_1(iot, ioh, cr0_istat) & INTR_SBR))
286         {
287 #ifdef  NCV_DEBUG
288                 printf("ncv: cr0_istat SCSI BUS RESET failed\n");
289 #endif  /* NCV_DEBUG */
290                 return ENODEV;
291         }
292
293         return 0;
294 }
295
296 static void
297 ncvhw_reset(iot, ioh, hw)
298         bus_space_tag_t iot;
299         bus_space_handle_t ioh;
300         struct ncv_hw *hw;
301 {
302
303         ncvhw_select_register_0(iot, ioh, hw);
304
305         /* dummy cmd twice */
306         bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
307         bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
308
309         /* chip reset */
310         bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTCHIP);
311
312         /* again dummy cmd twice */
313         bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
314         bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
315 }
316
317 static void
318 ncvhw_init(iot, ioh, hw)
319         bus_space_tag_t iot;
320         bus_space_handle_t ioh;
321         struct ncv_hw *hw;
322 {
323
324         ncvhw_select_register_0(iot, ioh, hw);
325         bus_space_write_1(iot, ioh, cr0_clk, hw->hw_clk);
326         bus_space_write_1(iot, ioh, cr0_srtout, SEL_TOUT);
327         bus_space_write_1(iot, ioh, cr0_period, 0);
328         bus_space_write_1(iot, ioh, cr0_offs, 0);
329
330         bus_space_write_1(iot, ioh, cr0_cfg1, hw->hw_cfg1);
331         bus_space_write_1(iot, ioh, cr0_cfg2, hw->hw_cfg2);
332         bus_space_write_1(iot, ioh, cr0_cfg3, hw->hw_cfg3);
333         bus_space_write_1(iot, ioh, cr0_tchsb, 0);
334
335         ncvhw_select_register_1(iot, ioh, hw);
336         bus_space_write_1(iot, ioh, cr1_fstat, 0x0);
337         bus_space_write_1(iot, ioh, cr1_pflag, 0x0);
338         bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE);
339
340         ncvhw_select_register_0(iot, ioh, hw);
341 }
342
343 #ifdef  NCV_POWER_CONTROL
344 static int
345 ncvhw_power(sc, flags)
346         struct ncv_softc *sc;
347         u_int flags;
348 {
349         struct scsi_low_softc *slp = &sc->sc_sclow;
350         bus_space_tag_t iot = sc->sc_iot;
351         bus_space_handle_t ioh = sc->sc_ioh;
352
353         if (flags == SCSI_LOW_POWDOWN)
354         {
355                 printf("%s power down\n", slp->sl_xname);
356                 ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
357                 bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_POWDOWN);
358         }
359         else
360         {
361                 switch (sc->sc_rstep)
362                 {
363                 case 0:
364                         printf("%s resume step O\n", slp->sl_xname);
365                         ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
366                         bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE);
367                         break;
368
369                 case 1:
370                         printf("%s resume step I\n", slp->sl_xname);
371                         ncvhw_reset(iot, ioh, &sc->sc_hw);
372                         ncvhw_init(iot, ioh, &sc->sc_hw);
373                         break;
374                 }
375         }
376
377         return 0;
378 }
379 #endif  /* NCV_POWER_CONTROL */
380
381 /**************************************************************
382  * scsi low interface
383  **************************************************************/
384 static void
385 ncvhw_attention(sc)
386         struct ncv_softc *sc;
387 {
388
389         bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, CMD_SETATN);
390         SCSI_LOW_DELAY(10);
391 }
392
393 static void
394 ncvhw_bus_reset(sc)
395         struct ncv_softc *sc;
396 {
397         bus_space_tag_t iot = sc->sc_iot;
398         bus_space_handle_t ioh = sc->sc_ioh;
399
400         ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
401         bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
402         bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI);
403         bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
404 }
405
406 static int
407 ncvhw_start_selection(sc, cb)
408         struct ncv_softc *sc;
409         struct slccb *cb;
410 {
411         struct scsi_low_softc *slp = &sc->sc_sclow;
412         bus_space_tag_t iot = sc->sc_iot;
413         bus_space_handle_t ioh = sc->sc_ioh;
414         struct targ_info *ti = cb->ti;
415         int s, len;
416         u_int flags;
417         u_int8_t cmd;
418
419         sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
420         sc->sc_compseq = 0;
421         if (scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0)
422         {
423                 cmd = CMD_SELATN;
424                 sc->sc_selstop = 0;
425                 flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
426         }
427         else if (scsi_low_is_msgout_continue(ti, 
428                         SCSI_LOW_MSG_IDENTIFY | SCSI_LOW_MSG_SIMPLE_QTAG) == 0)
429         {
430                 cmd = CMD_SELATN3;
431                 sc->sc_selstop = 0;
432                 flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
433         }       
434         else
435         {
436                 cmd = CMD_SELATNS;
437                 sc->sc_selstop = 1;
438                 flags = SCSI_LOW_MSGOUT_INIT;
439         }
440
441         ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
442         if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0)
443                 return SCSI_LOW_START_FAIL;
444
445         ncv_target_nexus_establish(sc);
446
447         len = scsi_low_msgout(slp, ti, flags);
448         if (sc->sc_selstop == 0)
449                 scsi_low_cmd(slp, ti);
450
451         s = splhigh();
452         if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0)
453         {
454                 splx(s);
455                 return SCSI_LOW_START_FAIL;
456         }
457
458         bus_space_write_1(iot, ioh, cr0_dstid, ti->ti_id);
459         bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
460         ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len);
461         if (sc->sc_selstop == 0)
462         {
463                 ncvhw_fpush(iot, ioh,
464                             slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
465         }
466         bus_space_write_1(iot, ioh, cr0_cmd, cmd);
467         splx(s);
468
469         SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
470         return SCSI_LOW_START_OK;
471 }
472
473 static int
474 ncv_world_start(sc, fdone)
475         struct ncv_softc *sc;
476         int fdone;
477 {
478         struct scsi_low_softc *slp = &sc->sc_sclow;
479         bus_space_tag_t iot = sc->sc_iot;
480         bus_space_handle_t ioh = sc->sc_ioh;
481         u_int8_t stat;
482
483         if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
484                 sc->sc_hw.hw_cfg1 |= C1_PARENB;
485         else
486                 sc->sc_hw.hw_cfg1 &= ~C1_PARENB;
487
488         ncvhw_reset(iot, ioh, &sc->sc_hw);
489         ncvhw_init(iot, ioh, &sc->sc_hw);
490
491         scsi_low_bus_reset(slp);
492
493         ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
494         bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat);
495         stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat);
496         SCSI_LOW_DELAY(1000);
497
498         if (((stat & INTR_SBR) == 0) ||
499             (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR))
500                 return ENODEV;
501
502         SOFT_INTR_REQUIRED(slp);
503         return 0;
504 }
505
506 static int
507 ncv_msg(sc, ti, msg)
508         struct ncv_softc *sc;
509         struct targ_info *ti;
510         u_int msg;
511 {
512         bus_space_tag_t iot = sc->sc_iot;
513         bus_space_handle_t ioh = sc->sc_ioh;
514         struct ncv_targ_info *nti = (void *) ti;
515         u_int hwcycle, period;
516
517         if ((msg & SCSI_LOW_MSG_WIDE) != 0)
518         {
519                 if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
520                 {
521                         ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
522                         return EINVAL;
523                 }
524                 return 0;
525         }
526
527         if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
528                 return 0;
529
530         period = ti->ti_maxsynch.period;
531         hwcycle = (sc->sc_hw.hw_clk == 0) ? 40 : (5 * sc->sc_hw.hw_clk);
532         hwcycle = 1000 / hwcycle;
533
534         if (period < 200 / 4 && period >= 100 / 4)
535                 nti->nti_reg_cfg3 |= sc->sc_hw.hw_cfg3_fscsi;
536         else
537                 nti->nti_reg_cfg3 &= ~sc->sc_hw.hw_cfg3_fscsi;
538
539         period = ((period * 40 / hwcycle) + 5) / 10;
540         nti->nti_reg_period = period & 0x1f;
541         nti->nti_reg_offset = ti->ti_maxsynch.offset;
542
543         bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period);
544         bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset);
545         bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3);
546         return 0;
547 }
548
549 static int
550 ncv_targ_init(sc, ti, action)
551         struct ncv_softc *sc;
552         struct targ_info *ti;
553         int action;
554 {
555         struct ncv_targ_info *nti = (void *) ti;
556
557         if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
558         {
559                 ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
560                 ti->ti_maxsynch.period = sc->sc_hw.hw_mperiod;
561                 ti->ti_maxsynch.offset = sc->sc_hw.hw_moffset;
562
563                 nti->nti_reg_cfg3 = sc->sc_hw.hw_cfg3;
564                 nti->nti_reg_period = 0;
565                 nti->nti_reg_offset = 0;
566         }
567         return 0;
568 }       
569
570 /**************************************************************
571  * General probe attach
572  **************************************************************/
573 static int ncv_setup_img(struct ncv_hw *, u_int, int);
574
575 static int
576 ncv_setup_img(hw, dvcfg, hostid)
577         struct ncv_hw *hw;
578         u_int dvcfg;
579         int hostid;
580 {
581
582         if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F)
583         {
584                 printf("ncv: invalid dvcfg flags\n");
585                 return EINVAL;
586         }
587
588         if (NCV_C5IMG(dvcfg) != 0)
589         {
590                 hw->hw_cfg5 = NCV_C5IMG(dvcfg);
591                 hw->hw_clk = NCV_CLKFACTOR(dvcfg);
592
593                 if ((ncv_io_control & NCV_ENABLE_FAST_SCSI) != 0 &&
594                     (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) != 0)
595                         hw->hw_mperiod = 100 / 4;
596
597                 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG)
598                         hw->hw_cfg3_fclk = 0x04;
599
600                 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1)
601                         hw->hw_cfg2 &= ~C2_SCSI2;
602
603                 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW)
604                         hw->hw_cfg1 |= C1_SLOW;
605         }
606
607         /* setup configuration image 3 */
608         if (hw->hw_clk != CLK_40M_F && hw->hw_clk <= CLK_25M_F)
609                 hw->hw_cfg3 &= ~hw->hw_cfg3_fclk;
610         else
611                 hw->hw_cfg3 |= hw->hw_cfg3_fclk;
612
613         /* setup configuration image 1 */
614         hw->hw_cfg1 = (hw->hw_cfg1 & 0xf0) | hostid;
615         return 0;
616 }
617
618 int
619 ncvprobesubr(iot, ioh, dvcfg, hsid)
620         bus_space_tag_t iot;
621         bus_space_handle_t ioh;
622         u_int dvcfg;
623         int hsid;
624 {
625         struct ncv_hw hwtab;
626
627         hwtab = ncv_template;
628         if (ncv_setup_img(&hwtab, dvcfg, hsid))
629                 return 0;
630         if (ncvhw_check(iot, ioh, &hwtab) != 0)
631                 return 0;
632
633         return 1;
634 }
635
636 int
637 ncvprint(aux, name)
638         void *aux;
639         const char *name;
640 {
641
642         if (name != NULL)
643                 printf("%s: scsibus ", name);
644         return UNCONF;
645 }
646
647 void
648 ncvattachsubr(sc)
649         struct ncv_softc *sc;
650 {
651         struct scsi_low_softc *slp = &sc->sc_sclow;
652
653         printf("\n");
654         sc->sc_hw = ncv_template;
655         ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid);
656         slp->sl_funcs = &ncv_funcs;
657         slp->sl_flags |= HW_READ_PADDING;
658         sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
659
660         (void) scsi_low_attach(slp, 0, NCV_NTARGETS, NCV_NLUNS,
661                                sizeof(struct ncv_targ_info), 0);
662 }
663
664 /**************************************************************
665  * PDMA
666  **************************************************************/
667 static __inline void
668 ncv_setup_and_start_pio(sc, reqlen)
669         struct ncv_softc *sc;
670         u_int reqlen;
671 {
672         bus_space_tag_t iot = sc->sc_iot;
673         bus_space_handle_t ioh = sc->sc_ioh;
674
675         ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
676         ncvhw_set_count(iot, ioh, reqlen);
677         bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA);
678
679         ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
680         bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN);
681 }
682
683 static void
684 ncv_pdma_end(sc, ti)
685         struct ncv_softc *sc;
686         struct targ_info *ti;
687 {
688         struct scsi_low_softc *slp = &sc->sc_sclow;
689         bus_space_tag_t iot = sc->sc_iot;
690         bus_space_handle_t ioh = sc->sc_ioh;
691         int len;
692
693         slp->sl_flags &= ~HW_PDMASTART;
694         if (slp->sl_Qnexus == NULL)
695         {
696                 slp->sl_error |= PDMAERR;
697                 goto out;
698         }
699
700         if (ti->ti_phase == PH_DATA)
701         {
702                 len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh);
703                 if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
704                         len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
705                                 cr0_sffl) & CR0_SFFLR_BMASK);
706
707                 if ((u_int) len <= (u_int) sc->sc_sdatalen)
708                 {
709                         if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) &&
710                             sc->sc_tdatalen != len)
711                                 goto bad;
712
713                         len = sc->sc_sdatalen - len;
714                         if ((u_int) len > (u_int) slp->sl_scp.scp_datalen)
715                                 goto bad;
716
717                         slp->sl_scp.scp_data += len;
718                         slp->sl_scp.scp_datalen -= len;
719                 }
720                 else
721                 {
722 bad:
723                         if ((slp->sl_error & PDMAERR) == 0)
724                         {
725                                 printf("%s: stragne cnt hw 0x%x soft 0x%x\n",
726                                         slp->sl_xname, len,
727                                         slp->sl_scp.scp_datalen);
728                         }
729                         slp->sl_error |= PDMAERR;
730                 }
731                 scsi_low_data_finish(slp);
732         }
733         else
734         {
735                 printf("%s: data phase miss\n", slp->sl_xname);
736                 slp->sl_error |= PDMAERR;
737         }
738
739 out:
740         ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
741         bus_space_write_1(iot, ioh, cr1_fstat, 0);
742         ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
743 }
744
745 static void
746 ncv_pio_read(sc, buf, reqlen)
747         struct ncv_softc *sc;
748         u_int8_t *buf;
749         u_int reqlen;
750 {
751         struct scsi_low_softc *slp = &sc->sc_sclow;
752         bus_space_tag_t iot = sc->sc_iot;
753         bus_space_handle_t ioh = sc->sc_ioh;
754         int tout;
755         register u_int8_t fstat;
756
757         ncv_setup_and_start_pio(sc, reqlen);
758         slp->sl_flags |= HW_PDMASTART;
759         sc->sc_sdatalen = reqlen;
760         tout = sc->sc_tmaxcnt;
761
762         while (reqlen >= FIFO_F_SZ && tout -- > 0)
763         {
764                 fstat = bus_space_read_1(iot, ioh, cr1_fstat);
765                 if (fstat == (u_int8_t) -1)
766                         goto out;
767                 if (fstat & FIFO_F)
768                 {
769 #define NCV_FAST32_ACCESS
770 #ifdef  NCV_FAST32_ACCESS
771                         bus_space_read_multi_4(iot, ioh, cr1_fdata, 
772                                 (u_int32_t *) buf, FIFO_F_SZ / 4);
773 #else   /* !NCV_FAST32_ACCESS */
774                         bus_space_read_multi_2(iot, ioh, cr1_fdata, 
775                                 (u_int16_t *) buf, FIFO_F_SZ / 2);
776 #endif  /* !NCV_FAST32_ACCESS */
777                         buf += FIFO_F_SZ;
778                         reqlen -= FIFO_F_SZ;
779                 }
780                 else 
781                 {
782                         if (fstat & FIFO_BRK)
783                                 break;
784
785                         SCSI_LOW_DELAY(1);
786                 }
787         }
788
789         while (reqlen > 0 && tout -- > 0)
790         {
791                 fstat = bus_space_read_1(iot, ioh, cr1_fstat);
792                 if ((fstat & FIFO_E) == 0)
793                 {
794                         *buf++ = bus_space_read_1(iot, ioh, cr1_fdata);
795                         reqlen --;
796                 }
797                 else
798                 {
799                          if (fstat & FIFO_BRK)
800                                 break;
801
802                         SCSI_LOW_DELAY(1);
803                 }
804         }
805
806 out:
807         ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
808         sc->sc_tdatalen = reqlen;
809 }
810
811 static void
812 ncv_pio_write(sc, buf, reqlen)
813         struct ncv_softc *sc;
814         u_int8_t *buf;
815         u_int reqlen;
816 {
817         struct scsi_low_softc *slp = &sc->sc_sclow;
818         bus_space_tag_t iot = sc->sc_iot;
819         bus_space_handle_t ioh = sc->sc_ioh;
820         int tout;
821         register u_int8_t fstat;
822
823         ncv_setup_and_start_pio(sc, reqlen);
824         sc->sc_sdatalen = reqlen;
825         tout = sc->sc_tmaxcnt;
826         slp->sl_flags |= HW_PDMASTART;
827
828         while (reqlen >= FIFO_F_SZ && tout -- > 0)
829         {
830                 fstat = bus_space_read_1(iot, ioh, cr1_fstat);
831                 if (fstat & FIFO_BRK)
832                         goto done;
833
834                 if ((fstat & FIFO_E) != 0)
835                 {
836 #ifdef  NCV_FAST32_ACCESS
837                         bus_space_write_multi_4(iot, ioh, cr1_fdata, 
838                                 (u_int32_t *) buf, FIFO_F_SZ / 4);
839 #else   /* !NCV_FAST32_ACCESS */
840                         bus_space_write_multi_2(iot, ioh, cr1_fdata, 
841                                 (u_int16_t *) buf, FIFO_F_SZ / 2);
842 #endif  /* !NCV_FAST32_ACCESS */
843                         buf += FIFO_F_SZ;
844                         reqlen -= FIFO_F_SZ;
845                 }
846                 else
847                 {
848                         SCSI_LOW_DELAY(1);
849                 }
850         }
851
852         while (reqlen > 0 && tout -- > 0)
853         {
854                 fstat = bus_space_read_1(iot, ioh, cr1_fstat);
855                 if (fstat & FIFO_BRK)
856                         break;
857
858                 if ((fstat & FIFO_F) == 0) /* fifo not full */
859                 {
860                         bus_space_write_1(iot, ioh, cr1_fdata, *buf++);
861                         reqlen --;
862                 }
863                 else
864                 {
865                         SCSI_LOW_DELAY(1);
866                 }
867         }
868
869 done:
870         ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
871 }
872
873 /**************************************************************
874  * disconnect & reselect (HW low)
875  **************************************************************/
876 static int
877 ncv_reselected(sc)
878         struct ncv_softc *sc;
879 {
880         struct scsi_low_softc *slp = &sc->sc_sclow;
881         bus_space_tag_t iot = sc->sc_iot;
882         bus_space_handle_t ioh = sc->sc_ioh;
883         struct targ_info *ti;
884         u_int sid;
885
886         if ((bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK) != 2)
887         {
888                 printf("%s illegal fifo bytes\n", slp->sl_xname);
889                 scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused");
890                 return EJUSTRETURN;
891         }
892
893         sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo);
894         sid &= ~(1 << slp->sl_hostid);
895         sid = ffs(sid) - 1;
896         ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid);
897         if (ti == NULL)
898                 return EJUSTRETURN;
899
900 #ifdef  NCV_STATICS
901         ncv_statics.reselect ++;
902 #endif  /* NCV_STATICS */
903         bus_space_write_1(iot, ioh, cr0_dstid, sid);
904         return 0;
905 }
906
907 static int
908 ncv_disconnected(sc, ti)
909         struct ncv_softc *sc;
910         struct targ_info *ti;
911 {
912         struct scsi_low_softc *slp = &sc->sc_sclow;
913         bus_space_tag_t iot = sc->sc_iot;
914         bus_space_handle_t ioh = sc->sc_ioh;
915
916         bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
917         bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL);
918
919 #ifdef  NCV_STATICS
920         ncv_statics.disconnect ++;
921 #endif  /* NCV_STATICS */
922
923         scsi_low_disconnected(slp, ti);
924         return 1;
925 }
926
927 /**************************************************************
928  * SEQUENCER
929  **************************************************************/
930 static int
931 ncv_target_nexus_establish(sc)
932         struct ncv_softc *sc;
933 {
934         struct scsi_low_softc *slp = &sc->sc_sclow;
935         struct targ_info *ti = slp->sl_Tnexus;
936         struct ncv_targ_info *nti = (void *) ti;
937         bus_space_tag_t iot = sc->sc_iot;
938         bus_space_handle_t ioh = sc->sc_ioh;
939
940         bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period);
941         bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset);
942         bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3);
943         return 0;
944 }
945
946 static int
947 ncv_lun_nexus_establish(sc)
948         struct ncv_softc *sc;
949 {
950
951         return 0;
952 }
953
954 static int
955 ncv_ccb_nexus_establish(sc)
956         struct ncv_softc *sc;
957 {
958         struct scsi_low_softc *slp = &sc->sc_sclow;
959         struct slccb *cb = slp->sl_Qnexus;
960
961         sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
962         return 0;
963 }
964
965 static int
966 ncv_catch_intr(sc)
967         struct ncv_softc *sc;
968 {
969         bus_space_tag_t iot = sc->sc_iot;
970         bus_space_handle_t ioh = sc->sc_ioh;
971         int wc;
972         register u_int8_t status;
973
974         for (wc = 0; wc < NCV_DELAY_MAX / NCV_DELAY_INTERVAL; wc ++)
975         {
976                 status = bus_space_read_1(iot, ioh, cr0_stat);
977                 if ((status & STAT_INT) != 0)
978                         return 0;
979
980                 SCSI_LOW_DELAY(NCV_DELAY_INTERVAL);
981         }
982         return EJUSTRETURN;
983 }
984
985 int
986 ncvintr(arg)
987         void *arg;
988 {
989         struct ncv_softc *sc = arg;
990         struct scsi_low_softc *slp = &sc->sc_sclow;
991         bus_space_tag_t iot = sc->sc_iot;
992         bus_space_handle_t ioh = sc->sc_ioh;
993         struct targ_info *ti;
994         struct physio_proc *pp;
995         struct buf *bp;
996         u_int derror, flags;
997         int len;
998         u_int8_t regv, status, ireason;
999
1000 again:
1001         if (slp->sl_flags & HW_INACTIVE)
1002                 return 0;
1003
1004         /********************************************
1005          * Status
1006          ********************************************/
1007         ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
1008         status = bus_space_read_1(iot, ioh, cr0_stat);
1009         if ((status & STAT_INT) == 0 || status == (u_int8_t) -1)
1010                 return 0;
1011
1012         ireason = bus_space_read_1(iot, ioh, cr0_istat);
1013         if ((ireason & INTR_SBR) != 0)
1014         {
1015                 u_int8_t val;
1016
1017                 /* avoid power off hangup */
1018                 val = bus_space_read_1(iot, ioh, cr0_cfg1);
1019                 bus_space_write_1(iot, ioh, cr0_cfg1, val | C1_SRR);
1020
1021                 /* status init */
1022                 scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, 
1023                                  "bus reset (power off?)");
1024                 return 1;
1025         }
1026
1027         /********************************************
1028          * Debug section
1029          ********************************************/
1030 #ifdef  NCV_DEBUG
1031         if (ncv_debug)
1032         {
1033                 scsi_low_print(slp, NULL);
1034                 printf("%s st %x ist %x\n\n", slp->sl_xname,
1035                         status, ireason);
1036 #ifdef  KDB
1037                 if (ncv_debug > 1)
1038                         SCSI_LOW_DEBUGGER("ncv");
1039 #endif  /* KDB */
1040         }
1041 #endif  /* NCV_DEBUG */
1042
1043         /********************************************
1044          * Reselect or Disconnect or Nexus check
1045          ********************************************/
1046         /* (I) reselect */
1047         if (ireason == INTR_RESELECT)
1048         {
1049                 if (ncv_reselected(sc) == EJUSTRETURN)
1050                         return 1;
1051         }
1052
1053         /* (II) nexus */
1054         if ((ti = slp->sl_Tnexus) == NULL)
1055                 return 0;
1056
1057         derror = 0;
1058         if ((status & (STAT_PE | STAT_GE)) != 0)
1059         {
1060                 slp->sl_error |= PARITYERR;
1061                 if ((status & PHASE_MASK) == MESSAGE_IN_PHASE)
1062                         scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
1063                 else
1064                         scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1);
1065                 derror = SCSI_LOW_DATA_PE;
1066         }
1067
1068         if ((ireason & (INTR_DIS | INTR_ILL)) != 0)
1069         {
1070                 if ((ireason & INTR_ILL) == 0)
1071                         return ncv_disconnected(sc, ti);
1072
1073                 slp->sl_error |= FATALIO;
1074                 scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "illegal cmd");
1075                 return 1;
1076         }
1077
1078         /********************************************
1079          * Internal scsi phase
1080          ********************************************/
1081         switch (ti->ti_phase)
1082         {
1083         case PH_SELSTART:
1084                 scsi_low_arbit_win(slp);
1085                 SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
1086
1087                 if (sc->sc_selstop == 0)
1088                 {
1089                         /* XXX:
1090                          * Here scsi phases expected are
1091                          * DATA PHASE: 
1092                          * MSGIN     : target wants to disconnect the host.
1093                          * STATUSIN  : immediate command completed.
1094                          * CMD PHASE : command out failed
1095                          * MSGOUT    : identify command failed.
1096                          */
1097                         if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
1098                                 break;
1099                 }
1100                 else
1101                 {
1102                         if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
1103                                 break;
1104                         if ((ireason & INTR_FC) != 0) 
1105                         {
1106                                 SCSI_LOW_ASSERT_ATN(slp);
1107                         }
1108                 }
1109                 SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
1110                 break;
1111
1112         case PH_RESEL:
1113                 ncv_target_nexus_establish(sc);
1114                 if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
1115                 {
1116                         printf("%s: unexpected phase after reselect\n",
1117                                 slp->sl_xname);
1118                         slp->sl_error |= FATALIO;
1119                         scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
1120                         return 1;
1121                 }
1122                 break;
1123
1124         default:
1125                 if ((slp->sl_flags & HW_PDMASTART) != 0)
1126                 {
1127                         ncv_pdma_end(sc, ti);
1128                 }
1129                 break;
1130         }
1131
1132         /********************************************
1133          * Scsi phase sequencer
1134          ********************************************/
1135         switch (status & PHASE_MASK)
1136         {
1137         case DATA_OUT_PHASE: /* data out */
1138                 SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
1139                 if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
1140                 {
1141                         scsi_low_attention(slp);
1142                 }
1143
1144                 pp = physio_proc_enter(bp);
1145                 if (slp->sl_scp.scp_datalen <= 0)
1146                 {
1147                         if ((ireason & INTR_BS) == 0)
1148                                 break;
1149
1150                         if ((slp->sl_error & PDMAERR) == 0)
1151                                 printf("%s: data underrun\n", slp->sl_xname);
1152                         slp->sl_error |= PDMAERR;
1153
1154                         if ((slp->sl_flags & HW_WRITE_PADDING) != 0)
1155                         {
1156                                 u_int8_t padding[NCV_PADDING_SIZE];
1157
1158                                 SCSI_LOW_BZERO(padding, sizeof(padding));
1159                                 ncv_pio_write(sc, padding, sizeof(padding));
1160                         }
1161                         else
1162                         {
1163                                 printf("%s: write padding required\n",
1164                                         slp->sl_xname);
1165                         }
1166                 }
1167                 else
1168                 {
1169                         len = slp->sl_scp.scp_datalen;
1170                         if ((ncv_io_control & NCV_WRITE_INTERRUPTS_DRIVEN) != 0)
1171                         {
1172                                 if (len > ncv_data_write_bytes)
1173                                         len = ncv_data_write_bytes;
1174                         }
1175                         ncv_pio_write(sc, slp->sl_scp.scp_data, len);
1176                 }
1177                 physio_proc_leave(pp);
1178                 break;
1179
1180         case DATA_IN_PHASE: /* data in */
1181                 SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
1182                 if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
1183                 {
1184                         scsi_low_attention(slp);
1185                 }
1186
1187                 pp = physio_proc_enter(bp);
1188                 if (slp->sl_scp.scp_datalen <= 0)
1189                 {
1190                         if ((ireason & INTR_BS) == 0)
1191                                 break;
1192
1193                         if ((slp->sl_error & PDMAERR) == 0)
1194                                 printf("%s: data overrun\n", slp->sl_xname);
1195                         slp->sl_error |= PDMAERR;
1196
1197                         if ((slp->sl_flags & HW_READ_PADDING) != 0)
1198                         {
1199                                 u_int8_t padding[NCV_PADDING_SIZE];
1200
1201                                 ncv_pio_read(sc, padding, sizeof(padding));
1202                         }
1203                         else
1204                         {
1205                                 printf("%s: read padding required\n",
1206                                         slp->sl_xname);
1207                                 break;
1208                         }
1209                 }
1210                 else
1211                 {
1212                         len = slp->sl_scp.scp_datalen;
1213                         if ((ncv_io_control & NCV_READ_INTERRUPTS_DRIVEN) != 0)
1214                         {
1215                                 if (len > ncv_data_read_bytes)
1216                                         len = ncv_data_read_bytes;
1217                         }
1218                         ncv_pio_read(sc, slp->sl_scp.scp_data, len);
1219                 }
1220                 physio_proc_leave(pp);
1221                 break;
1222
1223         case COMMAND_PHASE: /* cmd out */
1224                 SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
1225                 if (scsi_low_cmd(slp, ti) != 0)
1226                 {
1227                         scsi_low_attention(slp);
1228                 }
1229
1230                 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1231                 ncvhw_fpush(iot, ioh,
1232                             slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
1233                 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1234                 break;
1235
1236         case STATUS_PHASE: /* status in */
1237                 SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
1238                 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1239                 bus_space_write_1(iot, ioh, cr0_cmd, CMD_ICCS);
1240                 sc->sc_compseq = 1;
1241                 break;
1242
1243         default:
1244                 break;
1245
1246         case MESSAGE_OUT_PHASE: /* msg out */
1247                 SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
1248                 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1249
1250                 flags = SCSI_LOW_MSGOUT_UNIFY;
1251                 if (ti->ti_ophase != ti->ti_phase)
1252                         flags |= SCSI_LOW_MSGOUT_INIT;
1253                 len = scsi_low_msgout(slp, ti, flags);
1254
1255                 if (len > 1 && slp->sl_atten == 0)
1256                 {
1257                         scsi_low_attention(slp);
1258                 }
1259
1260                 ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len);
1261                 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1262                 SCSI_LOW_DEASSERT_ATN(slp);
1263                 break;
1264
1265         case MESSAGE_IN_PHASE: /* msg in */
1266                 SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
1267
1268                 len = bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK;
1269                 if (sc->sc_compseq != 0)
1270                 {
1271                         sc->sc_compseq = 0;
1272                         if ((ireason & INTR_FC) && len == 2)
1273                         {
1274                                 regv = bus_space_read_1(iot, ioh, cr0_sfifo);
1275                                 scsi_low_statusin(slp, ti, regv | derror);
1276                                 len --;
1277                         }
1278                         else
1279                         {
1280                                 slp->sl_error |= FATALIO;
1281                                 scsi_low_assert_msg(slp, ti,
1282                                                     SCSI_LOW_MSG_ABORT, 1);
1283                                 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
1284                                                   cr0_cmd, CMD_MSGOK);
1285                                 break;
1286                         }
1287                 }
1288                 else if (ireason & INTR_BS)
1289                 {
1290                         bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1291                         bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1292                         if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
1293                         {
1294                                 if (ncv_catch_intr(sc) == 0)
1295                                         goto again;
1296                         }
1297                         break;
1298                 }
1299
1300                 if ((ireason & INTR_FC) && len == 1)
1301                 {
1302                         regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
1303                                                 cr0_sfifo);
1304                         if (scsi_low_msgin(slp, ti, regv | derror) == 0)
1305                         {
1306                                 if (scsi_low_is_msgout_continue(ti, 0) != 0)
1307                                 {
1308                                         scsi_low_attention(slp);
1309                                 }
1310                         }
1311                         bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd,
1312                                 CMD_MSGOK);
1313                         if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
1314                         {
1315                                 /* XXX: 
1316                                  * clear a pending interrupt and sync with
1317                                  * a next interrupt!
1318                                  */
1319                                 ncv_catch_intr(sc);
1320                         }
1321                 }
1322                 else
1323                 {
1324                         slp->sl_error |= FATALIO;
1325                         scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
1326                         bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd,
1327                                 CMD_MSGOK);
1328                 }
1329                 break;
1330         }
1331
1332         return 1;
1333 }