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