ncr53c500.c revision 73025
1/* $FreeBSD: head/sys/dev/ncv/ncr53c500.c 73025 2001-02-25 12:40:30Z non $ */ 2/* $NecBSD: ncr53c500.c,v 1.30 1999/07/23 21:00:04 honda Exp $ */ 3/* $NetBSD$ */ 4 5#define NCV_DEBUG 6#define NCV_STATICS 7 8/* 9 * [NetBSD for NEC PC-98 series] 10 * Copyright (c) 1995, 1996, 1997, 1998, 1999 11 * NetBSD/pc98 porting staff. All rights reserved. 12 * Copyright (c) 1995, 1996, 1997, 1998, 1999 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#include "opt_ddb.h" 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/disklabel.h> 44#if defined(__FreeBSD__) && __FreeBSD_version >= 500001 45#include <sys/bio.h> 46#endif 47#include <sys/buf.h> 48#include <sys/queue.h> 49#include <sys/malloc.h> 50#include <sys/device_port.h> 51#include <sys/errno.h> 52 53#include <vm/vm.h> 54 55#ifdef __NetBSD__ 56#include <machine/bus.h> 57#include <machine/intr.h> 58 59#include <dev/scsipi/scsi_all.h> 60#include <dev/scsipi/scsipi_all.h> 61#include <dev/scsipi/scsiconf.h> 62#include <dev/scsipi/scsi_disk.h> 63 64#include <machine/dvcfg.h> 65#include <machine/physio_proc.h> 66 67#include <i386/Cbus/dev/scsi_low.h> 68 69#include <i386/Cbus/dev/ncr53c500reg.h> 70#include <i386/Cbus/dev/ncr53c500hw.h> 71#include <i386/Cbus/dev/ncr53c500var.h> 72 73#include <i386/Cbus/dev/ncr53c500hwtab.h> 74#endif /* __NetBSD__ */ 75 76#ifdef __FreeBSD__ 77#include <machine/clock.h> 78#define delay(time) DELAY(time) 79 80#include <machine/cpu.h> 81#include <machine/bus_pio.h> 82#include <machine/bus.h> 83 84#include <machine/dvcfg.h> 85#include <machine/physio_proc.h> 86 87#include <cam/scsi/scsi_low.h> 88 89#include <dev/ncv/ncr53c500reg.h> 90#include <dev/ncv/ncr53c500hw.h> 91#include <dev/ncv/ncr53c500var.h> 92 93#include <dev/ncv/ncr53c500hwtab.h> 94 95#if __FreeBSD_version < 400001 96#include "ncv.h" 97struct ncv_softc *ncvdata[NNCV]; 98#endif 99#endif /* __FreeBSD__ */ 100 101/*************************************************** 102 * DEBUG 103 ***************************************************/ 104#ifndef DDB 105#define Debugger() panic("should call debugger here (ncr53c500.c)") 106#else /* ! DDB */ 107#ifdef __FreeBSD__ 108#define Debugger() Debugger("ncv") 109#endif /* __FreeBSD__ */ 110#endif 111 112#ifdef NCV_DEBUG 113int ncv_debug; 114#endif /* NCV_DEBUG */ 115 116#ifdef NCV_STATICS 117struct ncv_statics { 118 int disconnect; 119 int reselect; 120} ncv_statics[NCV_NTARGETS]; 121#endif /* NCV_STATICS */ 122 123/*************************************************** 124 * ISA DEVICE STRUCTURE 125 ***************************************************/ 126extern struct cfdriver ncv_cd; 127 128/************************************************************** 129 * DECLARE 130 **************************************************************/ 131#ifdef __NetBSD__ 132extern int delaycount; 133#endif 134 135/* static */ 136static void ncv_pio_read __P((struct ncv_softc *, u_int8_t *, u_int)); 137static void ncv_pio_write __P((struct ncv_softc *, u_int8_t *, u_int)); 138static int ncv_msg __P((struct ncv_softc *, struct targ_info *, u_int)); 139static __inline int ncv_reselected __P((struct ncv_softc *)); 140static __inline int ncv_disconnected __P((struct ncv_softc *, struct targ_info *)); 141static __inline void ncv_pdma_end __P((struct ncv_softc *sc, struct targ_info *)); 142 143static __inline void ncvhw_set_count __P((bus_space_tag_t, bus_space_handle_t, int)); 144static __inline u_int ncvhw_get_count __P((bus_space_tag_t, bus_space_handle_t)); 145static __inline void ncvhw_select_register_0 __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); 146static __inline void ncvhw_select_register_1 __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); 147static __inline void ncvhw_fpush __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *, int)); 148 149static int ncv_world_start __P((struct ncv_softc *, int)); 150static void ncvhw_bus_reset __P((struct ncv_softc *)); 151static void ncvhw_reset __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); 152static int ncvhw_check __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); 153static void ncvhw_init __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *)); 154static int ncvhw_start_selection __P((struct ncv_softc *sc, struct slccb *)); 155static void ncvhw_attention __P((struct ncv_softc *)); 156static int ncv_nexus __P((struct ncv_softc *, struct targ_info *)); 157#ifdef NCV_POWER_CONTROL 158static int ncvhw_power __P((struct ncv_softc *, u_int)); 159#endif 160static int ncv_targ_init __P((struct ncv_softc *, struct targ_info *)); 161 162struct scsi_low_funcs ncv_funcs = { 163 SC_LOW_INIT_T ncv_world_start, 164 SC_LOW_BUSRST_T ncvhw_bus_reset, 165 SC_LOW_TARG_INIT_T ncv_targ_init, 166 167 SC_LOW_SELECT_T ncvhw_start_selection, 168 SC_LOW_NEXUS_T ncv_nexus, 169 170 SC_LOW_ATTEN_T ncvhw_attention, 171 SC_LOW_MSG_T ncv_msg, 172 173 SC_LOW_POLL_T ncvintr, 174 175 NULL, /* SC_LOW_POWER_T ncvhw_power, */ 176}; 177 178/************************************************************** 179 * hwfuncs 180 **************************************************************/ 181static __inline void 182ncvhw_select_register_0(iot, ioh, hw) 183 bus_space_tag_t iot; 184 bus_space_handle_t ioh; 185 struct ncv_hw *hw; 186{ 187 188 bus_space_write_1(iot, ioh, cr0_cfg4, hw->cfg4); 189} 190 191static __inline void 192ncvhw_select_register_1(iot, ioh, hw) 193 bus_space_tag_t iot; 194 bus_space_handle_t ioh; 195 struct ncv_hw *hw; 196{ 197 198 bus_space_write_1(iot, ioh, cr1_cfg5, hw->cfg5); 199} 200 201static __inline void 202ncvhw_fpush(iot, ioh, buf, len) 203 bus_space_tag_t iot; 204 bus_space_handle_t ioh; 205 u_int8_t *buf; 206 int len; 207{ 208 int ptr; 209 210 for (ptr = 0; ptr < len; ptr ++) 211 bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]); 212} 213 214static int 215ncvhw_check(iot, ioh, hw) 216 bus_space_tag_t iot; 217 bus_space_handle_t ioh; 218 struct ncv_hw *hw; 219{ 220 u_int8_t stat; 221 222 ncvhw_select_register_0(iot, ioh, hw); 223 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); 224 if (bus_space_read_1(iot, ioh, cr0_cmd) != (CMD_NOP | CMD_DMA)) 225 { 226#ifdef NCV_DEBUG 227 printf("ncv: cr0_cmd CMD_NOP|CMD_DMA failed\n"); 228#endif /* NCV_DEBUG */ 229 return ENODEV; 230 } 231 232 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 233 if (bus_space_read_1(iot, ioh, cr0_cmd) != CMD_NOP) 234 { 235#ifdef NCV_DEBUG 236 printf("ncv: cr0_cmd CMD_NOP failed\n"); 237#endif /* NCV_DEBUG */ 238 return ENODEV; 239 } 240 241 /* hardware reset */ 242 ncvhw_reset(iot, ioh, hw); 243 ncvhw_init(iot, ioh, hw); 244 245 /* bus reset */ 246 ncvhw_select_register_0(iot, ioh, hw); 247 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 248 bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI); 249 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); 250 delay(100 * 1000); 251 252 /* check response */ 253 bus_space_read_1(iot, ioh, cr0_stat); 254 stat = bus_space_read_1(iot, ioh, cr0_istat); 255 delay(1000); 256 257 if (((stat & INTR_SBR) == 0) || 258 (bus_space_read_1(iot, ioh, cr0_istat) & INTR_SBR)) 259 { 260#ifdef NCV_DEBUG 261 printf("ncv: cr0_istat SCSI BUS RESET failed\n"); 262#endif /* NCV_DEBUG */ 263 return ENODEV; 264 } 265 266 return 0; 267} 268 269static void 270ncvhw_reset(iot, ioh, hw) 271 bus_space_tag_t iot; 272 bus_space_handle_t ioh; 273 struct ncv_hw *hw; 274{ 275 276 ncvhw_select_register_0(iot, ioh, hw); 277 278 /* dummy cmd twice */ 279 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 280 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 281 282 /* chip reset */ 283 bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTCHIP); 284 285 /* again dummy cmd twice */ 286 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 287 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 288} 289 290static void 291ncvhw_init(iot, ioh, hw) 292 bus_space_tag_t iot; 293 bus_space_handle_t ioh; 294 struct ncv_hw *hw; 295{ 296 297 ncvhw_select_register_0(iot, ioh, hw); 298 bus_space_write_1(iot, ioh, cr0_clk, hw->clk); 299 bus_space_write_1(iot, ioh, cr0_srtout, SEL_TOUT); 300 bus_space_write_1(iot, ioh, cr0_period, 0); 301 bus_space_write_1(iot, ioh, cr0_offs, 0); 302 303 bus_space_write_1(iot, ioh, cr0_cfg1, hw->cfg1); 304 bus_space_write_1(iot, ioh, cr0_cfg2, hw->cfg2); 305 bus_space_write_1(iot, ioh, cr0_cfg3, hw->cfg3); 306 bus_space_write_1(iot, ioh, cr0_tchsb, 0); 307 308 ncvhw_select_register_1(iot, ioh, hw); 309 bus_space_write_1(iot, ioh, cr1_fstat, 0x0); 310 bus_space_write_1(iot, ioh, cr1_pflag, 0x0); 311 bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE); 312 313 ncvhw_select_register_0(iot, ioh, hw); 314} 315 316#ifdef NCV_POWER_CONTROL 317static int 318ncvhw_power(sc, flags) 319 struct ncv_softc *sc; 320 u_int flags; 321{ 322 struct scsi_low_softc *slp = &sc->sc_sclow; 323 bus_space_tag_t iot = sc->sc_iot; 324 bus_space_handle_t ioh = sc->sc_ioh; 325 326 if (flags == SCSI_LOW_POWDOWN) 327 { 328 printf("%s power down\n", slp->sl_xname); 329 ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 330 bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_POWDOWN); 331 } 332 else 333 { 334 switch (sc->sc_rstep) 335 { 336 case 0: 337 printf("%s resume step O\n", slp->sl_xname); 338 ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 339 bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE); 340 break; 341 342 case 1: 343 printf("%s resume step I\n", slp->sl_xname); 344 ncvhw_reset(iot, ioh, &sc->sc_hw); 345 ncvhw_init(iot, ioh, &sc->sc_hw); 346 break; 347 } 348 } 349 350 return 0; 351} 352#endif /* NCV_POWER_CONTROL */ 353 354/************************************************************** 355 * scsi low interface 356 **************************************************************/ 357static void 358ncvhw_attention(sc) 359 struct ncv_softc *sc; 360{ 361 362 bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, CMD_SETATN); 363 delay(10); 364} 365 366static void 367ncvhw_bus_reset(sc) 368 struct ncv_softc *sc; 369{ 370 bus_space_tag_t iot = sc->sc_iot; 371 bus_space_handle_t ioh = sc->sc_ioh; 372 373 ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 374 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 375 bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI); 376 bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); 377} 378 379static int 380ncvhw_start_selection(sc, cb) 381 struct ncv_softc *sc; 382 struct slccb *cb; 383{ 384 struct scsi_low_softc *slp = &sc->sc_sclow; 385 bus_space_tag_t iot = sc->sc_iot; 386 bus_space_handle_t ioh = sc->sc_ioh; 387 struct targ_info *ti = cb->ti; 388 int s; 389 u_int8_t msg; 390 391 msg = ID_MSG_SETUP(ti); 392 sc->sc_compseq = 0; 393 ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 394 395 s = splhigh(); 396 397 if (slp->sl_disc > 0 && 398 (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat) & STAT_INT)) 399 { 400 splx(s); 401 return SCSI_LOW_START_FAIL; 402 } 403 404 bus_space_write_1(iot, ioh, cr0_dstid, ti->ti_id); 405 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 406 bus_space_write_1(iot, ioh, cr0_sfifo, msg); 407 408 if (scsi_low_is_msgout_continue(ti) != 0) 409 { 410 bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATNS); 411 sc->sc_selstop = 1; 412 } 413 else 414 { 415 /* XXX: 416 * emulate nexus call because ncv bypasses CMD phase. 417 */ 418 scsi_low_cmd(slp, ti); 419 ncvhw_fpush(iot, ioh, 420 slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); 421 bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATN); 422 sc->sc_selstop = 0; 423 } 424 splx(s); 425 426 SCSI_LOW_TARGET_ASSERT_ATN(ti); 427 SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); 428 return SCSI_LOW_START_OK; 429} 430 431static int 432ncv_world_start(sc, fdone) 433 struct ncv_softc *sc; 434 int fdone; 435{ 436 struct scsi_low_softc *slp = &sc->sc_sclow; 437 bus_space_tag_t iot = sc->sc_iot; 438 bus_space_handle_t ioh = sc->sc_ioh; 439 u_int8_t stat; 440#ifdef __FreeBSD__ 441 intrmask_t s; 442#endif 443 444 ncvhw_reset(iot, ioh, &sc->sc_hw); 445 ncvhw_init(iot, ioh, &sc->sc_hw); 446 447#ifdef __FreeBSD__ 448 s = splcam(); 449#endif 450 scsi_low_bus_reset(slp); 451 452 ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 453 bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat); 454 stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat); 455#ifdef __FreeBSD__ 456 splx(s); 457#endif 458 delay(1000); 459 460 if (((stat & INTR_SBR) == 0) || 461 (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR)) 462 return ENODEV; 463 464 SOFT_INTR_REQUIRED(slp); 465 return 0; 466} 467 468static int 469ncv_msg(sc, ti, msg) 470 struct ncv_softc *sc; 471 struct targ_info *ti; 472 u_int msg; 473{ 474 struct ncv_targ_info *nti = (void *) ti; 475 u_int hwcycle, period; 476 477 if ((msg & SCSI_LOW_MSG_SYNCH) == 0) 478 return 0; 479 480 period = ti->ti_maxsynch.period; 481 hwcycle = 1000 / ((sc->sc_hw.clk == 0) ? 40 : (5 * sc->sc_hw.clk)); 482 483 if (period < 200 / 4 && period >= 100 / 4) 484 nti->nti_reg_cfg3 |= C3_FSCSI; 485 else 486 nti->nti_reg_cfg3 &= ~C3_FSCSI; 487 488 period = ((period * 40 / hwcycle) + 5) / 10; 489 nti->nti_reg_period = period & 0x1f; 490 nti->nti_reg_offset = ti->ti_maxsynch.offset; 491 return 0; 492} 493 494static int 495ncv_targ_init(sc, ti) 496 struct ncv_softc *sc; 497 struct targ_info *ti; 498{ 499 struct ncv_targ_info *nti = (void *) ti; 500 501 ti->ti_maxsynch.period = sc->sc_hw.mperiod; 502 ti->ti_maxsynch.offset = sc->sc_hw.moffset; 503 504 nti->nti_reg_cfg3 = sc->sc_hw.cfg3; 505 nti->nti_reg_period = 0; 506 nti->nti_reg_offset = 0; 507 return 0; 508} 509 510/************************************************************** 511 * General probe attach 512 **************************************************************/ 513static int ncv_setup_img __P((struct ncv_hw *, u_int, int)); 514 515static int 516ncv_setup_img(hw, dvcfg, hsid) 517 struct ncv_hw *hw; 518 u_int dvcfg; 519 int hsid; 520{ 521 522 if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F) 523 { 524 printf("ncv: invalid dvcfg flags\n"); 525 return EINVAL; 526 } 527 528 if (NCV_C5IMG(dvcfg) != 0) 529 { 530 hw->cfg5 = NCV_C5IMG(dvcfg); 531 hw->clk = NCV_CLKFACTOR(dvcfg); 532 533 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) 534 hw->mperiod = 100 / 4; 535 536 /* XXX: 537 * RATOC scsi cards have fatal fifo asic bug. 538 * To avoid it, currently make sync offset 0 (async)! 539 */ 540 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG) 541 { 542 hw->mperiod = 0; 543 hw->moffset = 0; 544 } 545 546 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1) 547 hw->cfg2 &= ~C2_SCSI2; 548 549 if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW) 550 hw->cfg1 |= C1_SLOW; 551 } 552 553 /* setup configuration image 3 */ 554 if (hw->clk != CLK_40M_F && hw->clk <= CLK_25M_F) 555 hw->cfg3 &= ~C3_FCLK; 556 557 /* setup configuration image 1 */ 558 hw->cfg1 = (hw->cfg1 & 0xf0) | hsid; 559 return 0; 560} 561 562int 563ncvprobesubr(iot, ioh, dvcfg, hsid) 564 bus_space_tag_t iot; 565 bus_space_handle_t ioh; 566 u_int dvcfg; 567 int hsid; 568{ 569 struct ncv_hw hwtab; 570 571 hwtab = ncv_template; 572 if (ncv_setup_img(&hwtab, dvcfg, hsid)) 573 return 0; 574 if (ncvhw_check(iot, ioh, &hwtab) != 0) 575 return 0; 576 577 return 1; 578} 579 580int 581ncvprint(aux, name) 582 void *aux; 583 const char *name; 584{ 585 586 if (name != NULL) 587 printf("%s: scsibus ", name); 588 return UNCONF; 589} 590 591void 592ncvattachsubr(sc) 593 struct ncv_softc *sc; 594{ 595 struct scsi_low_softc *slp = &sc->sc_sclow; 596 597 printf("\n"); 598 sc->sc_hw = ncv_template; 599 ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid); 600#ifdef __FreeBSD__ 601 sc->sc_wc = 0x2000 * 2000; /* XXX need calibration */ 602#else /* NetBSD */ 603 sc->sc_wc = delaycount * 2000; /* 2 sec */ 604#endif 605 slp->sl_funcs = &ncv_funcs; 606 (void) scsi_low_attach(slp, 2, NCV_NTARGETS, NCV_NLUNS, 607 sizeof(struct ncv_targ_info)); 608} 609 610/************************************************************** 611 * PDMA 612 **************************************************************/ 613static __inline void 614ncvhw_set_count(iot, ioh, count) 615 bus_space_tag_t iot; 616 bus_space_handle_t ioh; 617 int count; 618{ 619 620 bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count); 621 bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY)); 622 bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2))); 623} 624 625static __inline u_int 626ncvhw_get_count(iot, ioh) 627 bus_space_tag_t iot; 628 bus_space_handle_t ioh; 629{ 630 u_int count; 631 632 count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb); 633 count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY; 634 count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2); 635 return count; 636} 637 638static __inline void 639ncv_pdma_end(sc, ti) 640 struct ncv_softc *sc; 641 struct targ_info *ti; 642{ 643 struct scsi_low_softc *slp = &sc->sc_sclow; 644 bus_space_tag_t iot = sc->sc_iot; 645 bus_space_handle_t ioh = sc->sc_ioh; 646 int len; 647 648 slp->sl_flags &= ~HW_PDMASTART; 649 if (ti->ti_phase == PH_DATA) 650 { 651 len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh); 652 if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) 653 len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh, 654 cr0_sffl) & CR0_SFFLR_BMASK); 655 656 if ((u_int) len <= (u_int) slp->sl_scp.scp_datalen) 657 { 658 slp->sl_scp.scp_data += (slp->sl_scp.scp_datalen - len); 659 slp->sl_scp.scp_datalen = len; 660 if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) && 661 sc->sc_tdatalen != len) 662 goto bad; 663 } 664 else 665 { 666bad: 667 slp->sl_error |= PDMAERR; 668 printf("%s stragne count hw 0x%x soft 0x%x tlen 0x%x\n", 669 slp->sl_xname, len, slp->sl_scp.scp_datalen, 670 sc->sc_tdatalen); 671 } 672 } 673 else 674 { 675 printf("%s data phase miss\n", slp->sl_xname); 676 slp->sl_error |= PDMAERR; 677 } 678 679 ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 680 bus_space_write_1(iot, ioh, cr1_fstat, 0); 681 ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 682} 683 684static void 685ncv_pio_read(sc, buf, reqlen) 686 struct ncv_softc *sc; 687 u_int8_t *buf; 688 u_int reqlen; 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 tout = sc->sc_wc; 694 register u_int8_t fstat; 695 696 ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 697 bus_space_write_1(iot, ioh, cr1_pflag, 0); 698 699 ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 700 ncvhw_set_count(iot, ioh, reqlen); 701 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA); 702 703 ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 704 bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN); 705 slp->sl_flags |= HW_PDMASTART; 706 707 while (reqlen >= FIFO_F_SZ && tout > 0) 708 { 709 fstat = bus_space_read_1(iot, ioh, cr1_fstat); 710 if (fstat & FIFO_F) 711 { 712#define NCV_FAST32_ACCESS 713#ifdef NCV_FAST32_ACCESS 714 bus_space_read_multi_4(iot, ioh, cr1_fdata, 715 (u_int32_t *) buf, FIFO_F_SZ / 4); 716#else /* !NCV_FAST32_ACCESS */ 717 bus_space_read_multi_2(iot, ioh, cr1_fdata, 718 (u_int16_t *) buf, FIFO_F_SZ / 2); 719#endif /* !NCV_FAST32_ACCESS */ 720 buf += FIFO_F_SZ; 721 reqlen -= FIFO_F_SZ; 722 continue; 723 } 724 else if (fstat & FIFO_BRK) 725 break; 726 727 tout --; 728 } 729 730 if (reqlen >= FIFO_2_SZ) 731 { 732 fstat = bus_space_read_1(iot, ioh, cr1_fstat); 733 if (fstat & FIFO_2) 734 { 735#ifdef NCV_FAST32_ACCESS 736 bus_space_read_multi_4(iot, ioh, cr1_fdata, 737 (u_int32_t *) buf, FIFO_2_SZ / 4); 738#else /* !NCV_FAST32_ACCESS */ 739 bus_space_read_multi_2(iot, ioh, cr1_fdata, 740 (u_int16_t *) buf, FIFO_2_SZ / 2); 741#endif /* !NCV_FAST32_ACCESS */ 742 buf += FIFO_2_SZ; 743 reqlen -= FIFO_2_SZ; 744 } 745 } 746 747 while (reqlen > 0 && tout > 0) 748 { 749 fstat = bus_space_read_1(iot, ioh, cr1_fstat); 750 if ((fstat & FIFO_E) == 0) 751 { 752 *buf++ = bus_space_read_1(iot, ioh, cr1_fdata); 753 reqlen --; 754 continue; 755 } 756 else if (fstat & FIFO_BRK) 757 break; 758 759 tout --; 760 } 761 762 ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 763 sc->sc_tdatalen = reqlen; 764 765 if (tout <= 0) 766 printf("%s pio read timeout\n", slp->sl_xname); 767} 768 769static void 770ncv_pio_write(sc, buf, reqlen) 771 struct ncv_softc *sc; 772 u_int8_t *buf; 773 u_int reqlen; 774{ 775 struct scsi_low_softc *slp = &sc->sc_sclow; 776 bus_space_tag_t iot = sc->sc_iot; 777 bus_space_handle_t ioh = sc->sc_ioh; 778 int tout = sc->sc_wc; 779 register u_int8_t fstat; 780 781 ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 782 bus_space_write_1(iot, ioh, cr1_pflag, 0); 783 784 ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 785 ncvhw_set_count(iot, ioh, reqlen); 786 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA); 787 788 ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 789 bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN); 790 slp->sl_flags |= HW_PDMASTART; 791 792 while (reqlen >= FIFO_F_SZ && tout > 0) 793 { 794 fstat = bus_space_read_1(iot, ioh, cr1_fstat); 795 if (fstat & FIFO_BRK) 796 goto done; 797 798 if (fstat & FIFO_E) 799 { 800#ifdef NCV_FAST32_ACCESS 801 bus_space_write_multi_4(iot, ioh, cr1_fdata, 802 (u_int32_t *) buf, FIFO_F_SZ / 4); 803#else /* !NCV_FAST32_ACCESS */ 804 bus_space_write_multi_2(iot, ioh, cr1_fdata, 805 (u_int16_t *) buf, FIFO_F_SZ / 2); 806#endif /* !NCV_FAST32_ACCESS */ 807 buf += FIFO_F_SZ; 808 reqlen -= FIFO_F_SZ; 809 } 810 else 811 tout --; 812 } 813 814 while (reqlen > 0 && tout > 0) 815 { 816 fstat = bus_space_read_1(iot, ioh, cr1_fstat); 817 if (fstat & FIFO_BRK) 818 break; 819 820 if ((fstat & FIFO_F) == 0) /* fifo not full */ 821 { 822 bus_space_write_1(iot, ioh, cr1_fdata, *buf++); 823 reqlen --; 824 } 825 else 826 tout --; 827 } 828 829done: 830 ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 831 832 if (tout <= 0) 833 printf("%s pio write timeout\n", slp->sl_xname); 834} 835 836/************************************************************** 837 * disconnect & reselect (HW low) 838 **************************************************************/ 839static __inline int 840ncv_reselected(sc) 841 struct ncv_softc *sc; 842{ 843 struct scsi_low_softc *slp = &sc->sc_sclow; 844 bus_space_tag_t iot = sc->sc_iot; 845 bus_space_handle_t ioh = sc->sc_ioh; 846 struct targ_info *ti; 847 u_int sid; 848 849 if ((bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK) != 2) 850 { 851 printf("%s illegal fifo bytes\n", slp->sl_xname); 852 scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused"); 853 return EJUSTRETURN; 854 } 855 856 sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo); 857 sid = ffs(sid) - 1; 858 ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid); 859 if (ti == NULL) 860 return EJUSTRETURN; 861 862#ifdef NCV_STATICS 863 ncv_statics[sid].reselect ++; 864#endif /* NCV_STATICS */ 865 bus_space_write_1(iot, ioh, cr0_dstid, sid); 866 return 0; 867} 868 869static __inline int 870ncv_disconnected(sc, ti) 871 struct ncv_softc *sc; 872 struct targ_info *ti; 873{ 874 struct scsi_low_softc *slp = &sc->sc_sclow; 875 bus_space_tag_t iot = sc->sc_iot; 876 bus_space_handle_t ioh = sc->sc_ioh; 877 878 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 879 bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1); 880 bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL); 881 882#ifdef NCV_STATICS 883 if (slp->sl_msgphase == MSGPH_DISC) 884 ncv_statics[ti->ti_id].disconnect ++; 885#endif /* NCV_STATICS */ 886 887 scsi_low_disconnected(slp, ti); 888 return 1; 889} 890 891/************************************************************** 892 * SEQUENCER 893 **************************************************************/ 894static int 895ncv_nexus(sc, ti) 896 struct ncv_softc *sc; 897 struct targ_info *ti; 898{ 899 bus_space_tag_t iot = sc->sc_iot; 900 bus_space_handle_t ioh = sc->sc_ioh; 901 struct lun_info *li = ti->ti_li; 902 struct ncv_targ_info *nti = (void *) ti; 903 904 if (li->li_flags & SCSI_LOW_NOPARITY) 905 bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1); 906 else 907 bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1 | C1_PARENB); 908 bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period); 909 bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset); 910 bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3); 911 return 0; 912} 913 914int 915ncvintr(arg) 916 void *arg; 917{ 918 struct ncv_softc *sc = arg; 919 struct scsi_low_softc *slp = &sc->sc_sclow; 920 bus_space_tag_t iot = sc->sc_iot; 921 bus_space_handle_t ioh = sc->sc_ioh; 922 struct targ_info *ti; 923 struct physio_proc *pp; 924 struct buf *bp; 925 int len, identify; 926 u_int8_t regv, status, ireason; 927 928 if (slp->sl_flags & HW_INACTIVE) 929 return 0; 930 931 /******************************************** 932 * Status 933 ********************************************/ 934 ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 935 status = bus_space_read_1(iot, ioh, cr0_stat); 936 if ((status & STAT_INT) == 0) 937 return 0; 938 939 ireason = bus_space_read_1(iot, ioh, cr0_istat); 940 if (ireason & INTR_SBR) 941 { 942 u_int8_t val; 943 944 /* avoid power off hangup */ 945 val = bus_space_read_1(iot, ioh, cr0_cfg1); 946 bus_space_write_1(iot, ioh, cr0_cfg1, val | C1_SRR); 947 948 /* status init */ 949 scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, 950 "bus reset (power off?)"); 951 return 1; 952 } 953 954 /******************************************** 955 * Debug section 956 ********************************************/ 957#ifdef NCV_DEBUG 958 if (ncv_debug) 959 { 960 scsi_low_print(slp, NULL); 961 printf("%s st %x ist %x\n\n", slp->sl_xname, 962 status, ireason); 963 if (ncv_debug > 1) 964 Debugger(); 965 } 966#endif /* NCV_DEBUG */ 967 968 /******************************************** 969 * Reselect or Disconnect or Nexus check 970 ********************************************/ 971 /* (I) reselect */ 972 if (ireason == INTR_RESELECT) 973 { 974 if (ncv_reselected(sc) == EJUSTRETURN) 975 return 1; 976 } 977 978 /* (II) nexus */ 979 if ((ti = slp->sl_nexus) == NULL) 980 return 0; 981 982 if ((status & (STAT_PE | STAT_GE)) != 0) 983 { 984 slp->sl_error |= PARITYERR; 985 if (ti->ti_phase == PH_MSGIN) 986 scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 1); 987 else 988 scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1); 989 } 990 991 if ((ireason & (INTR_DIS | INTR_ILL)) != 0) 992 { 993 if ((ireason & INTR_ILL) == 0) 994 return ncv_disconnected(sc, ti); 995 996 slp->sl_error |= FATALIO; 997 scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "illegal cmd"); 998 return 1; 999 } 1000 1001 /******************************************** 1002 * Internal scsi phase 1003 ********************************************/ 1004 switch (ti->ti_phase) 1005 { 1006 case PH_SELSTART: 1007 scsi_low_arbit_win(slp, ti); 1008 SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); 1009 identify = 0; 1010 1011 if (sc->sc_selstop == 0) 1012 { 1013 /* XXX: 1014 * Here scsi phases expected are 1015 * DATA PHASE: 1016 * MSGIN : target wants to disconnect the host. 1017 * STATUSIN : immediate command completed. 1018 * MSGOUT : identify command failed. 1019 */ 1020 if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) 1021 break; 1022 identify = 1; 1023 } 1024 else 1025 { 1026 /* XXX: 1027 * Here scsi phase should be MSGOUT. 1028 * The driver NEVER supports devices 1029 * which neglect ATN singal. 1030 */ 1031 if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) 1032 { 1033 slp->sl_error |= FATALIO; 1034 scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 1035 "msgout error"); 1036 return 1; 1037 } 1038 1039 if ((ireason & INTR_FC) == 0) 1040 identify = 1; 1041 } 1042 1043 if (identify != 0) 1044 { 1045 printf("%s msg identify failed\n", slp->sl_xname); 1046 scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0); 1047 } 1048 break; 1049 1050 case PH_RESEL: 1051 if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) 1052 { 1053 scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); 1054 return 1; 1055 } 1056 break; 1057 1058 default: 1059 if (slp->sl_flags & HW_PDMASTART) 1060 ncv_pdma_end(sc, ti); 1061 break; 1062 } 1063 1064 /******************************************** 1065 * Scsi phase sequencer 1066 ********************************************/ 1067 switch (status & PHASE_MASK) 1068 { 1069 case DATA_OUT_PHASE: /* data out */ 1070 SCSI_LOW_SETUP_PHASE(ti, PH_DATA); 1071 if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) 1072 break; 1073 1074 pp = physio_proc_enter(bp); 1075 ncv_pio_write(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen); 1076 physio_proc_leave(pp); 1077 break; 1078 1079 case DATA_IN_PHASE: /* data in */ 1080 SCSI_LOW_SETUP_PHASE(ti, PH_DATA); 1081 if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) 1082 break; 1083 1084 pp = physio_proc_enter(bp); 1085 ncv_pio_read(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen); 1086 physio_proc_leave(pp); 1087 break; 1088 1089 case COMMAND_PHASE: /* cmd out */ 1090 SCSI_LOW_SETUP_PHASE(ti, PH_CMD); 1091 if (scsi_low_cmd(slp, ti) != 0) 1092 break; 1093 1094 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 1095 ncvhw_fpush(iot, ioh, 1096 slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); 1097 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); 1098 break; 1099 1100 case STATUS_PHASE: /* status in */ 1101 SCSI_LOW_SETUP_PHASE(ti, PH_STAT); 1102 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 1103 bus_space_write_1(iot, ioh, cr0_cmd, CMD_ICCS); 1104 sc->sc_compseq = 1; 1105 break; 1106 1107 default: 1108 break; 1109 1110 case MESSAGE_OUT_PHASE: /* msg out */ 1111 SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); 1112 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 1113 1114 len = scsi_low_msgout(slp, ti); 1115 ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len); 1116 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); 1117 if (scsi_low_is_msgout_continue(ti) == 0) 1118 bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTATN); 1119 break; 1120 1121 case MESSAGE_IN_PHASE: /* msg in */ 1122 SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 1123 1124 len = bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK; 1125 if (sc->sc_compseq != 0) 1126 { 1127 sc->sc_compseq = 0; 1128 if ((ireason & INTR_FC) && len == 2) 1129 { 1130 ti->ti_status = 1131 bus_space_read_1(iot, ioh, cr0_sfifo); 1132 len --; 1133 } 1134 else 1135 { 1136 scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 1137 "compseq error"); 1138 break; 1139 } 1140 } 1141 else if (ireason & INTR_BS) 1142 { 1143 bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 1144 bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); 1145 break; 1146 } 1147 1148 if ((ireason & INTR_FC) && len == 1) 1149 { 1150 regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 1151 cr0_sfifo); 1152 scsi_low_msgin(slp, ti, regv); 1153 bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, 1154 CMD_MSGOK); 1155 } 1156 else 1157 { 1158 slp->sl_error |= MSGERR; 1159 printf("%s st %x ist %x\n\n", slp->sl_xname, 1160 status, ireason); 1161 scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 1162 "hw msgin error"); 1163 } 1164 break; 1165 } 1166 1167 return 1; 1168} 1169