1/*- 2 * Copyright (c) 1994 Ludd, University of Lule}, Sweden. 3 * Copyright (c) 2000 Sergey A. Babkin 4 * All rights reserved. 5 * 6 * Written by Olof Johansson (offe@ludd.luth.se) 1995. 7 * Based on code written by Theo de Raadt (deraadt@fsa.ca). 8 * Resurrected, ported to CAM and generally cleaned up by Sergey Babkin 9 * <babkin@bellatlantic.net> or <babkin@users.sourceforge.net>. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed at Ludd, University of Lule} 22 * and by the FreeBSD project. 23 * 4. 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 WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 */ 38 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD$"); 41 42/* All bugs are subject to removal without further notice */ 43 44/* 45 * offe 01/07/95 46 * 47 * This version of the driver _still_ doesn't implement scatter/gather for the 48 * WD7000-FASST2. This is due to the fact that my controller doesn't seem to 49 * support it. That, and the lack of documentation makes it impossible for me 50 * to implement it. What I've done instead is allocated a local buffer, 51 * contiguous buffer big enough to handle the requests. I haven't seen any 52 * read/write bigger than 64k, so I allocate a buffer of 64+16k. The data 53 * that needs to be DMA'd to/from the controller is copied to/from that 54 * buffer before/after the command is sent to the card. 55 * 56 * SB 03/30/00 57 * 58 * An intermediate buffer is needed anyway to make sure that the buffer is 59 * located under 16MB, otherwise it's out of reach of ISA cards. I've added 60 * optimizations to allocate space in buffer in fragments. 61 */ 62 63/* 64 * Jumpers: (see The Ref(TM) for more info) 65 * W1/W2 - interrupt selection: 66 * W1 (1-2) IRQ3, (3-4) IRQ4, (5-6) IRQ5, (7-8) IRQ7, (9-10) IRQ9 67 * W2 (21-22) IRQ10, (19-20) IRQ11, (17-18) IRQ12, (15-16) IRQ14, (13-14) IRQ15 68 * 69 * W2 - DRQ/DACK selection, DRQ and DACK must be the same: 70 * (5-6) DRQ5 (11-12) DACK5 71 * (3-4) DRQ6 (9-10) DACK6 72 * (1-2) DRQ7 (7-8) DACK7 73 * 74 * W3 - I/O address selection: open pair of pins (OFF) means 1, jumpered (ON) means 0 75 * pair (1-2) is bit 3, ..., pair (9-10) is bit 7. All the other bits are equal 76 * to the value 0x300. In bitwise representation that would be: 77 * 0 0 1 1 (9-10) (7-8) (5-6) (3-4) (1-2) 0 0 0 78 * For example, address 0x3C0, bitwise 1111000000 will be represented as: 79 * (9-10) OFF, (7-8) OFF, (5-6) ON, (3-4) ON, (1-2) ON 80 * 81 * W4 - BIOS address: open pair of pins (OFF) means 1, jumpered (ON) means 0 82 * pair (1-2) is bit 13, ..., pair (7-8) is bit 16. All the other bits are 83 * equal to the value 0xC0000. In bitwise representation that would be: 84 * 1 1 0 (7-8) (5-6) (3-4) (1-2) 0 0000 0000 0000 85 * For example, address 0xD8000 will be represented as: 86 * (7-8) OFF, (5-6) OFF, (3-4) ON, (1-2) ON 87 * 88 * W98 (on newer cards) - BIOS enabled; on older cards just remove the BIOS 89 * chip to disable it 90 * W99 (on newer cards) - ROM size (1-2) OFF, (3-4) ON 91 * 92 * W5 - terminator power 93 * ON - host supplies term. power 94 * OFF - target supplies term. power 95 * 96 * W6, W9 - floppy support (a bit cryptic): 97 * W6 ON, W9 ON - disabled 98 * W6 OFF, W9 ON - enabled with HardCard only 99 * W6 OFF, W9 OFF - enabled with no hardCard or Combo 100 * 101 * Default: I/O 0x350, IRQ15, DMA6 102 */ 103 104/* 105 * debugging levels: 106 * 0 - disabled 107 * 1 - print debugging messages 108 * 2 - collect debugging messages in an internal log buffer which can be 109 * printed later by calling wds_printlog from DDB 110 * 111 * Both kind of logs are heavy and interact significantly with the timing 112 * of commands, so the observed problems may become invisible if debug 113 * logging is enabled. 114 * 115 * The light-weight logging facility may be enabled by defining 116 * WDS_ENABLE_SMALLOG as 1. It has very little overhead and allows observing 117 * the traces of various race conditions without affectiong them but the log is 118 * quite terse. The small log can be printer from DDB by calling 119 * wds_printsmallog. 120 */ 121#ifndef WDS_DEBUG 122#define WDS_DEBUG 0 123#endif 124 125#ifndef WDS_ENABLE_SMALLOG 126#define WDS_ENABLE_SMALLOG 0 127#endif 128 129#include <sys/types.h> 130#include <sys/param.h> 131#include <sys/systm.h> 132#include <sys/errno.h> 133#include <sys/kernel.h> 134#include <sys/assym.h> 135#include <sys/malloc.h> 136 137#include <sys/bio.h> 138#include <sys/buf.h> 139 140#include <cam/cam.h> 141#include <cam/cam_ccb.h> 142#include <cam/cam_sim.h> 143#include <cam/cam_xpt_sim.h> 144#include <cam/cam_debug.h> 145#include <cam/scsi/scsi_all.h> 146#include <cam/scsi/scsi_message.h> 147 148 149#include <vm/vm.h> 150#include <vm/vm_param.h> 151#include <vm/pmap.h> 152 153#include <sys/module.h> 154#include <sys/bus.h> 155#include <machine/bus.h> 156#include <machine/resource.h> 157#include <sys/rman.h> 158 159#include <isa/isavar.h> 160#include <isa/pnpvar.h> 161 162#define WDSTOPHYS(wp, a) ( ((uintptr_t)a) - ((uintptr_t)wp->dx) + (wp->dx_p) ) 163#define WDSTOVIRT(wp, a) ( ((a) - (wp->dx_p)) + ((char *)wp->dx) ) 164 165/* 0x10000 (64k) should be enough. But just to be sure... */ 166#define BUFSIZ 0x12000 167/* buffer fragment size, no more than 32 frags per buffer */ 168#define FRAGSIZ 0x1000 169 170 171/* WD7000 registers */ 172#define WDS_STAT 0 /* read */ 173#define WDS_IRQSTAT 1 /* read */ 174 175#define WDS_CMD 0 /* write */ 176#define WDS_IRQACK 1 /* write */ 177#define WDS_HCR 2 /* write */ 178 179#define WDS_NPORTS 4 /* number of ports used */ 180 181/* WDS_STAT (read) defs */ 182#define WDS_IRQ 0x80 183#define WDS_RDY 0x40 184#define WDS_REJ 0x20 185#define WDS_INIT 0x10 186 187/* WDS_IRQSTAT (read) defs */ 188#define WDSI_MASK 0xc0 189#define WDSI_ERR 0x00 190#define WDSI_MFREE 0x80 191#define WDSI_MSVC 0xc0 192 193/* WDS_CMD (write) defs */ 194#define WDSC_NOOP 0x00 195#define WDSC_INIT 0x01 196#define WDSC_DISUNSOL 0x02 /* disable unsolicited ints */ 197#define WDSC_ENAUNSOL 0x03 /* enable unsolicited ints */ 198#define WDSC_IRQMFREE 0x04 /* interrupt on free RQM */ 199#define WDSC_SCSIRESETSOFT 0x05 /* soft reset */ 200#define WDSC_SCSIRESETHARD 0x06 /* hard reset ack */ 201#define WDSC_MSTART(m) (0x80 + (m)) /* start mailbox */ 202#define WDSC_MMSTART(m) (0xc0 + (m)) /* start all mailboxes */ 203 204/* WDS_HCR (write) defs */ 205#define WDSH_IRQEN 0x08 206#define WDSH_DRQEN 0x04 207#define WDSH_SCSIRESET 0x02 208#define WDSH_ASCRESET 0x01 209 210struct wds_cmd { 211 u_int8_t cmd; 212 u_int8_t targ; 213 u_int8_t scb[12]; 214 u_int8_t stat; 215 u_int8_t venderr; 216 u_int8_t len[3]; 217 u_int8_t data[3]; 218 u_int8_t next[3]; 219 u_int8_t write; 220 u_int8_t xx[6]; 221}; 222 223struct wds_req { 224 struct wds_cmd cmd; 225 union ccb *ccb; 226 enum { 227 WR_DONE = 0x01, 228 WR_SENSE = 0x02 229 } flags; 230 u_int8_t *buf; /* address of linear data buffer */ 231 u_int32_t mask; /* mask of allocated fragments */ 232 u_int8_t ombn; 233 u_int8_t id; /* number of request */ 234}; 235 236#define WDSX_SCSICMD 0x00 237#define WDSX_OPEN_RCVBUF 0x80 238#define WDSX_RCV_CMD 0x81 239#define WDSX_RCV_DATA 0x82 240#define WDSX_RCV_DATASTAT 0x83 241#define WDSX_SND_DATA 0x84 242#define WDSX_SND_DATASTAT 0x85 243#define WDSX_SND_CMDSTAT 0x86 244#define WDSX_READINIT 0x88 245#define WDSX_READSCSIID 0x89 246#define WDSX_SETUNSOLIRQMASK 0x8a 247#define WDSX_GETUNSOLIRQMASK 0x8b 248#define WDSX_GETFIRMREV 0x8c 249#define WDSX_EXECDIAG 0x8d 250#define WDSX_SETEXECPARM 0x8e 251#define WDSX_GETEXECPARM 0x8f 252 253struct wds_mb { 254 u_int8_t stat; 255 u_int8_t addr[3]; 256}; 257/* ICMB status value */ 258#define ICMB_OK 0x01 259#define ICMB_OKERR 0x02 260#define ICMB_ETIME 0x04 261#define ICMB_ERESET 0x05 262#define ICMB_ETARCMD 0x06 263#define ICMB_ERESEL 0x80 264#define ICMB_ESEL 0x81 265#define ICMB_EABORT 0x82 266#define ICMB_ESRESET 0x83 267#define ICMB_EHRESET 0x84 268 269struct wds_setup { 270 u_int8_t cmd; 271 u_int8_t scsi_id; 272 u_int8_t buson_t; 273 u_int8_t busoff_t; 274 u_int8_t xx; 275 u_int8_t mbaddr[3]; 276 u_int8_t nomb; 277 u_int8_t nimb; 278}; 279 280/* the code depends on equality of these parameters */ 281#define MAXSIMUL 8 282#define WDS_NOMB MAXSIMUL 283#define WDS_NIMB MAXSIMUL 284 285static int fragsiz; 286static int nfrags; 287 288/* structure for data exchange with controller */ 289 290struct wdsdx { 291 struct wds_req req[MAXSIMUL]; 292 struct wds_mb ombs[MAXSIMUL]; 293 struct wds_mb imbs[MAXSIMUL]; 294 u_int8_t data[BUFSIZ]; 295}; 296 297/* structure softc */ 298 299struct wds { 300 device_t dev; 301 struct mtx lock; 302 int unit; 303 int drq; 304 struct cam_sim *sim; /* SIM descriptor for this card */ 305 struct cam_path *path; /* wildcard path for this card */ 306 char want_wdsr; /* resource shortage flag */ 307 u_int32_t data_free; 308 u_int32_t wdsr_free; 309 struct wdsdx *dx; 310 bus_addr_t dx_p; /* physical address */ 311 struct resource *port_r; 312 int port_rid; 313 struct resource *drq_r; 314 int drq_rid; 315 struct resource *intr_r; 316 int intr_rid; 317 void *intr_cookie; 318 bus_dma_tag_t bustag; 319 bus_dmamap_t busmap; 320}; 321 322#define ccb_wdsr spriv_ptr1 /* for wds request */ 323 324static int wds_probe(device_t dev); 325static int wds_attach(device_t dev); 326static void wds_intr(void *arg); 327static void wds_intr_locked(struct wds *wp); 328 329static void wds_action(struct cam_sim * sim, union ccb * ccb); 330static void wds_poll(struct cam_sim * sim); 331 332static int wds_preinit(struct wds *wp); 333static int wds_init(struct wds *wp); 334 335static void wds_alloc_callback(void *arg, bus_dma_segment_t *seg, 336 int nseg, int error); 337static void wds_free_resources(struct wds *wp); 338 339static struct wds_req *wdsr_alloc(struct wds *wp); 340 341static void wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio); 342static void wdsr_ccb_done(struct wds *wp, struct wds_req *r, 343 union ccb *ccb, u_int32_t status); 344 345static void wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat); 346static int wds_runsense(struct wds *wp, struct wds_req *r); 347static int wds_getvers(struct wds *wp); 348 349static int wds_cmd(struct wds *wp, u_int8_t * p, int l); 350static void wds_wait(struct wds *wp, int reg, int mask, int val); 351 352static struct wds_req *cmdtovirt(struct wds *wp, u_int32_t phys); 353 354static u_int32_t frag_alloc(struct wds *wp, int size, u_int8_t **res, 355 u_int32_t *maskp); 356static void frag_free(struct wds *wp, u_int32_t mask); 357 358void wds_print(void); 359 360#if WDS_ENABLE_SMALLOG==1 361static __inline void smallog(char c); 362void wds_printsmallog(void); 363#endif /* SMALLOG */ 364 365/* SCSI ID of the adapter itself */ 366#ifndef WDS_HBA_ID 367#define WDS_HBA_ID 7 368#endif 369 370#if WDS_DEBUG == 2 371#define LOGLINESIZ 81 372#define NLOGLINES 300 373#define DBX wds_nextlog(), LOGLINESIZ, 374#define DBG snprintf 375 376static char wds_log[NLOGLINES][LOGLINESIZ]; 377static int logwrite = 0, logread = 0; 378static char *wds_nextlog(void); 379void wds_printlog(void); 380 381#elif WDS_DEBUG != 0 382#define DBX 383#define DBG printf 384#else 385#define DBX 386#define DBG if(0) printf 387#endif 388 389/* the table of supported bus methods */ 390static device_method_t wds_isa_methods[] = { 391 DEVMETHOD(device_probe, wds_probe), 392 DEVMETHOD(device_attach, wds_attach), 393 { 0, 0 } 394}; 395 396static driver_t wds_isa_driver = { 397 "wds", 398 wds_isa_methods, 399 sizeof(struct wds), 400}; 401 402static devclass_t wds_devclass; 403 404DRIVER_MODULE(wds, isa, wds_isa_driver, wds_devclass, 0, 0); 405MODULE_DEPEND(wds, isa, 1, 1, 1); 406MODULE_DEPEND(wds, cam, 1, 1, 1); 407 408#if WDS_ENABLE_SMALLOG==1 409#define SMALLOGSIZ 512 410static char wds_smallog[SMALLOGSIZ]; 411static char *wds_smallogp = wds_smallog; 412static char wds_smallogover = 0; 413 414static __inline void 415smallog(char c) 416{ 417 *wds_smallogp = c; 418 if (++wds_smallogp == &wds_smallog[SMALLOGSIZ]) { 419 wds_smallogp = wds_smallog; 420 wds_smallogover = 1; 421 } 422} 423 424#define smallog2(a, b) (smallog(a), smallog(b)) 425#define smallog3(a, b, c) (smallog(a), smallog(b), smallog(c)) 426#define smallog4(a, b, c, d) (smallog(a),smallog(b),smallog(c),smallog(d)) 427 428void 429wds_printsmallog(void) 430{ 431 int i; 432 char *p; 433 434 printf("wds: "); 435 p = wds_smallogover ? wds_smallogp : wds_smallog; 436 i = 0; 437 do { 438 printf("%c", *p); 439 if (++p == &wds_smallog[SMALLOGSIZ]) 440 p = wds_smallog; 441 if (++i == 70) { 442 i = 0; 443 printf("\nwds: "); 444 } 445 } while (p != wds_smallogp); 446 printf("\n"); 447} 448#else 449#define smallog(a) 450#define smallog2(a, b) 451#define smallog3(a, b, c) 452#define smallog4(a, b, c, d) 453#endif /* SMALLOG */ 454 455static int 456wds_probe(device_t dev) 457{ 458 struct wds *wp; 459 unsigned long addr; 460 int error = 0; 461 int irq; 462 463 /* No pnp support */ 464 if (isa_get_vendorid(dev)) 465 return (ENXIO); 466 467 wp = (struct wds *) device_get_softc(dev); 468 wp->unit = device_get_unit(dev); 469 wp->dev = dev; 470 471 addr = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/); 472 if (addr == 0 || addr <0x300 || addr > 0x3f8 || addr & 0x7) { 473 device_printf(dev, "invalid port address 0x%lx\n", addr); 474 return (ENXIO); 475 } 476 477 if (bus_set_resource(dev, SYS_RES_IOPORT, 0, addr, WDS_NPORTS) < 0) 478 return (ENXIO); 479 480 /* get the DRQ */ 481 wp->drq = bus_get_resource_start(dev, SYS_RES_DRQ, 0 /*rid*/); 482 if (wp->drq < 5 || wp->drq > 7) { 483 device_printf(dev, "invalid DRQ %d\n", wp->drq); 484 return (ENXIO); 485 } 486 487 /* get the IRQ */ 488 irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0 /*rid*/); 489 if (irq < 3) { 490 device_printf(dev, "invalid IRQ %d\n", irq); 491 return (ENXIO); 492 } 493 494 wp->port_rid = 0; 495 wp->port_r = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &wp->port_rid, 496 RF_ACTIVE); 497 if (wp->port_r == NULL) 498 return (ENXIO); 499 500 error = wds_preinit(wp); 501 502 /* 503 * We cannot hold resources between probe and 504 * attach as we may never be attached. 505 */ 506 wds_free_resources(wp); 507 508 return (error); 509} 510 511static int 512wds_attach(device_t dev) 513{ 514 struct wds *wp; 515 struct cam_devq *devq; 516 struct cam_sim *sim; 517 struct cam_path *pathp; 518 int i; 519 int error = 0; 520 521 wp = (struct wds *)device_get_softc(dev); 522 mtx_init(&wp->lock, "wds", NULL, MTX_DEF); 523 524 wp->port_rid = 0; 525 wp->port_r = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &wp->port_rid, 526 RF_ACTIVE); 527 if (wp->port_r == NULL) 528 goto bad; 529 530 /* We must now release resources on error. */ 531 532 wp->drq_rid = 0; 533 wp->drq_r = bus_alloc_resource_any(dev, SYS_RES_DRQ, &wp->drq_rid, 534 RF_ACTIVE); 535 if (wp->drq_r == NULL) 536 goto bad; 537 538 wp->intr_rid = 0; 539 wp->intr_r = bus_alloc_resource_any(dev, SYS_RES_IRQ, &wp->intr_rid, 540 RF_ACTIVE); 541 if (wp->intr_r == NULL) 542 goto bad; 543 error = bus_setup_intr(dev, wp->intr_r, INTR_TYPE_CAM | INTR_ENTROPY | 544 INTR_MPSAFE, NULL, wds_intr, wp, &wp->intr_cookie); 545 if (error) 546 goto bad; 547 548 /* now create the memory buffer */ 549 error = bus_dma_tag_create(bus_get_dma_tag(dev), /*alignment*/4, 550 /*boundary*/0, 551 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 552 /*highaddr*/ BUS_SPACE_MAXADDR, 553 /*filter*/ NULL, /*filterarg*/ NULL, 554 /*maxsize*/ sizeof(* wp->dx), 555 /*nsegments*/ 1, 556 /*maxsegsz*/ sizeof(* wp->dx), /*flags*/ 0, 557 /*lockfunc*/NULL, 558 /*lockarg*/NULL, 559 &wp->bustag); 560 if (error) 561 goto bad; 562 563 error = bus_dmamem_alloc(wp->bustag, (void **)&wp->dx, 564 /*flags*/ 0, &wp->busmap); 565 if (error) 566 goto bad; 567 568 bus_dmamap_load(wp->bustag, wp->busmap, (void *)wp->dx, 569 sizeof(* wp->dx), wds_alloc_callback, 570 (void *)&wp->dx_p, /*flags*/0); 571 572 /* initialize the wds_req structures on this unit */ 573 for(i=0; i<MAXSIMUL; i++) { 574 wp->dx->req[i].id = i; 575 wp->wdsr_free |= 1<<i; 576 } 577 578 /* initialize the memory buffer allocation for this unit */ 579 if (BUFSIZ / FRAGSIZ > 32) { 580 fragsiz = (BUFSIZ / 32) & ~0x01; /* keep it word-aligned */ 581 device_printf(dev, "data buffer fragment size too small. " 582 "BUFSIZE / FRAGSIZE must be <= 32\n"); 583 } else 584 fragsiz = FRAGSIZ & ~0x01; /* keep it word-aligned */ 585 586 wp->data_free = 0; 587 nfrags = 0; 588 for (i = fragsiz; i <= BUFSIZ; i += fragsiz) { 589 nfrags++; 590 wp->data_free = (wp->data_free << 1) | 1; 591 } 592 593 /* complete the hardware initialization */ 594 if (wds_init(wp) != 0) 595 goto bad; 596 597 if (wds_getvers(wp) == -1) 598 device_printf(dev, "getvers failed\n"); 599 device_printf(dev, "using %d bytes / %d frags for dma buffer\n", 600 BUFSIZ, nfrags); 601 602 devq = cam_simq_alloc(MAXSIMUL); 603 if (devq == NULL) 604 goto bad; 605 606 sim = cam_sim_alloc(wds_action, wds_poll, "wds", (void *) wp, 607 wp->unit, &wp->lock, 1, 1, devq); 608 if (sim == NULL) { 609 cam_simq_free(devq); 610 goto bad; 611 } 612 wp->sim = sim; 613 614 mtx_lock(&wp->lock); 615 if (xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) { 616 cam_sim_free(sim, /* free_devq */ TRUE); 617 mtx_unlock(&wp->lock); 618 goto bad; 619 } 620 if (xpt_create_path(&pathp, /* periph */ NULL, 621 cam_sim_path(sim), CAM_TARGET_WILDCARD, 622 CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 623 xpt_bus_deregister(cam_sim_path(sim)); 624 cam_sim_free(sim, /* free_devq */ TRUE); 625 mtx_unlock(&wp->lock); 626 goto bad; 627 } 628 mtx_unlock(&wp->lock); 629 wp->path = pathp; 630 631 return (0); 632 633bad: 634 wds_free_resources(wp); 635 mtx_destroy(&wp->lock); 636 if (error) 637 return (error); 638 else /* exact error is unknown */ 639 return (ENXIO); 640} 641 642/* callback to save the physical address */ 643static void 644wds_alloc_callback(void *arg, bus_dma_segment_t *seg, int nseg, int error) 645{ 646 *(bus_addr_t *)arg = seg[0].ds_addr; 647} 648 649static void 650wds_free_resources(struct wds *wp) 651{ 652 /* check every resource and free if not zero */ 653 654 /* interrupt handler */ 655 if (wp->intr_r) { 656 bus_teardown_intr(wp->dev, wp->intr_r, wp->intr_cookie); 657 bus_release_resource(wp->dev, SYS_RES_IRQ, wp->intr_rid, 658 wp->intr_r); 659 wp->intr_r = 0; 660 } 661 662 /* all kinds of memory maps we could have allocated */ 663 if (wp->dx_p) { 664 bus_dmamap_unload(wp->bustag, wp->busmap); 665 wp->dx_p = 0; 666 } 667 if (wp->dx) { /* wp->busmap may be legitimately equal to 0 */ 668 /* the map will also be freed */ 669 bus_dmamem_free(wp->bustag, wp->dx, wp->busmap); 670 wp->dx = 0; 671 } 672 if (wp->bustag) { 673 bus_dma_tag_destroy(wp->bustag); 674 wp->bustag = 0; 675 } 676 /* release all the bus resources */ 677 if (wp->drq_r) { 678 bus_release_resource(wp->dev, SYS_RES_DRQ, 679 wp->drq_rid, wp->drq_r); 680 wp->drq_r = 0; 681 } 682 if (wp->port_r) { 683 bus_release_resource(wp->dev, SYS_RES_IOPORT, 684 wp->port_rid, wp->port_r); 685 wp->port_r = 0; 686 } 687} 688 689/* allocate contiguous fragments from the buffer */ 690static u_int32_t 691frag_alloc(struct wds *wp, int size, u_int8_t **res, u_int32_t *maskp) 692{ 693 int i; 694 u_int32_t mask; 695 u_int32_t free; 696 697 if (size > fragsiz * nfrags) 698 return (CAM_REQ_TOO_BIG); 699 700 mask = 1; /* always allocate at least 1 fragment */ 701 for (i = fragsiz; i < size; i += fragsiz) 702 mask = (mask << 1) | 1; 703 704 free = wp->data_free; 705 if(free != 0) { 706 i = ffs(free)-1; /* ffs counts bits from 1 */ 707 for (mask <<= i; i < nfrags; i++) { 708 if ((free & mask) == mask) { 709 wp->data_free &= ~mask; /* mark frags as busy */ 710 *maskp = mask; 711 *res = &wp->dx->data[fragsiz * i]; 712 DBG(DBX "wds%d: allocated buffer mask=0x%x\n", 713 wp->unit, mask); 714 return (CAM_REQ_CMP); 715 } 716 if (mask & 0x80000000) 717 break; 718 719 mask <<= 1; 720 } 721 } 722 return (CAM_REQUEUE_REQ); /* no free memory now, try later */ 723} 724 725static void 726frag_free(struct wds *wp, u_int32_t mask) 727{ 728 wp->data_free |= mask; /* mark frags as free */ 729 DBG(DBX "wds%d: freed buffer mask=0x%x\n", wp->unit, mask); 730} 731 732static struct wds_req * 733wdsr_alloc(struct wds *wp) 734{ 735 struct wds_req *r; 736 int x; 737 int i; 738 739 r = NULL; 740 x = splcam(); 741 742 /* anyway most of the time only 1 or 2 commands will 743 * be active because SCSI disconnect is not supported 744 * by hardware, so the search should be fast enough 745 */ 746 i = ffs(wp->wdsr_free) - 1; 747 if(i < 0) { 748 splx(x); 749 return (NULL); 750 } 751 wp->wdsr_free &= ~ (1<<i); 752 r = &wp->dx->req[i]; 753 r->flags = 0; /* reset all flags */ 754 r->ombn = i; /* luckily we have one omb per wdsr */ 755 wp->dx->ombs[i].stat = 1; 756 757 r->mask = 0; 758 splx(x); 759 smallog3('r', i + '0', r->ombn + '0'); 760 return (r); 761} 762 763static void 764wds_intr(void *arg) 765{ 766 struct wds *wp; 767 768 wp = arg; 769 mtx_lock(&wp->lock); 770 wds_intr_locked(wp); 771 mtx_unlock(&wp->lock); 772} 773 774static void 775wds_intr_locked(struct wds *wp) 776{ 777 struct wds_req *rp; 778 struct wds_mb *in; 779 u_int8_t stat; 780 u_int8_t c; 781 782 DBG(DBX "wds%d: interrupt [\n", wp->unit); 783 smallog('['); 784 785 if (bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) { 786 c = bus_read_1(wp->port_r, WDS_IRQSTAT); 787 if ((c & WDSI_MASK) == WDSI_MSVC) { 788 c = c & ~WDSI_MASK; 789 in = &wp->dx->imbs[c]; 790 791 rp = cmdtovirt(wp, scsi_3btoul(in->addr)); 792 stat = in->stat; 793 794 if (rp != NULL) 795 wds_done(wp, rp, stat); 796 else 797 device_printf(wp->dev, 798 "got weird command address %p" 799 "from controller\n", rp); 800 801 in->stat = 0; 802 } else 803 device_printf(wp->dev, 804 "weird interrupt, irqstat=0x%x\n", c); 805 bus_write_1(wp->port_r, WDS_IRQACK, 0); 806 } else { 807 smallog('?'); 808 } 809 smallog(']'); 810 DBG(DBX "wds%d: ]\n", wp->unit); 811} 812 813static void 814wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat) 815{ 816 struct ccb_hdr *ccb_h; 817 struct ccb_scsiio *csio; 818 int status; 819 820 smallog('d'); 821 822 if (r->flags & WR_DONE) { 823 device_printf(wp->dev, 824 "request %d reported done twice\n", r->id); 825 smallog2('x', r->id + '0'); 826 return; 827 } 828 829 smallog(r->id + '0'); 830 ccb_h = &r->ccb->ccb_h; 831 csio = &r->ccb->csio; 832 status = CAM_REQ_CMP_ERR; 833 834 DBG(DBX "wds%d: %s stat=0x%x c->stat=0x%x c->venderr=0x%x\n", wp->unit, 835 r->flags & WR_SENSE ? "(sense)" : "", 836 stat, r->cmd.stat, r->cmd.venderr); 837 838 if (r->flags & WR_SENSE) { 839 if (stat == ICMB_OK || (stat == ICMB_OKERR && r->cmd.stat == 0)) { 840 DBG(DBX "wds%d: sense 0x%x\n", wp->unit, r->buf[0]); 841 /* it has the same size now but for future */ 842 bcopy(r->buf, &csio->sense_data, 843 sizeof(struct scsi_sense_data) > csio->sense_len ? 844 csio->sense_len : sizeof(struct scsi_sense_data)); 845 if (sizeof(struct scsi_sense_data) >= csio->sense_len) 846 csio->sense_resid = 0; 847 else 848 csio->sense_resid = 849 csio->sense_len 850 - sizeof(struct scsi_sense_data); 851 status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR; 852 } else { 853 status = CAM_AUTOSENSE_FAIL; 854 } 855 } else { 856 switch (stat) { 857 case ICMB_OK: 858 if (ccb_h) { 859 csio->resid = 0; 860 csio->scsi_status = r->cmd.stat; 861 status = CAM_REQ_CMP; 862 } 863 break; 864 case ICMB_OKERR: 865 if (ccb_h) { 866 csio->scsi_status = r->cmd.stat; 867 if (r->cmd.stat) { 868 if (ccb_h->flags & CAM_DIS_AUTOSENSE) 869 status = CAM_SCSI_STATUS_ERROR; 870 else { 871 if ( wds_runsense(wp, r) == CAM_REQ_CMP ) 872 return; 873 /* in case of error continue with freeing of CCB */ 874 } 875 } else { 876 csio->resid = 0; 877 status = CAM_REQ_CMP; 878 } 879 } 880 break; 881 case ICMB_ETIME: 882 if (ccb_h) 883 status = CAM_SEL_TIMEOUT; 884 break; 885 case ICMB_ERESET: 886 case ICMB_ETARCMD: 887 case ICMB_ERESEL: 888 case ICMB_ESEL: 889 case ICMB_EABORT: 890 case ICMB_ESRESET: 891 case ICMB_EHRESET: 892 if (ccb_h) 893 status = CAM_REQ_CMP_ERR; 894 break; 895 } 896 897 if (ccb_h && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) { 898 /* we accept only virtual addresses in wds_action() */ 899 bcopy(r->buf, csio->data_ptr, csio->dxfer_len); 900 } 901 } 902 903 r->flags |= WR_DONE; 904 wp->dx->ombs[r->ombn].stat = 0; 905 906 if (ccb_h) { 907 wdsr_ccb_done(wp, r, r->ccb, status); 908 smallog3('-', ccb_h->target_id + '0', ccb_h->target_lun + '0'); 909 } else { 910 frag_free(wp, r->mask); 911 if (wp->want_wdsr) { 912 wp->want_wdsr = 0; 913 xpt_release_simq(wp->sim, /* run queue */ 1); 914 } 915 wp->wdsr_free |= (1 << r->id); 916 } 917 918 DBG(DBX "wds%d: request %p done\n", wp->unit, r); 919} 920 921/* command returned bad status, request sense */ 922 923static int 924wds_runsense(struct wds *wp, struct wds_req *r) 925{ 926 u_int8_t c; 927 struct ccb_hdr *ccb_h; 928 929 ccb_h = &r->ccb->ccb_h; 930 931 r->flags |= WR_SENSE; 932 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), 933 wp->dx->ombs[r->ombn].addr); 934 bzero(&r->cmd, sizeof r->cmd); 935 r->cmd.cmd = WDSX_SCSICMD; 936 r->cmd.targ = (ccb_h->target_id << 5) | 937 ccb_h->target_lun; 938 939 scsi_ulto3b(0, r->cmd.next); 940 941 r->cmd.scb[0] = REQUEST_SENSE; 942 r->cmd.scb[1] = ccb_h->target_lun << 5; 943 r->cmd.scb[4] = sizeof(struct scsi_sense_data); 944 r->cmd.scb[5] = 0; 945 scsi_ulto3b(WDSTOPHYS(wp, r->buf), r->cmd.data); 946 scsi_ulto3b(sizeof(struct scsi_sense_data), r->cmd.len); 947 r->cmd.write = 0x80; 948 949 bus_write_1(wp->port_r, WDS_HCR, WDSH_IRQEN | WDSH_DRQEN); 950 951 wp->dx->ombs[r->ombn].stat = 1; 952 c = WDSC_MSTART(r->ombn); 953 954 if (wds_cmd(wp, &c, sizeof c) != 0) { 955 device_printf(wp->dev, "unable to start outgoing sense mbox\n"); 956 wp->dx->ombs[r->ombn].stat = 0; 957 wdsr_ccb_done(wp, r, r->ccb, CAM_AUTOSENSE_FAIL); 958 return CAM_AUTOSENSE_FAIL; 959 } else { 960 DBG(DBX "wds%d: enqueued status cmd 0x%x, r=%p\n", 961 wp->unit, r->cmd.scb[0] & 0xFF, r); 962 /* don't free CCB yet */ 963 smallog3('*', ccb_h->target_id + '0', 964 ccb_h->target_lun + '0'); 965 return CAM_REQ_CMP; 966 } 967} 968 969static int 970wds_getvers(struct wds *wp) 971{ 972 struct wds_req *r; 973 u_int8_t c; 974 int i; 975 976 r = wdsr_alloc(wp); 977 if (!r) { 978 device_printf(wp->dev, "no request slot available!\n"); 979 return (-1); 980 } 981 r->flags &= ~WR_DONE; 982 983 r->ccb = NULL; 984 985 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr); 986 987 bzero(&r->cmd, sizeof r->cmd); 988 r->cmd.cmd = WDSX_GETFIRMREV; 989 990 bus_write_1(wp->port_r, WDS_HCR, WDSH_DRQEN); 991 992 c = WDSC_MSTART(r->ombn); 993 if (wds_cmd(wp, (u_int8_t *) & c, sizeof c)) { 994 device_printf(wp->dev, "version request failed\n"); 995 wp->wdsr_free |= (1 << r->id); 996 wp->dx->ombs[r->ombn].stat = 0; 997 return (-1); 998 } 999 while (1) { 1000 i = 0; 1001 while ((bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) == 0) { 1002 DELAY(9000); 1003 if (++i == 100) { 1004 device_printf(wp->dev, "getvers timeout\n"); 1005 return (-1); 1006 } 1007 } 1008 wds_intr_locked(wp); 1009 if (r->flags & WR_DONE) { 1010 device_printf(wp->dev, "firmware version %d.%02d\n", 1011 r->cmd.targ, r->cmd.scb[0]); 1012 wp->wdsr_free |= (1 << r->id); 1013 return (0); 1014 } 1015 } 1016} 1017 1018static void 1019wdsr_ccb_done(struct wds *wp, struct wds_req *r, 1020 union ccb *ccb, u_int32_t status) 1021{ 1022 ccb->ccb_h.ccb_wdsr = 0; 1023 1024 if (r != NULL) { 1025 /* To implement timeouts we would need to know how to abort the 1026 * command on controller, and this is a great mystery. 1027 * So for now we just pass the responsibility for timeouts 1028 * to the controller itself, it does that reasonably good. 1029 */ 1030 /* we're about to free a hcb, so the shortage has ended */ 1031 frag_free(wp, r->mask); 1032 if (wp->want_wdsr && status != CAM_REQUEUE_REQ) { 1033 wp->want_wdsr = 0; 1034 status |= CAM_RELEASE_SIMQ; 1035 smallog('R'); 1036 } 1037 wp->wdsr_free |= (1 << r->id); 1038 } 1039 ccb->ccb_h.status = 1040 status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED)); 1041 xpt_done(ccb); 1042} 1043 1044static void 1045wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio) 1046{ 1047 int unit = cam_sim_unit(sim); 1048 struct wds *wp; 1049 struct ccb_hdr *ccb_h; 1050 struct wds_req *r; 1051 u_int8_t c; 1052 int error; 1053 int n; 1054 1055 wp = (struct wds *)cam_sim_softc(sim); 1056 ccb_h = &csio->ccb_h; 1057 1058 DBG(DBX "wds%d: cmd TARG=%d LUN=%jx\n", unit, ccb_h->target_id, 1059 (uintmax_t)ccb_h->target_lun); 1060 1061 if (ccb_h->target_id > 7 || ccb_h->target_id == WDS_HBA_ID) { 1062 ccb_h->status = CAM_TID_INVALID; 1063 xpt_done((union ccb *) csio); 1064 return; 1065 } 1066 if (ccb_h->target_lun > 7) { 1067 ccb_h->status = CAM_LUN_INVALID; 1068 xpt_done((union ccb *) csio); 1069 return; 1070 } 1071 if (csio->dxfer_len > BUFSIZ) { 1072 ccb_h->status = CAM_REQ_TOO_BIG; 1073 xpt_done((union ccb *) csio); 1074 return; 1075 } 1076 if ((ccb_h->flags & CAM_DATA_MASK) != CAM_DATA_VADDR) { 1077 /* don't support these */ 1078 ccb_h->status = CAM_REQ_INVALID; 1079 xpt_done((union ccb *) csio); 1080 return; 1081 } 1082 1083 /* 1084 * this check is mostly for debugging purposes, 1085 * "can't happen" normally. 1086 */ 1087 if(wp->want_wdsr) { 1088 DBG(DBX "wds%d: someone already waits for buffer\n", unit); 1089 smallog('b'); 1090 n = xpt_freeze_simq(sim, /* count */ 1); 1091 smallog('0'+n); 1092 ccb_h->status = CAM_REQUEUE_REQ; 1093 xpt_done((union ccb *) csio); 1094 return; 1095 } 1096 1097 r = wdsr_alloc(wp); 1098 if (r == NULL) { 1099 device_printf(wp->dev, "no request slot available!\n"); 1100 wp->want_wdsr = 1; 1101 n = xpt_freeze_simq(sim, /* count */ 1); 1102 smallog2('f', '0'+n); 1103 ccb_h->status = CAM_REQUEUE_REQ; 1104 xpt_done((union ccb *) csio); 1105 return; 1106 } 1107 1108 ccb_h->ccb_wdsr = (void *) r; 1109 r->ccb = (union ccb *) csio; 1110 1111 switch (error = frag_alloc(wp, csio->dxfer_len, &r->buf, &r->mask)) { 1112 case CAM_REQ_CMP: 1113 break; 1114 case CAM_REQUEUE_REQ: 1115 DBG(DBX "wds%d: no data buffer available\n", unit); 1116 wp->want_wdsr = 1; 1117 n = xpt_freeze_simq(sim, /* count */ 1); 1118 smallog2('f', '0'+n); 1119 wdsr_ccb_done(wp, r, r->ccb, CAM_REQUEUE_REQ); 1120 return; 1121 default: 1122 DBG(DBX "wds%d: request is too big\n", unit); 1123 wdsr_ccb_done(wp, r, r->ccb, error); 1124 break; 1125 } 1126 1127 ccb_h->status |= CAM_SIM_QUEUED; 1128 r->flags &= ~WR_DONE; 1129 1130 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr); 1131 1132 bzero(&r->cmd, sizeof r->cmd); 1133 r->cmd.cmd = WDSX_SCSICMD; 1134 r->cmd.targ = (ccb_h->target_id << 5) | ccb_h->target_lun; 1135 1136 if (ccb_h->flags & CAM_CDB_POINTER) 1137 bcopy(csio->cdb_io.cdb_ptr, &r->cmd.scb, 1138 csio->cdb_len < 12 ? csio->cdb_len : 12); 1139 else 1140 bcopy(csio->cdb_io.cdb_bytes, &r->cmd.scb, 1141 csio->cdb_len < 12 ? csio->cdb_len : 12); 1142 1143 scsi_ulto3b(csio->dxfer_len, r->cmd.len); 1144 1145 if (csio->dxfer_len > 0 1146 && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 1147 /* we already rejected physical or scattered addresses */ 1148 bcopy(csio->data_ptr, r->buf, csio->dxfer_len); 1149 } 1150 scsi_ulto3b(csio->dxfer_len ? WDSTOPHYS(wp, r->buf) : 0, r->cmd.data); 1151 1152 if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) 1153 r->cmd.write = 0x80; 1154 else 1155 r->cmd.write = 0x00; 1156 1157 scsi_ulto3b(0, r->cmd.next); 1158 1159 bus_write_1(wp->port_r, WDS_HCR, WDSH_IRQEN | WDSH_DRQEN); 1160 1161 c = WDSC_MSTART(r->ombn); 1162 1163 if (wds_cmd(wp, &c, sizeof c) != 0) { 1164 device_printf(wp->dev, "unable to start outgoing mbox\n"); 1165 wp->dx->ombs[r->ombn].stat = 0; 1166 wdsr_ccb_done(wp, r, r->ccb, CAM_RESRC_UNAVAIL); 1167 return; 1168 } 1169 DBG(DBX "wds%d: enqueued cmd 0x%x, r=%p\n", unit, 1170 r->cmd.scb[0] & 0xFF, r); 1171 1172 smallog3('+', ccb_h->target_id + '0', ccb_h->target_lun + '0'); 1173} 1174 1175static void 1176wds_action(struct cam_sim * sim, union ccb * ccb) 1177{ 1178 int unit = cam_sim_unit(sim); 1179 1180 DBG(DBX "wds%d: action 0x%x\n", unit, ccb->ccb_h.func_code); 1181 switch (ccb->ccb_h.func_code) { 1182 case XPT_SCSI_IO: 1183 DBG(DBX "wds%d: SCSI IO entered\n", unit); 1184 wds_scsi_io(sim, &ccb->csio); 1185 DBG(DBX "wds%d: SCSI IO returned\n", unit); 1186 break; 1187 case XPT_RESET_BUS: 1188 /* how to do it right ? */ 1189 printf("wds%d: reset\n", unit); 1190 ccb->ccb_h.status = CAM_REQ_CMP; 1191 xpt_done(ccb); 1192 break; 1193 case XPT_ABORT: 1194 ccb->ccb_h.status = CAM_UA_ABORT; 1195 xpt_done(ccb); 1196 break; 1197 case XPT_CALC_GEOMETRY: 1198 { 1199 struct ccb_calc_geometry *ccg; 1200 u_int32_t size_mb; 1201 u_int32_t secs_per_cylinder; 1202 1203 ccg = &ccb->ccg; 1204 size_mb = ccg->volume_size 1205 / ((1024L * 1024L) / ccg->block_size); 1206 1207 ccg->heads = 64; 1208 ccg->secs_per_track = 16; 1209 secs_per_cylinder = ccg->heads * ccg->secs_per_track; 1210 ccg->cylinders = ccg->volume_size / secs_per_cylinder; 1211 ccb->ccb_h.status = CAM_REQ_CMP; 1212 xpt_done(ccb); 1213 break; 1214 } 1215 case XPT_PATH_INQ: /* Path routing inquiry */ 1216 { 1217 struct ccb_pathinq *cpi = &ccb->cpi; 1218 1219 cpi->version_num = 1; /* XXX??? */ 1220 cpi->hba_inquiry = 0; /* nothing fancy */ 1221 cpi->target_sprt = 0; 1222 cpi->hba_misc = 0; 1223 cpi->hba_eng_cnt = 0; 1224 cpi->max_target = 7; 1225 cpi->max_lun = 7; 1226 cpi->initiator_id = WDS_HBA_ID; 1227 cpi->hba_misc = 0; 1228 cpi->bus_id = cam_sim_bus(sim); 1229 cpi->base_transfer_speed = 3300; 1230 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1231 strncpy(cpi->hba_vid, "WD/FDC", HBA_IDLEN); 1232 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1233 cpi->unit_number = cam_sim_unit(sim); 1234 cpi->ccb_h.status = CAM_REQ_CMP; 1235 xpt_done(ccb); 1236 break; 1237 } 1238 default: 1239 ccb->ccb_h.status = CAM_REQ_INVALID; 1240 xpt_done(ccb); 1241 break; 1242 } 1243} 1244 1245static void 1246wds_poll(struct cam_sim * sim) 1247{ 1248 wds_intr_locked(cam_sim_softc(sim)); 1249} 1250 1251/* part of initialization done in probe() */ 1252/* returns 0 if OK, ENXIO if bad */ 1253 1254static int 1255wds_preinit(struct wds *wp) 1256{ 1257 int i; 1258 1259 /* 1260 * Sending a command causes the CMDRDY bit to clear. 1261 */ 1262 bus_write_1(wp->port_r, WDS_CMD, WDSC_NOOP); 1263 if (bus_read_1(wp->port_r, WDS_STAT) & WDS_RDY) 1264 return (ENXIO); 1265 1266 /* 1267 * the controller exists. reset and init. 1268 */ 1269 bus_write_1(wp->port_r, WDS_HCR, WDSH_ASCRESET | WDSH_SCSIRESET); 1270 DELAY(30); 1271 bus_write_1(wp->port_r, WDS_HCR, 0); 1272 1273 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY) { 1274 for (i = 0; i < 10; i++) { 1275 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) == WDS_RDY) 1276 break; 1277 DELAY(40000); 1278 } 1279 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY) 1280 /* probe timeout */ 1281 return (ENXIO); 1282 } 1283 1284 return (0); 1285} 1286 1287/* part of initialization done in attach() */ 1288/* returns 0 if OK, 1 if bad */ 1289 1290static int 1291wds_init(struct wds *wp) 1292{ 1293 struct wds_setup init; 1294 int i; 1295 struct wds_cmd wc; 1296 1297 bus_write_1(wp->port_r, WDS_HCR, WDSH_DRQEN); 1298 1299 isa_dmacascade(wp->drq); 1300 1301 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY) { 1302 for (i = 0; i < 10; i++) { 1303 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) == WDS_RDY) 1304 break; 1305 DELAY(40000); 1306 } 1307 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY) 1308 /* probe timeout */ 1309 return (1); 1310 } 1311 bzero(&init, sizeof init); 1312 init.cmd = WDSC_INIT; 1313 init.scsi_id = WDS_HBA_ID; 1314 init.buson_t = 24; 1315 init.busoff_t = 48; 1316 scsi_ulto3b(WDSTOPHYS(wp, &wp->dx->ombs), init.mbaddr); 1317 init.xx = 0; 1318 init.nomb = WDS_NOMB; 1319 init.nimb = WDS_NIMB; 1320 1321 wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY); 1322 if (wds_cmd(wp, (u_int8_t *) & init, sizeof init) != 0) { 1323 device_printf(wp->dev, "wds_cmd init failed\n"); 1324 return (1); 1325 } 1326 wds_wait(wp, WDS_STAT, WDS_INIT, WDS_INIT); 1327 1328 wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY); 1329 1330 bzero(&wc, sizeof wc); 1331 wc.cmd = WDSC_DISUNSOL; 1332 if (wds_cmd(wp, (char *) &wc, sizeof wc) != 0) { 1333 device_printf(wp->dev, "wds_cmd init2 failed\n"); 1334 return (1); 1335 } 1336 return (0); 1337} 1338 1339static int 1340wds_cmd(struct wds *wp, u_int8_t * p, int l) 1341{ 1342 1343 while (l--) { 1344 do { 1345 bus_write_1(wp->port_r, WDS_CMD, *p); 1346 wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY); 1347 } while (bus_read_1(wp->port_r, WDS_STAT) & WDS_REJ); 1348 p++; 1349 } 1350 1351 wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY); 1352 1353 return (0); 1354} 1355 1356static void 1357wds_wait(struct wds *wp, int reg, int mask, int val) 1358{ 1359 while ((bus_read_1(wp->port_r, reg) & mask) != val) 1360 ; 1361} 1362 1363static struct wds_req * 1364cmdtovirt(struct wds *wp, u_int32_t phys) 1365{ 1366 char *a; 1367 1368 a = WDSTOVIRT(wp, (uintptr_t)phys); 1369 if( a < (char *)&wp->dx->req[0] || a>= (char *)&wp->dx->req[MAXSIMUL]) { 1370 device_printf(wp->dev, "weird phys address 0x%x\n", phys); 1371 return (NULL); 1372 } 1373 a -= (int)offsetof(struct wds_req, cmd); /* convert cmd to request */ 1374 return ((struct wds_req *)a); 1375} 1376 1377/* for debugging, print out all the data about the status of devices */ 1378void 1379wds_print(void) 1380{ 1381 int unit; 1382 int i; 1383 struct wds_req *r; 1384 struct wds *wp; 1385 1386 for (unit = 0; unit < devclass_get_maxunit(wds_devclass); unit++) { 1387 wp = (struct wds *) devclass_get_device(wds_devclass, unit); 1388 if (wp == NULL) 1389 continue; 1390 printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n", 1391 unit, wp->want_wdsr, bus_read_1(wp->port_r, WDS_STAT) & 0xff, 1392 (bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) ? "ready" : "no", 1393 bus_read_1(wp->port_r, WDS_IRQSTAT) & 0xff); 1394 for (i = 0; i < MAXSIMUL; i++) { 1395 r = &wp->dx->req[i]; 1396 if( wp->wdsr_free & (1 << r->id) ) { 1397 printf("req=%d flg=0x%x ombn=%d ombstat=%d " 1398 "mask=0x%x targ=%d lun=%d cmd=0x%x\n", 1399 i, r->flags, r->ombn, 1400 wp->dx->ombs[r->ombn].stat, 1401 r->mask, r->cmd.targ >> 5, 1402 r->cmd.targ & 7, r->cmd.scb[0]); 1403 } 1404 } 1405 } 1406} 1407 1408#if WDS_DEBUG == 2 1409/* create circular log buffer */ 1410static char * 1411wds_nextlog(void) 1412{ 1413 int n = logwrite; 1414 1415 if (++logwrite >= NLOGLINES) 1416 logwrite = 0; 1417 if (logread == logwrite) 1418 if (++logread >= NLOGLINES) 1419 logread = 0; 1420 return (wds_log[n]); 1421} 1422 1423void 1424wds_printlog(void) 1425{ 1426 /* print the circular buffer */ 1427 int i; 1428 1429 for (i = logread; i != logwrite;) { 1430 printf("%s", wds_log[i]); 1431 if (i == NLOGLINES) 1432 i = 0; 1433 else 1434 i++; 1435 } 1436} 1437#endif /* WDS_DEBUG */ 1438