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