NFE - Change default RX ring size from 128 -> 256, Adjust moderation timer.
[dragonfly.git] / sys / dev / disk / ncv / ncr53c500.c
blobc67302a8eaa2adccc1f15141b42c4b56619b6313
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.13 2007/01/06 08:28:53 dillon Exp $ */
3 /* $NecBSD: ncr53c500.c,v 1.30.12.3 2001/06/26 07:31:41 honda Exp $ */
4 /* $NetBSD$ */
6 #define NCV_DEBUG
7 #define NCV_STATICS
8 #define NCV_IO_CONTROL_FLAGS (0)
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.
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.
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.
40 #include "opt_ddb.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/buf.h>
46 #include <sys/queue.h>
47 #include <sys/malloc.h>
48 #include <sys/errno.h>
49 #include <sys/bus.h>
50 #include <sys/thread2.h>
52 #include <machine/clock.h>
53 #include <machine/cpu.h>
55 #include "dvcfg.h"
57 #include <bus/cam/scsi/scsi_low.h>
59 #include "ncr53c500reg.h"
60 #include "ncr53c500hw.h"
61 #include "ncr53c500var.h"
63 #include "ncr53c500hwtab.h"
65 #define NCV_MAX_DATA_SIZE (64 * 1024)
66 #define NCV_DELAY_MAX (2 * 1000 * 1000)
67 #define NCV_DELAY_INTERVAL (1)
68 #define NCV_PADDING_SIZE (32)
70 /***************************************************
71 * IO control
72 ***************************************************/
73 #define NCV_READ_INTERRUPTS_DRIVEN 0x0001
74 #define NCV_WRITE_INTERRUPTS_DRIVEN 0x0002
75 #define NCV_ENABLE_FAST_SCSI 0x0010
76 #define NCV_FAST_INTERRUPTS 0x0100
78 u_int ncv_io_control = NCV_IO_CONTROL_FLAGS;
79 int ncv_data_read_bytes = 4096;
80 int ncv_data_write_bytes = 4096;
82 /***************************************************
83 * DEBUG
84 ***************************************************/
85 #ifdef NCV_DEBUG
86 int ncv_debug;
87 #endif /* NCV_DEBUG */
89 #ifdef NCV_STATICS
90 struct ncv_statics {
91 int disconnect;
92 int reselect;
93 } ncv_statics;
94 #endif /* NCV_STATICS */
96 /***************************************************
97 * DEVICE STRUCTURE
98 ***************************************************/
99 extern struct cfdriver ncv_cd;
101 /**************************************************************
102 * DECLARE
103 **************************************************************/
104 /* static */
105 static void ncv_pio_read (struct ncv_softc *, u_int8_t *, u_int);
106 static void ncv_pio_write (struct ncv_softc *, u_int8_t *, u_int);
107 static int ncv_msg (struct ncv_softc *, struct targ_info *, u_int);
108 static int ncv_reselected (struct ncv_softc *);
109 static int ncv_disconnected (struct ncv_softc *, struct targ_info *);
111 static __inline void ncvhw_set_count (bus_space_tag_t, bus_space_handle_t, int);
112 static __inline u_int ncvhw_get_count (bus_space_tag_t, bus_space_handle_t);
113 static __inline void ncvhw_select_register_0 (bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
114 static __inline void ncvhw_select_register_1 (bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
115 static __inline void ncvhw_fpush (bus_space_tag_t, bus_space_handle_t, u_int8_t *, int);
117 static void ncv_pdma_end (struct ncv_softc *sc, struct targ_info *);
118 static int ncv_world_start (struct ncv_softc *, int);
119 static void ncvhw_bus_reset (struct ncv_softc *);
120 static void ncvhw_reset (bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
121 static int ncvhw_check (bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
122 static void ncvhw_init (bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
123 static int ncvhw_start_selection (struct ncv_softc *sc, struct slccb *);
124 static void ncvhw_attention (struct ncv_softc *);
125 static int ncv_ccb_nexus_establish (struct ncv_softc *);
126 static int ncv_lun_nexus_establish (struct ncv_softc *);
127 static int ncv_target_nexus_establish (struct ncv_softc *);
128 static int ncv_targ_init (struct ncv_softc *, struct targ_info *, int);
129 static int ncv_catch_intr (struct ncv_softc *);
130 #ifdef NCV_POWER_CONTROL
131 static int ncvhw_power (struct ncv_softc *, u_int);
132 #endif /* NCV_POWER_CONTROL */
133 static __inline void ncv_setup_and_start_pio (struct ncv_softc *, u_int);
135 struct scsi_low_funcs ncv_funcs = {
136 SC_LOW_INIT_T ncv_world_start,
137 SC_LOW_BUSRST_T ncvhw_bus_reset,
138 SC_LOW_TARG_INIT_T ncv_targ_init,
139 SC_LOW_LUN_INIT_T NULL,
141 SC_LOW_SELECT_T ncvhw_start_selection,
142 SC_LOW_NEXUS_T ncv_lun_nexus_establish,
143 SC_LOW_NEXUS_T ncv_ccb_nexus_establish,
145 SC_LOW_ATTEN_T ncvhw_attention,
146 SC_LOW_MSG_T ncv_msg,
148 SC_LOW_TIMEOUT_T NULL,
149 SC_LOW_POLL_T ncvintr,
151 NULL, /* SC_LOW_POWER_T ncvhw_power, */
154 /**************************************************************
155 * hwfuncs
156 **************************************************************/
157 static __inline void
158 ncvhw_select_register_0(bus_space_tag_t iot, bus_space_handle_t ioh,
159 struct ncv_hw *hw)
162 bus_space_write_1(iot, ioh, cr0_cfg4, hw->hw_cfg4);
165 static __inline void
166 ncvhw_select_register_1(bus_space_tag_t iot, bus_space_handle_t ioh,
167 struct ncv_hw *hw)
170 bus_space_write_1(iot, ioh, cr1_cfg5, hw->hw_cfg5);
173 static __inline void
174 ncvhw_fpush(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t *buf,
175 int len)
177 int ptr;
179 for (ptr = 0; ptr < len; ptr ++)
180 bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]);
183 static __inline void
184 ncvhw_set_count(bus_space_tag_t iot, bus_space_handle_t ioh, int count)
187 bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count);
188 bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY));
189 bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2)));
192 static __inline u_int
193 ncvhw_get_count(bus_space_tag_t iot, bus_space_handle_t ioh)
195 u_int count;
197 count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb);
198 count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY;
199 count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2);
200 return count;
203 static int
204 ncvhw_check(bus_space_tag_t iot, bus_space_handle_t ioh, struct ncv_hw *hw)
206 u_int8_t stat;
208 ncvhw_select_register_0(iot, ioh, hw);
209 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
210 if (bus_space_read_1(iot, ioh, cr0_cmd) != (CMD_NOP | CMD_DMA))
212 #ifdef NCV_DEBUG
213 kprintf("ncv: cr0_cmd CMD_NOP|CMD_DMA failed\n");
214 #endif /* NCV_DEBUG */
215 return ENODEV;
218 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
219 if (bus_space_read_1(iot, ioh, cr0_cmd) != CMD_NOP)
221 #ifdef NCV_DEBUG
222 kprintf("ncv: cr0_cmd CMD_NOP failed\n");
223 #endif /* NCV_DEBUG */
224 return ENODEV;
227 /* hardware reset */
228 ncvhw_reset(iot, ioh, hw);
229 ncvhw_init(iot, ioh, hw);
231 /* bus reset */
232 ncvhw_select_register_0(iot, ioh, hw);
233 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
234 bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI);
235 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
236 SCSI_LOW_DELAY(100 * 1000);
238 /* check response */
239 bus_space_read_1(iot, ioh, cr0_stat);
240 stat = bus_space_read_1(iot, ioh, cr0_istat);
241 SCSI_LOW_DELAY(1000);
243 if (((stat & INTR_SBR) == 0) ||
244 (bus_space_read_1(iot, ioh, cr0_istat) & INTR_SBR))
246 #ifdef NCV_DEBUG
247 kprintf("ncv: cr0_istat SCSI BUS RESET failed\n");
248 #endif /* NCV_DEBUG */
249 return ENODEV;
252 return 0;
255 static void
256 ncvhw_reset(bus_space_tag_t iot, bus_space_handle_t ioh,
257 struct ncv_hw *hw)
260 ncvhw_select_register_0(iot, ioh, hw);
262 /* dummy cmd twice */
263 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
264 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
266 /* chip reset */
267 bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTCHIP);
269 /* again dummy cmd twice */
270 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
271 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
274 static void
275 ncvhw_init(bus_space_tag_t iot, bus_space_handle_t ioh,
276 struct ncv_hw *hw)
279 ncvhw_select_register_0(iot, ioh, hw);
280 bus_space_write_1(iot, ioh, cr0_clk, hw->hw_clk);
281 bus_space_write_1(iot, ioh, cr0_srtout, SEL_TOUT);
282 bus_space_write_1(iot, ioh, cr0_period, 0);
283 bus_space_write_1(iot, ioh, cr0_offs, 0);
285 bus_space_write_1(iot, ioh, cr0_cfg1, hw->hw_cfg1);
286 bus_space_write_1(iot, ioh, cr0_cfg2, hw->hw_cfg2);
287 bus_space_write_1(iot, ioh, cr0_cfg3, hw->hw_cfg3);
288 bus_space_write_1(iot, ioh, cr0_tchsb, 0);
290 ncvhw_select_register_1(iot, ioh, hw);
291 bus_space_write_1(iot, ioh, cr1_fstat, 0x0);
292 bus_space_write_1(iot, ioh, cr1_pflag, 0x0);
293 bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE);
295 ncvhw_select_register_0(iot, ioh, hw);
298 #ifdef NCV_POWER_CONTROL
299 static int
300 ncvhw_power(struct ncv_softc *sc, u_int flags)
302 struct scsi_low_softc *slp = &sc->sc_sclow;
303 bus_space_tag_t iot = sc->sc_iot;
304 bus_space_handle_t ioh = sc->sc_ioh;
306 if (flags == SCSI_LOW_POWDOWN)
308 kprintf("%s power down\n", slp->sl_xname);
309 ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
310 bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_POWDOWN);
312 else
314 switch (sc->sc_rstep)
316 case 0:
317 kprintf("%s resume step O\n", slp->sl_xname);
318 ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
319 bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE);
320 break;
322 case 1:
323 kprintf("%s resume step I\n", slp->sl_xname);
324 ncvhw_reset(iot, ioh, &sc->sc_hw);
325 ncvhw_init(iot, ioh, &sc->sc_hw);
326 break;
330 return 0;
332 #endif /* NCV_POWER_CONTROL */
334 /**************************************************************
335 * scsi low interface
336 **************************************************************/
337 static void
338 ncvhw_attention(struct ncv_softc *sc)
341 bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, CMD_SETATN);
342 SCSI_LOW_DELAY(10);
345 static void
346 ncvhw_bus_reset(struct ncv_softc *sc)
348 bus_space_tag_t iot = sc->sc_iot;
349 bus_space_handle_t ioh = sc->sc_ioh;
351 ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
352 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
353 bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI);
354 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
357 static int
358 ncvhw_start_selection(struct ncv_softc *sc, struct slccb *cb)
360 struct scsi_low_softc *slp = &sc->sc_sclow;
361 bus_space_tag_t iot = sc->sc_iot;
362 bus_space_handle_t ioh = sc->sc_ioh;
363 struct targ_info *ti = cb->ti;
364 int len;
365 u_int flags;
366 u_int8_t cmd;
368 sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
369 sc->sc_compseq = 0;
370 if (scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0)
372 cmd = CMD_SELATN;
373 sc->sc_selstop = 0;
374 flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
376 else if (scsi_low_is_msgout_continue(ti,
377 SCSI_LOW_MSG_IDENTIFY | SCSI_LOW_MSG_SIMPLE_QTAG) == 0)
379 cmd = CMD_SELATN3;
380 sc->sc_selstop = 0;
381 flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
383 else
385 cmd = CMD_SELATNS;
386 sc->sc_selstop = 1;
387 flags = SCSI_LOW_MSGOUT_INIT;
390 ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
391 if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0)
392 return SCSI_LOW_START_FAIL;
394 ncv_target_nexus_establish(sc);
396 len = scsi_low_msgout(slp, ti, flags);
397 if (sc->sc_selstop == 0)
398 scsi_low_cmd(slp, ti);
400 crit_enter();
401 if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0)
403 crit_exit();
404 return SCSI_LOW_START_FAIL;
407 bus_space_write_1(iot, ioh, cr0_dstid, ti->ti_id);
408 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
409 ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len);
410 if (sc->sc_selstop == 0)
412 ncvhw_fpush(iot, ioh,
413 slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
415 bus_space_write_1(iot, ioh, cr0_cmd, cmd);
416 crit_exit();
418 SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
419 return SCSI_LOW_START_OK;
422 static int
423 ncv_world_start(struct ncv_softc *sc, int fdone)
425 struct scsi_low_softc *slp = &sc->sc_sclow;
426 bus_space_tag_t iot = sc->sc_iot;
427 bus_space_handle_t ioh = sc->sc_ioh;
428 u_int8_t stat;
430 if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
431 sc->sc_hw.hw_cfg1 |= C1_PARENB;
432 else
433 sc->sc_hw.hw_cfg1 &= ~C1_PARENB;
435 ncvhw_reset(iot, ioh, &sc->sc_hw);
436 ncvhw_init(iot, ioh, &sc->sc_hw);
438 scsi_low_bus_reset(slp);
440 ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
441 bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat);
442 stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat);
443 SCSI_LOW_DELAY(1000);
445 if (((stat & INTR_SBR) == 0) ||
446 (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR))
447 return ENODEV;
449 SOFT_INTR_REQUIRED(slp);
450 return 0;
453 static int
454 ncv_msg(struct ncv_softc *sc, struct targ_info *ti, u_int msg)
456 bus_space_tag_t iot = sc->sc_iot;
457 bus_space_handle_t ioh = sc->sc_ioh;
458 struct ncv_targ_info *nti = (void *) ti;
459 u_int hwcycle, period;
461 if ((msg & SCSI_LOW_MSG_WIDE) != 0)
463 if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
465 ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
466 return EINVAL;
468 return 0;
471 if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
472 return 0;
474 period = ti->ti_maxsynch.period;
475 hwcycle = (sc->sc_hw.hw_clk == 0) ? 40 : (5 * sc->sc_hw.hw_clk);
476 hwcycle = 1000 / hwcycle;
478 if (period < 200 / 4 && period >= 100 / 4)
479 nti->nti_reg_cfg3 |= sc->sc_hw.hw_cfg3_fscsi;
480 else
481 nti->nti_reg_cfg3 &= ~sc->sc_hw.hw_cfg3_fscsi;
483 period = ((period * 40 / hwcycle) + 5) / 10;
484 nti->nti_reg_period = period & 0x1f;
485 nti->nti_reg_offset = ti->ti_maxsynch.offset;
487 bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period);
488 bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset);
489 bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3);
490 return 0;
493 static int
494 ncv_targ_init(struct ncv_softc *sc, struct targ_info *ti, int action)
496 struct ncv_targ_info *nti = (void *) ti;
498 if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
500 ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
501 ti->ti_maxsynch.period = sc->sc_hw.hw_mperiod;
502 ti->ti_maxsynch.offset = sc->sc_hw.hw_moffset;
504 nti->nti_reg_cfg3 = sc->sc_hw.hw_cfg3;
505 nti->nti_reg_period = 0;
506 nti->nti_reg_offset = 0;
508 return 0;
511 /**************************************************************
512 * General probe attach
513 **************************************************************/
514 static int ncv_setup_img (struct ncv_hw *, u_int, int);
516 static int
517 ncv_setup_img(struct ncv_hw *hw, u_int dvcfg, int hostid)
520 if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F)
522 kprintf("ncv: invalid dvcfg flags\n");
523 return EINVAL;
526 if (NCV_C5IMG(dvcfg) != 0)
528 hw->hw_cfg5 = NCV_C5IMG(dvcfg);
529 hw->hw_clk = NCV_CLKFACTOR(dvcfg);
531 if ((ncv_io_control & NCV_ENABLE_FAST_SCSI) != 0 &&
532 (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) != 0)
533 hw->hw_mperiod = 100 / 4;
535 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG)
536 hw->hw_cfg3_fclk = 0x04;
538 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1)
539 hw->hw_cfg2 &= ~C2_SCSI2;
541 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW)
542 hw->hw_cfg1 |= C1_SLOW;
545 /* setup configuration image 3 */
546 if (hw->hw_clk != CLK_40M_F && hw->hw_clk <= CLK_25M_F)
547 hw->hw_cfg3 &= ~hw->hw_cfg3_fclk;
548 else
549 hw->hw_cfg3 |= hw->hw_cfg3_fclk;
551 /* setup configuration image 1 */
552 hw->hw_cfg1 = (hw->hw_cfg1 & 0xf0) | hostid;
553 return 0;
557 ncvprobesubr(bus_space_tag_t iot, bus_space_handle_t ioh, u_int dvcfg,
558 int hsid)
560 struct ncv_hw hwtab;
562 hwtab = ncv_template;
563 if (ncv_setup_img(&hwtab, dvcfg, hsid))
564 return 0;
565 if (ncvhw_check(iot, ioh, &hwtab) != 0)
566 return 0;
568 return 1;
572 ncvprint(void *aux, const char *name)
575 if (name != NULL)
576 kprintf("%s: scsibus ", name);
577 return UNCONF;
580 void
581 ncvattachsubr(struct ncv_softc *sc)
583 struct scsi_low_softc *slp = &sc->sc_sclow;
585 kprintf("\n");
586 sc->sc_hw = ncv_template;
587 ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid);
588 slp->sl_funcs = &ncv_funcs;
589 slp->sl_flags |= HW_READ_PADDING;
590 sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
592 (void) scsi_low_attach(slp, 0, NCV_NTARGETS, NCV_NLUNS,
593 sizeof(struct ncv_targ_info), 0);
596 /**************************************************************
597 * PDMA
598 **************************************************************/
599 static __inline void
600 ncv_setup_and_start_pio(struct ncv_softc *sc, u_int reqlen)
602 bus_space_tag_t iot = sc->sc_iot;
603 bus_space_handle_t ioh = sc->sc_ioh;
605 ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
606 ncvhw_set_count(iot, ioh, reqlen);
607 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA);
609 ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
610 bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN);
613 static void
614 ncv_pdma_end(struct ncv_softc *sc, struct targ_info *ti)
616 struct scsi_low_softc *slp = &sc->sc_sclow;
617 bus_space_tag_t iot = sc->sc_iot;
618 bus_space_handle_t ioh = sc->sc_ioh;
619 int len;
621 slp->sl_flags &= ~HW_PDMASTART;
622 if (slp->sl_Qnexus == NULL)
624 slp->sl_error |= PDMAERR;
625 goto out;
628 if (ti->ti_phase == PH_DATA)
630 len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh);
631 if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
632 len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
633 cr0_sffl) & CR0_SFFLR_BMASK);
635 if ((u_int) len <= (u_int) sc->sc_sdatalen)
637 if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) &&
638 sc->sc_tdatalen != len)
639 goto bad;
641 len = sc->sc_sdatalen - len;
642 if ((u_int) len > (u_int) slp->sl_scp.scp_datalen)
643 goto bad;
645 slp->sl_scp.scp_data += len;
646 slp->sl_scp.scp_datalen -= len;
648 else
650 bad:
651 if ((slp->sl_error & PDMAERR) == 0)
653 kprintf("%s: stragne cnt hw 0x%x soft 0x%x\n",
654 slp->sl_xname, len,
655 slp->sl_scp.scp_datalen);
657 slp->sl_error |= PDMAERR;
659 scsi_low_data_finish(slp);
661 else
663 kprintf("%s: data phase miss\n", slp->sl_xname);
664 slp->sl_error |= PDMAERR;
667 out:
668 ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
669 bus_space_write_1(iot, ioh, cr1_fstat, 0);
670 ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
673 static void
674 ncv_pio_read(struct ncv_softc *sc, u_int8_t *buf, u_int reqlen)
676 struct scsi_low_softc *slp = &sc->sc_sclow;
677 bus_space_tag_t iot = sc->sc_iot;
678 bus_space_handle_t ioh = sc->sc_ioh;
679 int tout;
680 u_int8_t fstat;
682 ncv_setup_and_start_pio(sc, reqlen);
683 slp->sl_flags |= HW_PDMASTART;
684 sc->sc_sdatalen = reqlen;
685 tout = sc->sc_tmaxcnt;
687 while (reqlen >= FIFO_F_SZ && tout -- > 0)
689 fstat = bus_space_read_1(iot, ioh, cr1_fstat);
690 if (fstat == (u_int8_t) -1)
691 goto out;
692 if (fstat & FIFO_F)
694 #define NCV_FAST32_ACCESS
695 #ifdef NCV_FAST32_ACCESS
696 bus_space_read_multi_4(iot, ioh, cr1_fdata,
697 (u_int32_t *) buf, FIFO_F_SZ / 4);
698 #else /* !NCV_FAST32_ACCESS */
699 bus_space_read_multi_2(iot, ioh, cr1_fdata,
700 (u_int16_t *) buf, FIFO_F_SZ / 2);
701 #endif /* !NCV_FAST32_ACCESS */
702 buf += FIFO_F_SZ;
703 reqlen -= FIFO_F_SZ;
705 else
707 if (fstat & FIFO_BRK)
708 break;
710 SCSI_LOW_DELAY(1);
714 while (reqlen > 0 && tout -- > 0)
716 fstat = bus_space_read_1(iot, ioh, cr1_fstat);
717 if ((fstat & FIFO_E) == 0)
719 *buf++ = bus_space_read_1(iot, ioh, cr1_fdata);
720 reqlen --;
722 else
724 if (fstat & FIFO_BRK)
725 break;
727 SCSI_LOW_DELAY(1);
731 out:
732 ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
733 sc->sc_tdatalen = reqlen;
736 static void
737 ncv_pio_write(struct ncv_softc *sc, u_int8_t *buf, u_int reqlen)
739 struct scsi_low_softc *slp = &sc->sc_sclow;
740 bus_space_tag_t iot = sc->sc_iot;
741 bus_space_handle_t ioh = sc->sc_ioh;
742 int tout;
743 u_int8_t fstat;
745 ncv_setup_and_start_pio(sc, reqlen);
746 sc->sc_sdatalen = reqlen;
747 tout = sc->sc_tmaxcnt;
748 slp->sl_flags |= HW_PDMASTART;
750 while (reqlen >= FIFO_F_SZ && tout -- > 0)
752 fstat = bus_space_read_1(iot, ioh, cr1_fstat);
753 if (fstat & FIFO_BRK)
754 goto done;
756 if ((fstat & FIFO_E) != 0)
758 #ifdef NCV_FAST32_ACCESS
759 bus_space_write_multi_4(iot, ioh, cr1_fdata,
760 (u_int32_t *) buf, FIFO_F_SZ / 4);
761 #else /* !NCV_FAST32_ACCESS */
762 bus_space_write_multi_2(iot, ioh, cr1_fdata,
763 (u_int16_t *) buf, FIFO_F_SZ / 2);
764 #endif /* !NCV_FAST32_ACCESS */
765 buf += FIFO_F_SZ;
766 reqlen -= FIFO_F_SZ;
768 else
770 SCSI_LOW_DELAY(1);
774 while (reqlen > 0 && tout -- > 0)
776 fstat = bus_space_read_1(iot, ioh, cr1_fstat);
777 if (fstat & FIFO_BRK)
778 break;
780 if ((fstat & FIFO_F) == 0) /* fifo not full */
782 bus_space_write_1(iot, ioh, cr1_fdata, *buf++);
783 reqlen --;
785 else
787 SCSI_LOW_DELAY(1);
791 done:
792 ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
795 /**************************************************************
796 * disconnect & reselect (HW low)
797 **************************************************************/
798 static int
799 ncv_reselected(struct ncv_softc *sc)
801 struct scsi_low_softc *slp = &sc->sc_sclow;
802 bus_space_tag_t iot = sc->sc_iot;
803 bus_space_handle_t ioh = sc->sc_ioh;
804 struct targ_info *ti;
805 u_int sid;
807 if ((bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK) != 2)
809 kprintf("%s illegal fifo bytes\n", slp->sl_xname);
810 scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused");
811 return EJUSTRETURN;
814 sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo);
815 sid &= ~(1 << slp->sl_hostid);
816 sid = ffs(sid) - 1;
817 ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid);
818 if (ti == NULL)
819 return EJUSTRETURN;
821 #ifdef NCV_STATICS
822 ncv_statics.reselect ++;
823 #endif /* NCV_STATICS */
824 bus_space_write_1(iot, ioh, cr0_dstid, sid);
825 return 0;
828 static int
829 ncv_disconnected(struct ncv_softc *sc, struct targ_info *ti)
831 struct scsi_low_softc *slp = &sc->sc_sclow;
832 bus_space_tag_t iot = sc->sc_iot;
833 bus_space_handle_t ioh = sc->sc_ioh;
835 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
836 bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL);
838 #ifdef NCV_STATICS
839 ncv_statics.disconnect ++;
840 #endif /* NCV_STATICS */
842 scsi_low_disconnected(slp, ti);
843 return 1;
846 /**************************************************************
847 * SEQUENCER
848 **************************************************************/
849 static int
850 ncv_target_nexus_establish(struct ncv_softc *sc)
852 struct scsi_low_softc *slp = &sc->sc_sclow;
853 struct targ_info *ti = slp->sl_Tnexus;
854 struct ncv_targ_info *nti = (void *) ti;
855 bus_space_tag_t iot = sc->sc_iot;
856 bus_space_handle_t ioh = sc->sc_ioh;
858 bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period);
859 bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset);
860 bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3);
861 return 0;
864 static int
865 ncv_lun_nexus_establish(struct ncv_softc *sc)
868 return 0;
871 static int
872 ncv_ccb_nexus_establish(struct ncv_softc *sc)
874 struct scsi_low_softc *slp = &sc->sc_sclow;
875 struct slccb *cb = slp->sl_Qnexus;
877 sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
878 return 0;
881 static int
882 ncv_catch_intr(struct ncv_softc *sc)
884 bus_space_tag_t iot = sc->sc_iot;
885 bus_space_handle_t ioh = sc->sc_ioh;
886 int wc;
887 u_int8_t status;
889 for (wc = 0; wc < NCV_DELAY_MAX / NCV_DELAY_INTERVAL; wc ++)
891 status = bus_space_read_1(iot, ioh, cr0_stat);
892 if ((status & STAT_INT) != 0)
893 return 0;
895 SCSI_LOW_DELAY(NCV_DELAY_INTERVAL);
897 return EJUSTRETURN;
901 ncvintr(void *arg)
903 struct ncv_softc *sc = arg;
904 struct scsi_low_softc *slp = &sc->sc_sclow;
905 bus_space_tag_t iot = sc->sc_iot;
906 bus_space_handle_t ioh = sc->sc_ioh;
907 struct targ_info *ti;
908 struct buf *bp;
909 u_int derror, flags;
910 int len;
911 u_int8_t regv, status, ireason;
913 again:
914 if (slp->sl_flags & HW_INACTIVE)
915 return 0;
917 /********************************************
918 * Status
919 ********************************************/
920 ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
921 status = bus_space_read_1(iot, ioh, cr0_stat);
922 if ((status & STAT_INT) == 0 || status == (u_int8_t) -1)
923 return 0;
925 ireason = bus_space_read_1(iot, ioh, cr0_istat);
926 if ((ireason & INTR_SBR) != 0)
928 u_int8_t val;
930 /* avoid power off hangup */
931 val = bus_space_read_1(iot, ioh, cr0_cfg1);
932 bus_space_write_1(iot, ioh, cr0_cfg1, val | C1_SRR);
934 /* status init */
935 scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT,
936 "bus reset (power off?)");
937 return 1;
940 /********************************************
941 * Debug section
942 ********************************************/
943 #ifdef NCV_DEBUG
944 if (ncv_debug)
946 scsi_low_print(slp, NULL);
947 kprintf("%s st %x ist %x\n\n", slp->sl_xname,
948 status, ireason);
949 #ifdef DDB
950 if (ncv_debug > 1)
951 SCSI_LOW_DEBUGGER("ncv");
952 #endif /* DDB */
954 #endif /* NCV_DEBUG */
956 /********************************************
957 * Reselect or Disconnect or Nexus check
958 ********************************************/
959 /* (I) reselect */
960 if (ireason == INTR_RESELECT)
962 if (ncv_reselected(sc) == EJUSTRETURN)
963 return 1;
966 /* (II) nexus */
967 if ((ti = slp->sl_Tnexus) == NULL)
968 return 0;
970 derror = 0;
971 if ((status & (STAT_PE | STAT_GE)) != 0)
973 slp->sl_error |= PARITYERR;
974 if ((status & PHASE_MASK) == MESSAGE_IN_PHASE)
975 scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
976 else
977 scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1);
978 derror = SCSI_LOW_DATA_PE;
981 if ((ireason & (INTR_DIS | INTR_ILL)) != 0)
983 if ((ireason & INTR_ILL) == 0)
984 return ncv_disconnected(sc, ti);
986 slp->sl_error |= FATALIO;
987 scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "illegal cmd");
988 return 1;
991 /********************************************
992 * Internal scsi phase
993 ********************************************/
994 switch (ti->ti_phase)
996 case PH_SELSTART:
997 scsi_low_arbit_win(slp);
998 SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
1000 if (sc->sc_selstop == 0)
1002 /* XXX:
1003 * Here scsi phases expected are
1004 * DATA PHASE:
1005 * MSGIN : target wants to disconnect the host.
1006 * STATUSIN : immediate command completed.
1007 * CMD PHASE : command out failed
1008 * MSGOUT : identify command failed.
1010 if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
1011 break;
1013 else
1015 if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
1016 break;
1017 if ((ireason & INTR_FC) != 0)
1019 SCSI_LOW_ASSERT_ATN(slp);
1022 SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
1023 break;
1025 case PH_RESEL:
1026 ncv_target_nexus_establish(sc);
1027 if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
1029 kprintf("%s: unexpected phase after reselect\n",
1030 slp->sl_xname);
1031 slp->sl_error |= FATALIO;
1032 scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
1033 return 1;
1035 break;
1037 default:
1038 if ((slp->sl_flags & HW_PDMASTART) != 0)
1040 ncv_pdma_end(sc, ti);
1042 break;
1045 /********************************************
1046 * Scsi phase sequencer
1047 ********************************************/
1048 switch (status & PHASE_MASK)
1050 case DATA_OUT_PHASE: /* data out */
1051 SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
1052 if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
1054 scsi_low_attention(slp);
1057 if (slp->sl_scp.scp_datalen <= 0)
1059 if ((ireason & INTR_BS) == 0)
1060 break;
1062 if ((slp->sl_error & PDMAERR) == 0)
1063 kprintf("%s: data underrun\n", slp->sl_xname);
1064 slp->sl_error |= PDMAERR;
1066 if ((slp->sl_flags & HW_WRITE_PADDING) != 0)
1068 u_int8_t padding[NCV_PADDING_SIZE];
1070 SCSI_LOW_BZERO(padding, sizeof(padding));
1071 ncv_pio_write(sc, padding, sizeof(padding));
1073 else
1075 kprintf("%s: write padding required\n",
1076 slp->sl_xname);
1079 else
1081 len = slp->sl_scp.scp_datalen;
1082 if ((ncv_io_control & NCV_WRITE_INTERRUPTS_DRIVEN) != 0)
1084 if (len > ncv_data_write_bytes)
1085 len = ncv_data_write_bytes;
1087 ncv_pio_write(sc, slp->sl_scp.scp_data, len);
1089 break;
1091 case DATA_IN_PHASE: /* data in */
1092 SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
1093 if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
1095 scsi_low_attention(slp);
1098 if (slp->sl_scp.scp_datalen <= 0)
1100 if ((ireason & INTR_BS) == 0)
1101 break;
1103 if ((slp->sl_error & PDMAERR) == 0)
1104 kprintf("%s: data overrun\n", slp->sl_xname);
1105 slp->sl_error |= PDMAERR;
1107 if ((slp->sl_flags & HW_READ_PADDING) != 0)
1109 u_int8_t padding[NCV_PADDING_SIZE];
1111 ncv_pio_read(sc, padding, sizeof(padding));
1113 else
1115 kprintf("%s: read padding required\n",
1116 slp->sl_xname);
1117 break;
1120 else
1122 len = slp->sl_scp.scp_datalen;
1123 if ((ncv_io_control & NCV_READ_INTERRUPTS_DRIVEN) != 0)
1125 if (len > ncv_data_read_bytes)
1126 len = ncv_data_read_bytes;
1128 ncv_pio_read(sc, slp->sl_scp.scp_data, len);
1130 break;
1132 case COMMAND_PHASE: /* cmd out */
1133 SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
1134 if (scsi_low_cmd(slp, ti) != 0)
1136 scsi_low_attention(slp);
1139 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1140 ncvhw_fpush(iot, ioh,
1141 slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
1142 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1143 break;
1145 case STATUS_PHASE: /* status in */
1146 SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
1147 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1148 bus_space_write_1(iot, ioh, cr0_cmd, CMD_ICCS);
1149 sc->sc_compseq = 1;
1150 break;
1152 default:
1153 break;
1155 case MESSAGE_OUT_PHASE: /* msg out */
1156 SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
1157 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1159 flags = SCSI_LOW_MSGOUT_UNIFY;
1160 if (ti->ti_ophase != ti->ti_phase)
1161 flags |= SCSI_LOW_MSGOUT_INIT;
1162 len = scsi_low_msgout(slp, ti, flags);
1164 if (len > 1 && slp->sl_atten == 0)
1166 scsi_low_attention(slp);
1169 ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len);
1170 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1171 SCSI_LOW_DEASSERT_ATN(slp);
1172 break;
1174 case MESSAGE_IN_PHASE: /* msg in */
1175 SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
1177 len = bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK;
1178 if (sc->sc_compseq != 0)
1180 sc->sc_compseq = 0;
1181 if ((ireason & INTR_FC) && len == 2)
1183 regv = bus_space_read_1(iot, ioh, cr0_sfifo);
1184 scsi_low_statusin(slp, ti, regv | derror);
1185 len --;
1187 else
1189 slp->sl_error |= FATALIO;
1190 scsi_low_assert_msg(slp, ti,
1191 SCSI_LOW_MSG_ABORT, 1);
1192 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
1193 cr0_cmd, CMD_MSGOK);
1194 break;
1197 else if (ireason & INTR_BS)
1199 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1200 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1201 if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
1203 if (ncv_catch_intr(sc) == 0)
1204 goto again;
1206 break;
1209 if ((ireason & INTR_FC) && len == 1)
1211 regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
1212 cr0_sfifo);
1213 if (scsi_low_msgin(slp, ti, regv | derror) == 0)
1215 if (scsi_low_is_msgout_continue(ti, 0) != 0)
1217 scsi_low_attention(slp);
1220 bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd,
1221 CMD_MSGOK);
1222 if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
1224 /* XXX:
1225 * clear a pending interrupt and sync with
1226 * a next interrupt!
1228 ncv_catch_intr(sc);
1231 else
1233 slp->sl_error |= FATALIO;
1234 scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
1235 bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd,
1236 CMD_MSGOK);
1238 break;
1241 return 1;