1139749Simp/*- 267482Sbabkin * Copyright (c) 1994 Ludd, University of Lule}, Sweden. 367482Sbabkin * Copyright (c) 2000 Sergey A. Babkin 467482Sbabkin * All rights reserved. 567482Sbabkin * 667482Sbabkin * Written by Olof Johansson (offe@ludd.luth.se) 1995. 767482Sbabkin * Based on code written by Theo de Raadt (deraadt@fsa.ca). 867482Sbabkin * Resurrected, ported to CAM and generally cleaned up by Sergey Babkin 967482Sbabkin * <babkin@bellatlantic.net> or <babkin@users.sourceforge.net>. 1067482Sbabkin * 1167482Sbabkin * Redistribution and use in source and binary forms, with or without 1267482Sbabkin * modification, are permitted provided that the following conditions 1367482Sbabkin * are met: 1467482Sbabkin * 1. Redistributions of source code must retain the above copyright 1567482Sbabkin * notice, this list of conditions and the following disclaimer. 1667482Sbabkin * 2. Redistributions in binary form must reproduce the above copyright 1767482Sbabkin * notice, this list of conditions and the following disclaimer in the 1867482Sbabkin * documentation and/or other materials provided with the distribution. 1967482Sbabkin * 3. All advertising materials mentioning features or use of this software 2067482Sbabkin * must display the following acknowledgement: 2167482Sbabkin * This product includes software developed at Ludd, University of Lule} 2267482Sbabkin * and by the FreeBSD project. 2367482Sbabkin * 4. The name of the author may not be used to endorse or promote products 2467482Sbabkin * derived from this software without specific prior written permission 2567482Sbabkin * 2667482Sbabkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2767482Sbabkin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2867482Sbabkin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2967482Sbabkin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3067482Sbabkin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3167482Sbabkin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3267482Sbabkin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3367482Sbabkin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3467482Sbabkin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3567482Sbabkin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3667482Sbabkin * 3767482Sbabkin */ 3867482Sbabkin 39119418Sobrien#include <sys/cdefs.h> 40119418Sobrien__FBSDID("$FreeBSD$"); 41119418Sobrien 4267482Sbabkin/* All bugs are subject to removal without further notice */ 4367482Sbabkin 4467482Sbabkin/* 4567482Sbabkin * offe 01/07/95 4667482Sbabkin * 4767482Sbabkin * This version of the driver _still_ doesn't implement scatter/gather for the 4867482Sbabkin * WD7000-FASST2. This is due to the fact that my controller doesn't seem to 4967482Sbabkin * support it. That, and the lack of documentation makes it impossible for me 5067482Sbabkin * to implement it. What I've done instead is allocated a local buffer, 5167482Sbabkin * contiguous buffer big enough to handle the requests. I haven't seen any 5267482Sbabkin * read/write bigger than 64k, so I allocate a buffer of 64+16k. The data 5367482Sbabkin * that needs to be DMA'd to/from the controller is copied to/from that 5467482Sbabkin * buffer before/after the command is sent to the card. 5567482Sbabkin * 5667482Sbabkin * SB 03/30/00 5767482Sbabkin * 5867482Sbabkin * An intermediate buffer is needed anyway to make sure that the buffer is 5967482Sbabkin * located under 16MB, otherwise it's out of reach of ISA cards. I've added 6067482Sbabkin * optimizations to allocate space in buffer in fragments. 6167482Sbabkin */ 6267482Sbabkin 6367482Sbabkin/* 6467482Sbabkin * Jumpers: (see The Ref(TM) for more info) 6567482Sbabkin * W1/W2 - interrupt selection: 6667482Sbabkin * W1 (1-2) IRQ3, (3-4) IRQ4, (5-6) IRQ5, (7-8) IRQ7, (9-10) IRQ9 6767482Sbabkin * W2 (21-22) IRQ10, (19-20) IRQ11, (17-18) IRQ12, (15-16) IRQ14, (13-14) IRQ15 6867482Sbabkin * 6967482Sbabkin * W2 - DRQ/DACK selection, DRQ and DACK must be the same: 7067482Sbabkin * (5-6) DRQ5 (11-12) DACK5 7167482Sbabkin * (3-4) DRQ6 (9-10) DACK6 7267482Sbabkin * (1-2) DRQ7 (7-8) DACK7 7367482Sbabkin * 7467482Sbabkin * W3 - I/O address selection: open pair of pins (OFF) means 1, jumpered (ON) means 0 7567482Sbabkin * pair (1-2) is bit 3, ..., pair (9-10) is bit 7. All the other bits are equal 7667482Sbabkin * to the value 0x300. In bitwise representation that would be: 7767482Sbabkin * 0 0 1 1 (9-10) (7-8) (5-6) (3-4) (1-2) 0 0 0 7867482Sbabkin * For example, address 0x3C0, bitwise 1111000000 will be represented as: 7967482Sbabkin * (9-10) OFF, (7-8) OFF, (5-6) ON, (3-4) ON, (1-2) ON 8067482Sbabkin * 8167482Sbabkin * W4 - BIOS address: open pair of pins (OFF) means 1, jumpered (ON) means 0 8267482Sbabkin * pair (1-2) is bit 13, ..., pair (7-8) is bit 16. All the other bits are 8367482Sbabkin * equal to the value 0xC0000. In bitwise representation that would be: 8467482Sbabkin * 1 1 0 (7-8) (5-6) (3-4) (1-2) 0 0000 0000 0000 8567482Sbabkin * For example, address 0xD8000 will be represented as: 8667482Sbabkin * (7-8) OFF, (5-6) OFF, (3-4) ON, (1-2) ON 8767482Sbabkin * 8867482Sbabkin * W98 (on newer cards) - BIOS enabled; on older cards just remove the BIOS 8967482Sbabkin * chip to disable it 9067482Sbabkin * W99 (on newer cards) - ROM size (1-2) OFF, (3-4) ON 9167482Sbabkin * 9267482Sbabkin * W5 - terminator power 9367482Sbabkin * ON - host supplies term. power 9467482Sbabkin * OFF - target supplies term. power 9567482Sbabkin * 9667482Sbabkin * W6, W9 - floppy support (a bit cryptic): 9767482Sbabkin * W6 ON, W9 ON - disabled 9867482Sbabkin * W6 OFF, W9 ON - enabled with HardCard only 9967482Sbabkin * W6 OFF, W9 OFF - enabled with no hardCard or Combo 10067482Sbabkin * 10167482Sbabkin * Default: I/O 0x350, IRQ15, DMA6 10267482Sbabkin */ 10367482Sbabkin 10467482Sbabkin/* 10567482Sbabkin * debugging levels: 10667482Sbabkin * 0 - disabled 10767482Sbabkin * 1 - print debugging messages 10867482Sbabkin * 2 - collect debugging messages in an internal log buffer which can be 10967482Sbabkin * printed later by calling wds_printlog from DDB 11067482Sbabkin * 11167482Sbabkin * Both kind of logs are heavy and interact significantly with the timing 11267482Sbabkin * of commands, so the observed problems may become invisible if debug 11367482Sbabkin * logging is enabled. 11467482Sbabkin * 11567482Sbabkin * The light-weight logging facility may be enabled by defining 11667482Sbabkin * WDS_ENABLE_SMALLOG as 1. It has very little overhead and allows observing 11767482Sbabkin * the traces of various race conditions without affectiong them but the log is 11867482Sbabkin * quite terse. The small log can be printer from DDB by calling 11967482Sbabkin * wds_printsmallog. 12067482Sbabkin */ 12167482Sbabkin#ifndef WDS_DEBUG 12267482Sbabkin#define WDS_DEBUG 0 12367482Sbabkin#endif 12467482Sbabkin 12567482Sbabkin#ifndef WDS_ENABLE_SMALLOG 12667482Sbabkin#define WDS_ENABLE_SMALLOG 0 12767482Sbabkin#endif 12867482Sbabkin 12967482Sbabkin#include <sys/types.h> 13067482Sbabkin#include <sys/param.h> 13167482Sbabkin#include <sys/systm.h> 13267482Sbabkin#include <sys/errno.h> 13367482Sbabkin#include <sys/kernel.h> 13467482Sbabkin#include <sys/assym.h> 135168752Sscottl#include <sys/malloc.h> 13667482Sbabkin 13767482Sbabkin#include <sys/bio.h> 13867482Sbabkin#include <sys/buf.h> 13967482Sbabkin 14067482Sbabkin#include <cam/cam.h> 14167482Sbabkin#include <cam/cam_ccb.h> 14267482Sbabkin#include <cam/cam_sim.h> 14367482Sbabkin#include <cam/cam_xpt_sim.h> 14467482Sbabkin#include <cam/cam_debug.h> 14567482Sbabkin#include <cam/scsi/scsi_all.h> 14667482Sbabkin#include <cam/scsi/scsi_message.h> 14767482Sbabkin 14867482Sbabkin 14967482Sbabkin#include <vm/vm.h> 15067482Sbabkin#include <vm/vm_param.h> 15167482Sbabkin#include <vm/pmap.h> 15267482Sbabkin 15367482Sbabkin#include <sys/module.h> 15467482Sbabkin#include <sys/bus.h> 15567482Sbabkin#include <machine/bus.h> 15667482Sbabkin#include <machine/resource.h> 15767482Sbabkin#include <sys/rman.h> 15867482Sbabkin 15967482Sbabkin#include <isa/isavar.h> 16067482Sbabkin#include <isa/pnpvar.h> 16167482Sbabkin 16267482Sbabkin#define WDSTOPHYS(wp, a) ( ((u_long)a) - ((u_long)wp->dx) + ((u_long)wp->dx_p) ) 16367482Sbabkin#define WDSTOVIRT(wp, a) ( ((char *)a) - ((char*)wp->dx_p) + ((char *)wp->dx) ) 16467482Sbabkin 16567482Sbabkin/* 0x10000 (64k) should be enough. But just to be sure... */ 16667482Sbabkin#define BUFSIZ 0x12000 16767482Sbabkin/* buffer fragment size, no more than 32 frags per buffer */ 16867482Sbabkin#define FRAGSIZ 0x1000 16967482Sbabkin 17067482Sbabkin 17167482Sbabkin/* WD7000 registers */ 17267482Sbabkin#define WDS_STAT 0 /* read */ 17367482Sbabkin#define WDS_IRQSTAT 1 /* read */ 17467482Sbabkin 17567482Sbabkin#define WDS_CMD 0 /* write */ 17667482Sbabkin#define WDS_IRQACK 1 /* write */ 17767482Sbabkin#define WDS_HCR 2 /* write */ 17867482Sbabkin 17967482Sbabkin#define WDS_NPORTS 4 /* number of ports used */ 18067482Sbabkin 18167482Sbabkin/* WDS_STAT (read) defs */ 18267482Sbabkin#define WDS_IRQ 0x80 18367482Sbabkin#define WDS_RDY 0x40 18467482Sbabkin#define WDS_REJ 0x20 18567482Sbabkin#define WDS_INIT 0x10 18667482Sbabkin 18767482Sbabkin/* WDS_IRQSTAT (read) defs */ 18867482Sbabkin#define WDSI_MASK 0xc0 18967482Sbabkin#define WDSI_ERR 0x00 19067482Sbabkin#define WDSI_MFREE 0x80 19167482Sbabkin#define WDSI_MSVC 0xc0 19267482Sbabkin 19367482Sbabkin/* WDS_CMD (write) defs */ 19467482Sbabkin#define WDSC_NOOP 0x00 19567482Sbabkin#define WDSC_INIT 0x01 19667482Sbabkin#define WDSC_DISUNSOL 0x02 /* disable unsolicited ints */ 19767482Sbabkin#define WDSC_ENAUNSOL 0x03 /* enable unsolicited ints */ 19867482Sbabkin#define WDSC_IRQMFREE 0x04 /* interrupt on free RQM */ 19967482Sbabkin#define WDSC_SCSIRESETSOFT 0x05 /* soft reset */ 20067482Sbabkin#define WDSC_SCSIRESETHARD 0x06 /* hard reset ack */ 20167482Sbabkin#define WDSC_MSTART(m) (0x80 + (m)) /* start mailbox */ 20267482Sbabkin#define WDSC_MMSTART(m) (0xc0 + (m)) /* start all mailboxes */ 20367482Sbabkin 20467482Sbabkin/* WDS_HCR (write) defs */ 20567482Sbabkin#define WDSH_IRQEN 0x08 20667482Sbabkin#define WDSH_DRQEN 0x04 20767482Sbabkin#define WDSH_SCSIRESET 0x02 20867482Sbabkin#define WDSH_ASCRESET 0x01 20967482Sbabkin 21067482Sbabkinstruct wds_cmd { 21167482Sbabkin u_int8_t cmd; 21267482Sbabkin u_int8_t targ; 21367482Sbabkin u_int8_t scb[12]; 21467482Sbabkin u_int8_t stat; 21567482Sbabkin u_int8_t venderr; 21667482Sbabkin u_int8_t len[3]; 21767482Sbabkin u_int8_t data[3]; 21867482Sbabkin u_int8_t next[3]; 21967482Sbabkin u_int8_t write; 22067482Sbabkin u_int8_t xx[6]; 22167482Sbabkin}; 22267482Sbabkin 22367482Sbabkinstruct wds_req { 22467482Sbabkin struct wds_cmd cmd; 22567482Sbabkin union ccb *ccb; 22667482Sbabkin enum { 22767482Sbabkin WR_DONE = 0x01, 22867482Sbabkin WR_SENSE = 0x02 22967482Sbabkin } flags; 23067482Sbabkin u_int8_t *buf; /* address of linear data buffer */ 23167482Sbabkin u_int32_t mask; /* mask of allocated fragments */ 23267482Sbabkin u_int8_t ombn; 23367482Sbabkin u_int8_t id; /* number of request */ 23467482Sbabkin}; 23567482Sbabkin 23667482Sbabkin#define WDSX_SCSICMD 0x00 23767482Sbabkin#define WDSX_OPEN_RCVBUF 0x80 23867482Sbabkin#define WDSX_RCV_CMD 0x81 23967482Sbabkin#define WDSX_RCV_DATA 0x82 24067482Sbabkin#define WDSX_RCV_DATASTAT 0x83 24167482Sbabkin#define WDSX_SND_DATA 0x84 24267482Sbabkin#define WDSX_SND_DATASTAT 0x85 24367482Sbabkin#define WDSX_SND_CMDSTAT 0x86 24467482Sbabkin#define WDSX_READINIT 0x88 24567482Sbabkin#define WDSX_READSCSIID 0x89 24667482Sbabkin#define WDSX_SETUNSOLIRQMASK 0x8a 24767482Sbabkin#define WDSX_GETUNSOLIRQMASK 0x8b 24867482Sbabkin#define WDSX_GETFIRMREV 0x8c 24967482Sbabkin#define WDSX_EXECDIAG 0x8d 25067482Sbabkin#define WDSX_SETEXECPARM 0x8e 25167482Sbabkin#define WDSX_GETEXECPARM 0x8f 25267482Sbabkin 25367482Sbabkinstruct wds_mb { 25467482Sbabkin u_int8_t stat; 25567482Sbabkin u_int8_t addr[3]; 25667482Sbabkin}; 25767482Sbabkin/* ICMB status value */ 25867482Sbabkin#define ICMB_OK 0x01 25967482Sbabkin#define ICMB_OKERR 0x02 26067482Sbabkin#define ICMB_ETIME 0x04 26167482Sbabkin#define ICMB_ERESET 0x05 26267482Sbabkin#define ICMB_ETARCMD 0x06 26367482Sbabkin#define ICMB_ERESEL 0x80 26467482Sbabkin#define ICMB_ESEL 0x81 26567482Sbabkin#define ICMB_EABORT 0x82 26667482Sbabkin#define ICMB_ESRESET 0x83 26767482Sbabkin#define ICMB_EHRESET 0x84 26867482Sbabkin 26967482Sbabkinstruct wds_setup { 27067482Sbabkin u_int8_t cmd; 27167482Sbabkin u_int8_t scsi_id; 27267482Sbabkin u_int8_t buson_t; 27367482Sbabkin u_int8_t busoff_t; 27467482Sbabkin u_int8_t xx; 27567482Sbabkin u_int8_t mbaddr[3]; 27667482Sbabkin u_int8_t nomb; 27767482Sbabkin u_int8_t nimb; 27867482Sbabkin}; 27967482Sbabkin 28067482Sbabkin/* the code depends on equality of these parameters */ 28167482Sbabkin#define MAXSIMUL 8 28267482Sbabkin#define WDS_NOMB MAXSIMUL 28367482Sbabkin#define WDS_NIMB MAXSIMUL 28467482Sbabkin 28567482Sbabkinstatic int fragsiz; 28667482Sbabkinstatic int nfrags; 28767482Sbabkin 28867482Sbabkin/* structure for data exchange with controller */ 28967482Sbabkin 29067482Sbabkinstruct wdsdx { 29167482Sbabkin struct wds_req req[MAXSIMUL]; 29267482Sbabkin struct wds_mb ombs[MAXSIMUL]; 29367482Sbabkin struct wds_mb imbs[MAXSIMUL]; 29467482Sbabkin u_int8_t data[BUFSIZ]; 29567482Sbabkin}; 29667482Sbabkin 29767482Sbabkin/* structure softc */ 29867482Sbabkin 29967482Sbabkinstruct wds { 30067482Sbabkin device_t dev; 30167482Sbabkin int unit; 30267482Sbabkin int addr; 30367482Sbabkin int drq; 30467482Sbabkin struct cam_sim *sim; /* SIM descriptor for this card */ 30567482Sbabkin struct cam_path *path; /* wildcard path for this card */ 30667482Sbabkin char want_wdsr; /* resource shortage flag */ 30767482Sbabkin u_int32_t data_free; 30867482Sbabkin u_int32_t wdsr_free; 30967482Sbabkin struct wdsdx *dx; 31067482Sbabkin struct wdsdx *dx_p; /* physical address */ 31167482Sbabkin struct resource *port_r; 31267482Sbabkin int port_rid; 31367482Sbabkin struct resource *drq_r; 31467482Sbabkin int drq_rid; 31567482Sbabkin struct resource *intr_r; 31667482Sbabkin int intr_rid; 31767482Sbabkin void *intr_cookie; 31867482Sbabkin bus_dma_tag_t bustag; 31967482Sbabkin bus_dmamap_t busmap; 32067482Sbabkin}; 32167482Sbabkin 32267482Sbabkin#define ccb_wdsr spriv_ptr1 /* for wds request */ 32367482Sbabkin 32467482Sbabkinstatic int wds_probe(device_t dev); 32567482Sbabkinstatic int wds_attach(device_t dev); 32667482Sbabkinstatic void wds_intr(struct wds *wp); 32767482Sbabkin 32867482Sbabkinstatic void wds_action(struct cam_sim * sim, union ccb * ccb); 32967482Sbabkinstatic void wds_poll(struct cam_sim * sim); 33067482Sbabkin 33167482Sbabkinstatic int wds_preinit(struct wds *wp); 33267482Sbabkinstatic int wds_init(struct wds *wp); 33367482Sbabkin 33467482Sbabkinstatic void wds_alloc_callback(void *arg, bus_dma_segment_t *seg, 33567482Sbabkin int nseg, int error); 33667482Sbabkinstatic void wds_free_resources(struct wds *wp); 33767482Sbabkin 33867482Sbabkinstatic struct wds_req *wdsr_alloc(struct wds *wp); 33967482Sbabkin 34067482Sbabkinstatic void wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio); 34167482Sbabkinstatic void wdsr_ccb_done(struct wds *wp, struct wds_req *r, 34267482Sbabkin union ccb *ccb, u_int32_t status); 34367482Sbabkin 34467482Sbabkinstatic void wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat); 34567482Sbabkinstatic int wds_runsense(struct wds *wp, struct wds_req *r); 34667482Sbabkinstatic int wds_getvers(struct wds *wp); 34767482Sbabkin 34867482Sbabkinstatic int wds_cmd(int base, u_int8_t * p, int l); 34967482Sbabkinstatic void wds_wait(int reg, int mask, int val); 35067482Sbabkin 35167482Sbabkinstatic struct wds_req *cmdtovirt(struct wds *wp, u_int32_t phys); 35267482Sbabkin 35367482Sbabkinstatic u_int32_t frag_alloc(struct wds *wp, int size, u_int8_t **res, 35467482Sbabkin u_int32_t *maskp); 35567482Sbabkinstatic void frag_free(struct wds *wp, u_int32_t mask); 35667482Sbabkin 35767482Sbabkinvoid wds_print(void); 35867482Sbabkin 35967482Sbabkin#if WDS_ENABLE_SMALLOG==1 36067482Sbabkinstatic __inline void smallog(char c); 36167482Sbabkinvoid wds_printsmallog(void); 36267482Sbabkin#endif /* SMALLOG */ 36367482Sbabkin 36467482Sbabkin/* SCSI ID of the adapter itself */ 36567482Sbabkin#ifndef WDS_HBA_ID 36667482Sbabkin#define WDS_HBA_ID 7 36767482Sbabkin#endif 36867482Sbabkin 36967482Sbabkin#if WDS_DEBUG == 2 37067482Sbabkin#define LOGLINESIZ 81 37167482Sbabkin#define NLOGLINES 300 37267482Sbabkin#define DBX wds_nextlog(), LOGLINESIZ, 37367482Sbabkin#define DBG snprintf 37467482Sbabkin 37567482Sbabkinstatic char wds_log[NLOGLINES][LOGLINESIZ]; 37667482Sbabkinstatic int logwrite = 0, logread = 0; 37767482Sbabkinstatic char *wds_nextlog(void); 37867482Sbabkinvoid wds_printlog(void); 37967482Sbabkin 38067482Sbabkin#elif WDS_DEBUG != 0 38167482Sbabkin#define DBX 38267482Sbabkin#define DBG printf 38367482Sbabkin#else 38467482Sbabkin#define DBX 38567482Sbabkin#define DBG if(0) printf 38667482Sbabkin#endif 38767482Sbabkin 38867482Sbabkin/* the table of supported bus methods */ 38967482Sbabkinstatic device_method_t wds_isa_methods[] = { 39067482Sbabkin DEVMETHOD(device_probe, wds_probe), 39167482Sbabkin DEVMETHOD(device_attach, wds_attach), 39267482Sbabkin { 0, 0 } 39367482Sbabkin}; 39467482Sbabkin 39567482Sbabkinstatic driver_t wds_isa_driver = { 39667482Sbabkin "wds", 39767482Sbabkin wds_isa_methods, 39867482Sbabkin sizeof(struct wds), 39967482Sbabkin}; 40067482Sbabkin 40167482Sbabkinstatic devclass_t wds_devclass; 40267482Sbabkin 40367482SbabkinDRIVER_MODULE(wds, isa, wds_isa_driver, wds_devclass, 0, 0); 404165102SmjacobMODULE_DEPEND(wds, isa, 1, 1, 1); 405165102SmjacobMODULE_DEPEND(wds, cam, 1, 1, 1); 40667482Sbabkin 40767482Sbabkin#if WDS_ENABLE_SMALLOG==1 40867482Sbabkin#define SMALLOGSIZ 512 40967482Sbabkinstatic char wds_smallog[SMALLOGSIZ]; 41067482Sbabkinstatic char *wds_smallogp = wds_smallog; 41167482Sbabkinstatic char wds_smallogover = 0; 41267482Sbabkin 41367482Sbabkinstatic __inline void 41467482Sbabkinsmallog(char c) 41567482Sbabkin{ 41667482Sbabkin *wds_smallogp = c; 41767482Sbabkin if (++wds_smallogp == &wds_smallog[SMALLOGSIZ]) { 41867482Sbabkin wds_smallogp = wds_smallog; 41967482Sbabkin wds_smallogover = 1; 42067482Sbabkin } 42167482Sbabkin} 42267482Sbabkin 42367482Sbabkin#define smallog2(a, b) (smallog(a), smallog(b)) 42467482Sbabkin#define smallog3(a, b, c) (smallog(a), smallog(b), smallog(c)) 42567482Sbabkin#define smallog4(a, b, c, d) (smallog(a),smallog(b),smallog(c),smallog(d)) 42667482Sbabkin 42767482Sbabkinvoid 42867482Sbabkinwds_printsmallog(void) 42967482Sbabkin{ 43067482Sbabkin int i; 43167482Sbabkin char *p; 43267482Sbabkin 43367482Sbabkin printf("wds: "); 43467482Sbabkin p = wds_smallogover ? wds_smallogp : wds_smallog; 43567482Sbabkin i = 0; 43667482Sbabkin do { 43767482Sbabkin printf("%c", *p); 43867482Sbabkin if (++p == &wds_smallog[SMALLOGSIZ]) 43967482Sbabkin p = wds_smallog; 44067482Sbabkin if (++i == 70) { 44167482Sbabkin i = 0; 44267482Sbabkin printf("\nwds: "); 44367482Sbabkin } 44467482Sbabkin } while (p != wds_smallogp); 44567482Sbabkin printf("\n"); 44667482Sbabkin} 44767482Sbabkin#else 44867482Sbabkin#define smallog(a) 44967482Sbabkin#define smallog2(a, b) 45067482Sbabkin#define smallog3(a, b, c) 45167482Sbabkin#define smallog4(a, b, c, d) 45267482Sbabkin#endif /* SMALLOG */ 45367482Sbabkin 45467482Sbabkinstatic int 45567482Sbabkinwds_probe(device_t dev) 45667482Sbabkin{ 45767482Sbabkin struct wds *wp; 45867482Sbabkin int error = 0; 45967482Sbabkin int irq; 46067482Sbabkin 46167482Sbabkin /* No pnp support */ 46267482Sbabkin if (isa_get_vendorid(dev)) 46367482Sbabkin return (ENXIO); 46467482Sbabkin 46567482Sbabkin wp = (struct wds *) device_get_softc(dev); 46667482Sbabkin wp->unit = device_get_unit(dev); 46767482Sbabkin wp->dev = dev; 46867482Sbabkin 46967482Sbabkin wp->addr = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/); 47067482Sbabkin if (wp->addr == 0 || wp->addr <0x300 47167482Sbabkin || wp->addr > 0x3f8 || wp->addr & 0x7) { 47267482Sbabkin device_printf(dev, "invalid port address 0x%x\n", wp->addr); 47367482Sbabkin return (ENXIO); 47467482Sbabkin } 47567482Sbabkin 47667482Sbabkin if (bus_set_resource(dev, SYS_RES_IOPORT, 0, wp->addr, WDS_NPORTS) < 0) 47767482Sbabkin return (ENXIO); 47867482Sbabkin 47967482Sbabkin /* get the DRQ */ 48067482Sbabkin wp->drq = bus_get_resource_start(dev, SYS_RES_DRQ, 0 /*rid*/); 48167482Sbabkin if (wp->drq < 5 || wp->drq > 7) { 48267482Sbabkin device_printf(dev, "invalid DRQ %d\n", wp->drq); 48367482Sbabkin return (ENXIO); 48467482Sbabkin } 48567482Sbabkin 48667482Sbabkin /* get the IRQ */ 48767482Sbabkin irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0 /*rid*/); 48867482Sbabkin if (irq < 3) { 48967482Sbabkin device_printf(dev, "invalid IRQ %d\n", irq); 49067482Sbabkin return (ENXIO); 49167482Sbabkin } 49267482Sbabkin 49367482Sbabkin wp->port_rid = 0; 49467482Sbabkin wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &wp->port_rid, 49567482Sbabkin /*start*/ 0, /*end*/ ~0, 49667482Sbabkin /*count*/ 0, RF_ACTIVE); 49767482Sbabkin if (wp->port_r == NULL) 49867482Sbabkin return (ENXIO); 49967482Sbabkin 50067482Sbabkin error = wds_preinit(wp); 50167482Sbabkin 50267482Sbabkin /* 50367482Sbabkin * We cannot hold resources between probe and 50467482Sbabkin * attach as we may never be attached. 50567482Sbabkin */ 50667482Sbabkin wds_free_resources(wp); 50767482Sbabkin 50867482Sbabkin return (error); 50967482Sbabkin} 51067482Sbabkin 51167482Sbabkinstatic int 51267482Sbabkinwds_attach(device_t dev) 51367482Sbabkin{ 51467482Sbabkin struct wds *wp; 51567482Sbabkin struct cam_devq *devq; 51667482Sbabkin struct cam_sim *sim; 51767482Sbabkin struct cam_path *pathp; 51867482Sbabkin int i; 51967482Sbabkin int error = 0; 52067482Sbabkin 52167482Sbabkin wp = (struct wds *)device_get_softc(dev); 52267482Sbabkin 52367482Sbabkin wp->port_rid = 0; 52467482Sbabkin wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &wp->port_rid, 52567482Sbabkin /*start*/ 0, /*end*/ ~0, 52667482Sbabkin /*count*/ 0, RF_ACTIVE); 52767482Sbabkin if (wp->port_r == NULL) 52867482Sbabkin return (ENXIO); 52967482Sbabkin 53067482Sbabkin /* We must now release resources on error. */ 53167482Sbabkin 53267482Sbabkin wp->drq_rid = 0; 53367482Sbabkin wp->drq_r = bus_alloc_resource(dev, SYS_RES_DRQ, &wp->drq_rid, 53467482Sbabkin /*start*/ 0, /*end*/ ~0, 53567482Sbabkin /*count*/ 0, RF_ACTIVE); 53667482Sbabkin if (wp->drq_r == NULL) 53767482Sbabkin goto bad; 53867482Sbabkin 53967482Sbabkin wp->intr_rid = 0; 54067482Sbabkin wp->intr_r = bus_alloc_resource(dev, SYS_RES_IRQ, &wp->intr_rid, 54167482Sbabkin /*start*/ 0, /*end*/ ~0, 54267482Sbabkin /*count*/ 0, RF_ACTIVE); 54367482Sbabkin if (wp->intr_r == NULL) 54467482Sbabkin goto bad; 54573280Smarkm error = bus_setup_intr(dev, wp->intr_r, INTR_TYPE_CAM | INTR_ENTROPY, 546166914Simp NULL, (driver_intr_t *)wds_intr, (void *)wp, 54767482Sbabkin &wp->intr_cookie); 54867482Sbabkin if (error) 54967482Sbabkin goto bad; 55067482Sbabkin 55167482Sbabkin /* now create the memory buffer */ 552233024Sscottl error = bus_dma_tag_create(bus_get_dma_tag(dev), /*alignment*/4, 55367482Sbabkin /*boundary*/0, 55467482Sbabkin /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 55567482Sbabkin /*highaddr*/ BUS_SPACE_MAXADDR, 55667482Sbabkin /*filter*/ NULL, /*filterarg*/ NULL, 55767482Sbabkin /*maxsize*/ sizeof(* wp->dx), 55867482Sbabkin /*nsegments*/ 1, 55967482Sbabkin /*maxsegsz*/ sizeof(* wp->dx), /*flags*/ 0, 560117126Sscottl /*lockfunc*/busdma_lock_mutex, 561117126Sscottl /*lockarg*/&Giant, 56267482Sbabkin &wp->bustag); 56367482Sbabkin if (error) 56467482Sbabkin goto bad; 56567482Sbabkin 56667482Sbabkin error = bus_dmamem_alloc(wp->bustag, (void **)&wp->dx, 56767482Sbabkin /*flags*/ 0, &wp->busmap); 56867482Sbabkin if (error) 56967482Sbabkin goto bad; 57067482Sbabkin 57167482Sbabkin bus_dmamap_load(wp->bustag, wp->busmap, (void *)wp->dx, 57267482Sbabkin sizeof(* wp->dx), wds_alloc_callback, 57367482Sbabkin (void *)&wp->dx_p, /*flags*/0); 57467482Sbabkin 57567482Sbabkin /* initialize the wds_req structures on this unit */ 57667482Sbabkin for(i=0; i<MAXSIMUL; i++) { 57767482Sbabkin wp->dx->req[i].id = i; 57867482Sbabkin wp->wdsr_free |= 1<<i; 57967482Sbabkin } 58067482Sbabkin 58167482Sbabkin /* initialize the memory buffer allocation for this unit */ 58267482Sbabkin if (BUFSIZ / FRAGSIZ > 32) { 58367482Sbabkin fragsiz = (BUFSIZ / 32) & ~0x01; /* keep it word-aligned */ 58467482Sbabkin device_printf(dev, "data buffer fragment size too small. " 58567482Sbabkin "BUFSIZE / FRAGSIZE must be <= 32\n"); 58667482Sbabkin } else 58767482Sbabkin fragsiz = FRAGSIZ & ~0x01; /* keep it word-aligned */ 58867482Sbabkin 58967482Sbabkin wp->data_free = 0; 59067482Sbabkin nfrags = 0; 59167482Sbabkin for (i = fragsiz; i <= BUFSIZ; i += fragsiz) { 59267482Sbabkin nfrags++; 59367482Sbabkin wp->data_free = (wp->data_free << 1) | 1; 59467482Sbabkin } 59567482Sbabkin 59667482Sbabkin /* complete the hardware initialization */ 59767482Sbabkin if (wds_init(wp) != 0) 59867482Sbabkin goto bad; 59967482Sbabkin 60067482Sbabkin if (wds_getvers(wp) == -1) 60167482Sbabkin device_printf(dev, "getvers failed\n"); 60267482Sbabkin device_printf(dev, "using %d bytes / %d frags for dma buffer\n", 60367482Sbabkin BUFSIZ, nfrags); 60467482Sbabkin 60567482Sbabkin devq = cam_simq_alloc(MAXSIMUL); 60667482Sbabkin if (devq == NULL) 60767482Sbabkin goto bad; 60867482Sbabkin 60967482Sbabkin sim = cam_sim_alloc(wds_action, wds_poll, "wds", (void *) wp, 610168752Sscottl wp->unit, &Giant, 1, 1, devq); 61167482Sbabkin if (sim == NULL) { 61267482Sbabkin cam_simq_free(devq); 61367482Sbabkin goto bad; 61467482Sbabkin } 61567482Sbabkin wp->sim = sim; 61667482Sbabkin 617170872Sscottl if (xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) { 61867482Sbabkin cam_sim_free(sim, /* free_devq */ TRUE); 61967482Sbabkin goto bad; 62067482Sbabkin } 62167482Sbabkin if (xpt_create_path(&pathp, /* periph */ NULL, 62267482Sbabkin cam_sim_path(sim), CAM_TARGET_WILDCARD, 62367482Sbabkin CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 62467482Sbabkin xpt_bus_deregister(cam_sim_path(sim)); 62567482Sbabkin cam_sim_free(sim, /* free_devq */ TRUE); 62667482Sbabkin goto bad; 62767482Sbabkin } 62867482Sbabkin wp->path = pathp; 62967482Sbabkin 63067482Sbabkin return (0); 63167482Sbabkin 63267482Sbabkinbad: 63367482Sbabkin wds_free_resources(wp); 63467482Sbabkin if (error) 63567482Sbabkin return (error); 63667482Sbabkin else /* exact error is unknown */ 63767482Sbabkin return (ENXIO); 63867482Sbabkin} 63967482Sbabkin 64067482Sbabkin/* callback to save the physical address */ 64167482Sbabkinstatic void 64267482Sbabkinwds_alloc_callback(void *arg, bus_dma_segment_t *seg, int nseg, int error) 64367482Sbabkin{ 64467482Sbabkin *(bus_addr_t *)arg = seg[0].ds_addr; 64567482Sbabkin} 64667482Sbabkin 64767482Sbabkinstatic void 64867482Sbabkinwds_free_resources(struct wds *wp) 64967482Sbabkin{ 65067482Sbabkin /* check every resource and free if not zero */ 65167482Sbabkin 65267482Sbabkin /* interrupt handler */ 65367482Sbabkin if (wp->intr_r) { 65467482Sbabkin bus_teardown_intr(wp->dev, wp->intr_r, wp->intr_cookie); 65567482Sbabkin bus_release_resource(wp->dev, SYS_RES_IRQ, wp->intr_rid, 65667482Sbabkin wp->intr_r); 65767482Sbabkin wp->intr_r = 0; 65867482Sbabkin } 65967482Sbabkin 66067482Sbabkin /* all kinds of memory maps we could have allocated */ 66167482Sbabkin if (wp->dx_p) { 66267482Sbabkin bus_dmamap_unload(wp->bustag, wp->busmap); 66367482Sbabkin wp->dx_p = 0; 66467482Sbabkin } 66567482Sbabkin if (wp->dx) { /* wp->busmap may be legitimately equal to 0 */ 66667482Sbabkin /* the map will also be freed */ 66767482Sbabkin bus_dmamem_free(wp->bustag, wp->dx, wp->busmap); 66867482Sbabkin wp->dx = 0; 66967482Sbabkin } 67067482Sbabkin if (wp->bustag) { 67167482Sbabkin bus_dma_tag_destroy(wp->bustag); 67267482Sbabkin wp->bustag = 0; 67367482Sbabkin } 67467482Sbabkin /* release all the bus resources */ 67567482Sbabkin if (wp->drq_r) { 67667482Sbabkin bus_release_resource(wp->dev, SYS_RES_DRQ, 67767482Sbabkin wp->drq_rid, wp->drq_r); 67867482Sbabkin wp->drq_r = 0; 67967482Sbabkin } 68067482Sbabkin if (wp->port_r) { 68167482Sbabkin bus_release_resource(wp->dev, SYS_RES_IOPORT, 68267482Sbabkin wp->port_rid, wp->port_r); 68367482Sbabkin wp->port_r = 0; 68467482Sbabkin } 68567482Sbabkin} 68667482Sbabkin 68767482Sbabkin/* allocate contiguous fragments from the buffer */ 68867482Sbabkinstatic u_int32_t 68967482Sbabkinfrag_alloc(struct wds *wp, int size, u_int8_t **res, u_int32_t *maskp) 69067482Sbabkin{ 69167482Sbabkin int i; 69267482Sbabkin u_int32_t mask; 69367482Sbabkin u_int32_t free; 69467482Sbabkin 69567482Sbabkin if (size > fragsiz * nfrags) 69667482Sbabkin return (CAM_REQ_TOO_BIG); 69767482Sbabkin 69867482Sbabkin mask = 1; /* always allocate at least 1 fragment */ 69967482Sbabkin for (i = fragsiz; i < size; i += fragsiz) 70067482Sbabkin mask = (mask << 1) | 1; 70167482Sbabkin 70267482Sbabkin free = wp->data_free; 70367482Sbabkin if(free != 0) { 70467482Sbabkin i = ffs(free)-1; /* ffs counts bits from 1 */ 70567482Sbabkin for (mask <<= i; i < nfrags; i++) { 70667482Sbabkin if ((free & mask) == mask) { 70767482Sbabkin wp->data_free &= ~mask; /* mark frags as busy */ 70867482Sbabkin *maskp = mask; 70967482Sbabkin *res = &wp->dx->data[fragsiz * i]; 71067482Sbabkin DBG(DBX "wds%d: allocated buffer mask=0x%x\n", 71167482Sbabkin wp->unit, mask); 71267482Sbabkin return (CAM_REQ_CMP); 71367482Sbabkin } 71467482Sbabkin if (mask & 0x80000000) 71567482Sbabkin break; 71667482Sbabkin 71767482Sbabkin mask <<= 1; 71867482Sbabkin } 71967482Sbabkin } 72067482Sbabkin return (CAM_REQUEUE_REQ); /* no free memory now, try later */ 72167482Sbabkin} 72267482Sbabkin 72367482Sbabkinstatic void 72467482Sbabkinfrag_free(struct wds *wp, u_int32_t mask) 72567482Sbabkin{ 72667482Sbabkin wp->data_free |= mask; /* mark frags as free */ 72767482Sbabkin DBG(DBX "wds%d: freed buffer mask=0x%x\n", wp->unit, mask); 72867482Sbabkin} 72967482Sbabkin 73067482Sbabkinstatic struct wds_req * 73167482Sbabkinwdsr_alloc(struct wds *wp) 73267482Sbabkin{ 73367482Sbabkin struct wds_req *r; 73467482Sbabkin int x; 73567482Sbabkin int i; 73667482Sbabkin 73767482Sbabkin r = NULL; 73867482Sbabkin x = splcam(); 73967482Sbabkin 74067482Sbabkin /* anyway most of the time only 1 or 2 commands will 74167482Sbabkin * be active because SCSI disconnect is not supported 74267482Sbabkin * by hardware, so the search should be fast enough 74367482Sbabkin */ 74467482Sbabkin i = ffs(wp->wdsr_free) - 1; 74567482Sbabkin if(i < 0) { 74667482Sbabkin splx(x); 74767482Sbabkin return (NULL); 74867482Sbabkin } 74967482Sbabkin wp->wdsr_free &= ~ (1<<i); 75067482Sbabkin r = &wp->dx->req[i]; 75167482Sbabkin r->flags = 0; /* reset all flags */ 75267482Sbabkin r->ombn = i; /* luckily we have one omb per wdsr */ 75367482Sbabkin wp->dx->ombs[i].stat = 1; 75467482Sbabkin 75567482Sbabkin r->mask = 0; 75667482Sbabkin splx(x); 75767482Sbabkin smallog3('r', i + '0', r->ombn + '0'); 75867482Sbabkin return (r); 75967482Sbabkin} 76067482Sbabkin 76167482Sbabkinstatic void 76267482Sbabkinwds_intr(struct wds *wp) 76367482Sbabkin{ 76467482Sbabkin struct wds_req *rp; 76567482Sbabkin struct wds_mb *in; 76667482Sbabkin u_int8_t stat; 76767482Sbabkin u_int8_t c; 76867482Sbabkin int addr = wp->addr; 76967482Sbabkin 77067482Sbabkin DBG(DBX "wds%d: interrupt [\n", wp->unit); 77167482Sbabkin smallog('['); 77267482Sbabkin 77367482Sbabkin if (inb(addr + WDS_STAT) & WDS_IRQ) { 77467482Sbabkin c = inb(addr + WDS_IRQSTAT); 77567482Sbabkin if ((c & WDSI_MASK) == WDSI_MSVC) { 77667482Sbabkin c = c & ~WDSI_MASK; 77767482Sbabkin in = &wp->dx->imbs[c]; 77867482Sbabkin 77967482Sbabkin rp = cmdtovirt(wp, scsi_3btoul(in->addr)); 78067482Sbabkin stat = in->stat; 78167482Sbabkin 78267482Sbabkin if (rp != NULL) 78367482Sbabkin wds_done(wp, rp, stat); 78467482Sbabkin else 78567482Sbabkin device_printf(wp->dev, 78667482Sbabkin "got weird command address %p" 78767482Sbabkin "from controller\n", rp); 78867482Sbabkin 78967482Sbabkin in->stat = 0; 79067482Sbabkin } else 79167482Sbabkin device_printf(wp->dev, 79267482Sbabkin "weird interrupt, irqstat=0x%x\n", c); 79367482Sbabkin outb(addr + WDS_IRQACK, 0); 79467482Sbabkin } else { 79567482Sbabkin smallog('?'); 79667482Sbabkin } 79767482Sbabkin smallog(']'); 79867482Sbabkin DBG(DBX "wds%d: ]\n", wp->unit); 79967482Sbabkin} 80067482Sbabkin 80167482Sbabkinstatic void 80267482Sbabkinwds_done(struct wds *wp, struct wds_req *r, u_int8_t stat) 80367482Sbabkin{ 80467482Sbabkin struct ccb_hdr *ccb_h; 80567482Sbabkin struct ccb_scsiio *csio; 80667482Sbabkin int status; 80767482Sbabkin 80867482Sbabkin smallog('d'); 80967482Sbabkin 81067482Sbabkin if (r->flags & WR_DONE) { 81167482Sbabkin device_printf(wp->dev, 81267482Sbabkin "request %d reported done twice\n", r->id); 81367482Sbabkin smallog2('x', r->id + '0'); 81467482Sbabkin return; 81567482Sbabkin } 81667482Sbabkin 81767482Sbabkin smallog(r->id + '0'); 81867482Sbabkin ccb_h = &r->ccb->ccb_h; 81967482Sbabkin csio = &r->ccb->csio; 82067482Sbabkin status = CAM_REQ_CMP_ERR; 82167482Sbabkin 82267482Sbabkin DBG(DBX "wds%d: %s stat=0x%x c->stat=0x%x c->venderr=0x%x\n", wp->unit, 82367482Sbabkin r->flags & WR_SENSE ? "(sense)" : "", 82467482Sbabkin stat, r->cmd.stat, r->cmd.venderr); 82567482Sbabkin 82667482Sbabkin if (r->flags & WR_SENSE) { 82767482Sbabkin if (stat == ICMB_OK || (stat == ICMB_OKERR && r->cmd.stat == 0)) { 82867482Sbabkin DBG(DBX "wds%d: sense 0x%x\n", wp->unit, r->buf[0]); 82967482Sbabkin /* it has the same size now but for future */ 83067482Sbabkin bcopy(r->buf, &csio->sense_data, 83167482Sbabkin sizeof(struct scsi_sense_data) > csio->sense_len ? 83267482Sbabkin csio->sense_len : sizeof(struct scsi_sense_data)); 83367482Sbabkin if (sizeof(struct scsi_sense_data) >= csio->sense_len) 83467482Sbabkin csio->sense_resid = 0; 83567482Sbabkin else 83667482Sbabkin csio->sense_resid = 83767482Sbabkin csio->sense_len 83867482Sbabkin - sizeof(struct scsi_sense_data); 83967482Sbabkin status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR; 84067482Sbabkin } else { 84167482Sbabkin status = CAM_AUTOSENSE_FAIL; 84267482Sbabkin } 84367482Sbabkin } else { 84467482Sbabkin switch (stat) { 84567482Sbabkin case ICMB_OK: 84667482Sbabkin if (ccb_h) { 84767482Sbabkin csio->resid = 0; 84867482Sbabkin csio->scsi_status = r->cmd.stat; 84967482Sbabkin status = CAM_REQ_CMP; 85067482Sbabkin } 85167482Sbabkin break; 85267482Sbabkin case ICMB_OKERR: 85367482Sbabkin if (ccb_h) { 85467482Sbabkin csio->scsi_status = r->cmd.stat; 85567482Sbabkin if (r->cmd.stat) { 85667482Sbabkin if (ccb_h->flags & CAM_DIS_AUTOSENSE) 85767482Sbabkin status = CAM_SCSI_STATUS_ERROR; 85867482Sbabkin else { 85967482Sbabkin if ( wds_runsense(wp, r) == CAM_REQ_CMP ) 86067482Sbabkin return; 86167482Sbabkin /* in case of error continue with freeing of CCB */ 86267482Sbabkin } 86367482Sbabkin } else { 86467482Sbabkin csio->resid = 0; 86567482Sbabkin status = CAM_REQ_CMP; 86667482Sbabkin } 86767482Sbabkin } 86867482Sbabkin break; 86967482Sbabkin case ICMB_ETIME: 87067482Sbabkin if (ccb_h) 87167482Sbabkin status = CAM_SEL_TIMEOUT; 87267482Sbabkin break; 87367482Sbabkin case ICMB_ERESET: 87467482Sbabkin case ICMB_ETARCMD: 87567482Sbabkin case ICMB_ERESEL: 87667482Sbabkin case ICMB_ESEL: 87767482Sbabkin case ICMB_EABORT: 87867482Sbabkin case ICMB_ESRESET: 87967482Sbabkin case ICMB_EHRESET: 88067482Sbabkin if (ccb_h) 88167482Sbabkin status = CAM_REQ_CMP_ERR; 88267482Sbabkin break; 88367482Sbabkin } 88467482Sbabkin 88567482Sbabkin if (ccb_h && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) { 88667482Sbabkin /* we accept only virtual addresses in wds_action() */ 88767482Sbabkin bcopy(r->buf, csio->data_ptr, csio->dxfer_len); 88867482Sbabkin } 88967482Sbabkin } 89067482Sbabkin 89167482Sbabkin r->flags |= WR_DONE; 89267482Sbabkin wp->dx->ombs[r->ombn].stat = 0; 89367482Sbabkin 89467482Sbabkin if (ccb_h) { 89567482Sbabkin wdsr_ccb_done(wp, r, r->ccb, status); 89667482Sbabkin smallog3('-', ccb_h->target_id + '0', ccb_h->target_lun + '0'); 89767482Sbabkin } else { 89867482Sbabkin frag_free(wp, r->mask); 89967482Sbabkin if (wp->want_wdsr) { 90067482Sbabkin wp->want_wdsr = 0; 90167482Sbabkin xpt_release_simq(wp->sim, /* run queue */ 1); 90267482Sbabkin } 90367482Sbabkin wp->wdsr_free |= (1 << r->id); 90467482Sbabkin } 90567482Sbabkin 906106592Sjhb DBG(DBX "wds%d: request %p done\n", wp->unit, r); 90767482Sbabkin} 90867482Sbabkin 90967482Sbabkin/* command returned bad status, request sense */ 91067482Sbabkin 91167482Sbabkinstatic int 91267482Sbabkinwds_runsense(struct wds *wp, struct wds_req *r) 91367482Sbabkin{ 91467482Sbabkin u_int8_t c; 91567482Sbabkin struct ccb_hdr *ccb_h; 91667482Sbabkin 91767482Sbabkin ccb_h = &r->ccb->ccb_h; 91867482Sbabkin 91967482Sbabkin r->flags |= WR_SENSE; 92067482Sbabkin scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), 92167482Sbabkin wp->dx->ombs[r->ombn].addr); 92267482Sbabkin bzero(&r->cmd, sizeof r->cmd); 92367482Sbabkin r->cmd.cmd = WDSX_SCSICMD; 92467482Sbabkin r->cmd.targ = (ccb_h->target_id << 5) | 92567482Sbabkin ccb_h->target_lun; 92667482Sbabkin 92767482Sbabkin scsi_ulto3b(0, r->cmd.next); 92867482Sbabkin 92967482Sbabkin r->cmd.scb[0] = REQUEST_SENSE; 93067482Sbabkin r->cmd.scb[1] = ccb_h->target_lun << 5; 93167482Sbabkin r->cmd.scb[4] = sizeof(struct scsi_sense_data); 93267482Sbabkin r->cmd.scb[5] = 0; 93367482Sbabkin scsi_ulto3b(WDSTOPHYS(wp, r->buf), r->cmd.data); 93467482Sbabkin scsi_ulto3b(sizeof(struct scsi_sense_data), r->cmd.len); 93567482Sbabkin r->cmd.write = 0x80; 93667482Sbabkin 93767482Sbabkin outb(wp->addr + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN); 93867482Sbabkin 93967482Sbabkin wp->dx->ombs[r->ombn].stat = 1; 94067482Sbabkin c = WDSC_MSTART(r->ombn); 94167482Sbabkin 94267482Sbabkin if (wds_cmd(wp->addr, &c, sizeof c) != 0) { 94367482Sbabkin device_printf(wp->dev, "unable to start outgoing sense mbox\n"); 94467482Sbabkin wp->dx->ombs[r->ombn].stat = 0; 94567482Sbabkin wdsr_ccb_done(wp, r, r->ccb, CAM_AUTOSENSE_FAIL); 94667482Sbabkin return CAM_AUTOSENSE_FAIL; 94767482Sbabkin } else { 948106592Sjhb DBG(DBX "wds%d: enqueued status cmd 0x%x, r=%p\n", 949106592Sjhb wp->unit, r->cmd.scb[0] & 0xFF, r); 95067482Sbabkin /* don't free CCB yet */ 95167482Sbabkin smallog3('*', ccb_h->target_id + '0', 95267482Sbabkin ccb_h->target_lun + '0'); 95367482Sbabkin return CAM_REQ_CMP; 95467482Sbabkin } 95567482Sbabkin} 95667482Sbabkin 95767482Sbabkinstatic int 95867482Sbabkinwds_getvers(struct wds *wp) 95967482Sbabkin{ 96067482Sbabkin struct wds_req *r; 96167482Sbabkin int base; 96267482Sbabkin u_int8_t c; 96367482Sbabkin int i; 96467482Sbabkin 96567482Sbabkin base = wp->addr; 96667482Sbabkin 96767482Sbabkin r = wdsr_alloc(wp); 96867482Sbabkin if (!r) { 96967482Sbabkin device_printf(wp->dev, "no request slot available!\n"); 97067482Sbabkin return (-1); 97167482Sbabkin } 97267482Sbabkin r->flags &= ~WR_DONE; 97367482Sbabkin 97467482Sbabkin r->ccb = NULL; 97567482Sbabkin 97667482Sbabkin scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr); 97767482Sbabkin 97867482Sbabkin bzero(&r->cmd, sizeof r->cmd); 97967482Sbabkin r->cmd.cmd = WDSX_GETFIRMREV; 98067482Sbabkin 98167482Sbabkin outb(base + WDS_HCR, WDSH_DRQEN); 98267482Sbabkin 98367482Sbabkin c = WDSC_MSTART(r->ombn); 98467482Sbabkin if (wds_cmd(base, (u_int8_t *) & c, sizeof c)) { 98567482Sbabkin device_printf(wp->dev, "version request failed\n"); 98667482Sbabkin wp->wdsr_free |= (1 << r->id); 98767482Sbabkin wp->dx->ombs[r->ombn].stat = 0; 98867482Sbabkin return (-1); 98967482Sbabkin } 99067482Sbabkin while (1) { 99167482Sbabkin i = 0; 99267482Sbabkin while ((inb(base + WDS_STAT) & WDS_IRQ) == 0) { 99367482Sbabkin DELAY(9000); 99467482Sbabkin if (++i == 100) { 99567482Sbabkin device_printf(wp->dev, "getvers timeout\n"); 99667482Sbabkin return (-1); 99767482Sbabkin } 99867482Sbabkin } 99967482Sbabkin wds_intr(wp); 100067482Sbabkin if (r->flags & WR_DONE) { 100167482Sbabkin device_printf(wp->dev, "firmware version %d.%02d\n", 100267482Sbabkin r->cmd.targ, r->cmd.scb[0]); 100367482Sbabkin wp->wdsr_free |= (1 << r->id); 100467482Sbabkin return (0); 100567482Sbabkin } 100667482Sbabkin } 100767482Sbabkin} 100867482Sbabkin 100967482Sbabkinstatic void 101067482Sbabkinwdsr_ccb_done(struct wds *wp, struct wds_req *r, 101167482Sbabkin union ccb *ccb, u_int32_t status) 101267482Sbabkin{ 101367482Sbabkin ccb->ccb_h.ccb_wdsr = 0; 101467482Sbabkin 101567482Sbabkin if (r != NULL) { 101667482Sbabkin /* To implement timeouts we would need to know how to abort the 101767482Sbabkin * command on controller, and this is a great mystery. 101867482Sbabkin * So for now we just pass the responsibility for timeouts 101967482Sbabkin * to the controlles itself, it does that reasonably good. 102067482Sbabkin */ 102167482Sbabkin /* untimeout(_timeout, (caddr_t) hcb, ccb->ccb_h.timeout_ch); */ 102267482Sbabkin /* we're about to free a hcb, so the shortage has ended */ 102367482Sbabkin frag_free(wp, r->mask); 102467482Sbabkin if (wp->want_wdsr && status != CAM_REQUEUE_REQ) { 102567482Sbabkin wp->want_wdsr = 0; 102667482Sbabkin status |= CAM_RELEASE_SIMQ; 102767482Sbabkin smallog('R'); 102867482Sbabkin } 102967482Sbabkin wp->wdsr_free |= (1 << r->id); 103067482Sbabkin } 103167482Sbabkin ccb->ccb_h.status = 103267482Sbabkin status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED)); 103367482Sbabkin xpt_done(ccb); 103467482Sbabkin} 103567482Sbabkin 103667482Sbabkinstatic void 103767482Sbabkinwds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio) 103867482Sbabkin{ 103967482Sbabkin int unit = cam_sim_unit(sim); 104067482Sbabkin struct wds *wp; 104167482Sbabkin struct ccb_hdr *ccb_h; 104267482Sbabkin struct wds_req *r; 104367482Sbabkin int base; 104467482Sbabkin u_int8_t c; 104567482Sbabkin int error; 104667482Sbabkin int n; 104767482Sbabkin 104867482Sbabkin wp = (struct wds *)cam_sim_softc(sim); 104967482Sbabkin ccb_h = &csio->ccb_h; 105067482Sbabkin 105167482Sbabkin DBG(DBX "wds%d: cmd TARG=%d LUN=%d\n", unit, ccb_h->target_id, 105267482Sbabkin ccb_h->target_lun); 105367482Sbabkin 105467482Sbabkin if (ccb_h->target_id > 7 || ccb_h->target_id == WDS_HBA_ID) { 105567482Sbabkin ccb_h->status = CAM_TID_INVALID; 105667482Sbabkin xpt_done((union ccb *) csio); 105767482Sbabkin return; 105867482Sbabkin } 105967482Sbabkin if (ccb_h->target_lun > 7) { 106067482Sbabkin ccb_h->status = CAM_LUN_INVALID; 106167482Sbabkin xpt_done((union ccb *) csio); 106267482Sbabkin return; 106367482Sbabkin } 106467482Sbabkin if (csio->dxfer_len > BUFSIZ) { 106567482Sbabkin ccb_h->status = CAM_REQ_TOO_BIG; 106667482Sbabkin xpt_done((union ccb *) csio); 106767482Sbabkin return; 106867482Sbabkin } 1069251874Sscottl if ((ccb_h->flags & CAM_DATA_MASK) != CAM_DATA_VADDR) { 107067482Sbabkin /* don't support these */ 107167482Sbabkin ccb_h->status = CAM_REQ_INVALID; 107267482Sbabkin xpt_done((union ccb *) csio); 107367482Sbabkin return; 107467482Sbabkin } 107567482Sbabkin base = wp->addr; 107667482Sbabkin 107767482Sbabkin /* 107867482Sbabkin * this check is mostly for debugging purposes, 107967482Sbabkin * "can't happen" normally. 108067482Sbabkin */ 108167482Sbabkin if(wp->want_wdsr) { 108267482Sbabkin DBG(DBX "wds%d: someone already waits for buffer\n", unit); 108367482Sbabkin smallog('b'); 108467482Sbabkin n = xpt_freeze_simq(sim, /* count */ 1); 108567482Sbabkin smallog('0'+n); 108667482Sbabkin ccb_h->status = CAM_REQUEUE_REQ; 108767482Sbabkin xpt_done((union ccb *) csio); 108867482Sbabkin return; 108967482Sbabkin } 109067482Sbabkin 109167482Sbabkin r = wdsr_alloc(wp); 109267482Sbabkin if (r == NULL) { 109367482Sbabkin device_printf(wp->dev, "no request slot available!\n"); 109467482Sbabkin wp->want_wdsr = 1; 109567482Sbabkin n = xpt_freeze_simq(sim, /* count */ 1); 109667482Sbabkin smallog2('f', '0'+n); 109767482Sbabkin ccb_h->status = CAM_REQUEUE_REQ; 109867482Sbabkin xpt_done((union ccb *) csio); 109967482Sbabkin return; 110067482Sbabkin } 110167482Sbabkin 110267482Sbabkin ccb_h->ccb_wdsr = (void *) r; 110367482Sbabkin r->ccb = (union ccb *) csio; 110467482Sbabkin 110567482Sbabkin switch (error = frag_alloc(wp, csio->dxfer_len, &r->buf, &r->mask)) { 110667482Sbabkin case CAM_REQ_CMP: 110767482Sbabkin break; 110867482Sbabkin case CAM_REQUEUE_REQ: 110967482Sbabkin DBG(DBX "wds%d: no data buffer available\n", unit); 111067482Sbabkin wp->want_wdsr = 1; 111167482Sbabkin n = xpt_freeze_simq(sim, /* count */ 1); 111267482Sbabkin smallog2('f', '0'+n); 111367482Sbabkin wdsr_ccb_done(wp, r, r->ccb, CAM_REQUEUE_REQ); 111467482Sbabkin return; 111567482Sbabkin default: 111667482Sbabkin DBG(DBX "wds%d: request is too big\n", unit); 111767482Sbabkin wdsr_ccb_done(wp, r, r->ccb, error); 111867482Sbabkin break; 111967482Sbabkin } 112067482Sbabkin 112167482Sbabkin ccb_h->status |= CAM_SIM_QUEUED; 112267482Sbabkin r->flags &= ~WR_DONE; 112367482Sbabkin 112467482Sbabkin scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr); 112567482Sbabkin 112667482Sbabkin bzero(&r->cmd, sizeof r->cmd); 112767482Sbabkin r->cmd.cmd = WDSX_SCSICMD; 112867482Sbabkin r->cmd.targ = (ccb_h->target_id << 5) | ccb_h->target_lun; 112967482Sbabkin 113067482Sbabkin if (ccb_h->flags & CAM_CDB_POINTER) 113167482Sbabkin bcopy(csio->cdb_io.cdb_ptr, &r->cmd.scb, 113267482Sbabkin csio->cdb_len < 12 ? csio->cdb_len : 12); 113367482Sbabkin else 113467482Sbabkin bcopy(csio->cdb_io.cdb_bytes, &r->cmd.scb, 113567482Sbabkin csio->cdb_len < 12 ? csio->cdb_len : 12); 113667482Sbabkin 113767482Sbabkin scsi_ulto3b(csio->dxfer_len, r->cmd.len); 113867482Sbabkin 113967482Sbabkin if (csio->dxfer_len > 0 114067482Sbabkin && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_OUT) { 114167482Sbabkin /* we already rejected physical or scattered addresses */ 114267482Sbabkin bcopy(csio->data_ptr, r->buf, csio->dxfer_len); 114367482Sbabkin } 114467482Sbabkin scsi_ulto3b(csio->dxfer_len ? WDSTOPHYS(wp, r->buf) : 0, r->cmd.data); 114567482Sbabkin 114667482Sbabkin if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) 114767482Sbabkin r->cmd.write = 0x80; 114867482Sbabkin else 114967482Sbabkin r->cmd.write = 0x00; 115067482Sbabkin 115167482Sbabkin scsi_ulto3b(0, r->cmd.next); 115267482Sbabkin 115367482Sbabkin outb(base + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN); 115467482Sbabkin 115567482Sbabkin c = WDSC_MSTART(r->ombn); 115667482Sbabkin 115767482Sbabkin if (wds_cmd(base, &c, sizeof c) != 0) { 115867482Sbabkin device_printf(wp->dev, "unable to start outgoing mbox\n"); 115967482Sbabkin wp->dx->ombs[r->ombn].stat = 0; 116067482Sbabkin wdsr_ccb_done(wp, r, r->ccb, CAM_RESRC_UNAVAIL); 116167482Sbabkin return; 116267482Sbabkin } 1163106592Sjhb DBG(DBX "wds%d: enqueued cmd 0x%x, r=%p\n", unit, 1164106592Sjhb r->cmd.scb[0] & 0xFF, r); 116567482Sbabkin 116667482Sbabkin smallog3('+', ccb_h->target_id + '0', ccb_h->target_lun + '0'); 116767482Sbabkin} 116867482Sbabkin 116967482Sbabkinstatic void 117067482Sbabkinwds_action(struct cam_sim * sim, union ccb * ccb) 117167482Sbabkin{ 117267482Sbabkin int unit = cam_sim_unit(sim); 117367482Sbabkin int s; 117467482Sbabkin 117567482Sbabkin DBG(DBX "wds%d: action 0x%x\n", unit, ccb->ccb_h.func_code); 117667482Sbabkin switch (ccb->ccb_h.func_code) { 117767482Sbabkin case XPT_SCSI_IO: 117867482Sbabkin s = splcam(); 117967482Sbabkin DBG(DBX "wds%d: SCSI IO entered\n", unit); 118067482Sbabkin wds_scsi_io(sim, &ccb->csio); 118167482Sbabkin DBG(DBX "wds%d: SCSI IO returned\n", unit); 118267482Sbabkin splx(s); 118367482Sbabkin break; 118467482Sbabkin case XPT_RESET_BUS: 118567482Sbabkin /* how to do it right ? */ 118667482Sbabkin printf("wds%d: reset\n", unit); 118767482Sbabkin ccb->ccb_h.status = CAM_REQ_CMP; 118867482Sbabkin xpt_done(ccb); 118967482Sbabkin break; 119067482Sbabkin case XPT_ABORT: 119167482Sbabkin ccb->ccb_h.status = CAM_UA_ABORT; 119267482Sbabkin xpt_done(ccb); 119367482Sbabkin break; 119467482Sbabkin case XPT_CALC_GEOMETRY: 119567482Sbabkin { 119667482Sbabkin struct ccb_calc_geometry *ccg; 119767482Sbabkin u_int32_t size_mb; 119867482Sbabkin u_int32_t secs_per_cylinder; 119967482Sbabkin 120067482Sbabkin ccg = &ccb->ccg; 120167482Sbabkin size_mb = ccg->volume_size 120267482Sbabkin / ((1024L * 1024L) / ccg->block_size); 120367482Sbabkin 120467482Sbabkin ccg->heads = 64; 120567482Sbabkin ccg->secs_per_track = 16; 120667482Sbabkin secs_per_cylinder = ccg->heads * ccg->secs_per_track; 120767482Sbabkin ccg->cylinders = ccg->volume_size / secs_per_cylinder; 120867482Sbabkin ccb->ccb_h.status = CAM_REQ_CMP; 120967482Sbabkin xpt_done(ccb); 121067482Sbabkin break; 121167482Sbabkin } 121267482Sbabkin case XPT_PATH_INQ: /* Path routing inquiry */ 121367482Sbabkin { 121467482Sbabkin struct ccb_pathinq *cpi = &ccb->cpi; 121567482Sbabkin 121667482Sbabkin cpi->version_num = 1; /* XXX??? */ 121767482Sbabkin cpi->hba_inquiry = 0; /* nothing fancy */ 121867482Sbabkin cpi->target_sprt = 0; 121967482Sbabkin cpi->hba_misc = 0; 122067482Sbabkin cpi->hba_eng_cnt = 0; 122167482Sbabkin cpi->max_target = 7; 122267482Sbabkin cpi->max_lun = 7; 122367482Sbabkin cpi->initiator_id = WDS_HBA_ID; 122467482Sbabkin cpi->hba_misc = 0; 122567482Sbabkin cpi->bus_id = cam_sim_bus(sim); 122667482Sbabkin cpi->base_transfer_speed = 3300; 122767482Sbabkin strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 122867482Sbabkin strncpy(cpi->hba_vid, "WD/FDC", HBA_IDLEN); 122967482Sbabkin strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 123067482Sbabkin cpi->unit_number = cam_sim_unit(sim); 123167482Sbabkin cpi->ccb_h.status = CAM_REQ_CMP; 123267482Sbabkin xpt_done(ccb); 123367482Sbabkin break; 123467482Sbabkin } 123567482Sbabkin default: 123667482Sbabkin ccb->ccb_h.status = CAM_REQ_INVALID; 123767482Sbabkin xpt_done(ccb); 123867482Sbabkin break; 123967482Sbabkin } 124067482Sbabkin} 124167482Sbabkin 124267482Sbabkinstatic void 124367482Sbabkinwds_poll(struct cam_sim * sim) 124467482Sbabkin{ 124567482Sbabkin wds_intr((struct wds *)cam_sim_softc(sim)); 124667482Sbabkin} 124767482Sbabkin 124867482Sbabkin/* part of initialization done in probe() */ 124967482Sbabkin/* returns 0 if OK, ENXIO if bad */ 125067482Sbabkin 125167482Sbabkinstatic int 125267482Sbabkinwds_preinit(struct wds *wp) 125367482Sbabkin{ 125467482Sbabkin int base; 125567482Sbabkin int i; 125667482Sbabkin 125767482Sbabkin base = wp->addr; 125867482Sbabkin 125967482Sbabkin /* 126067482Sbabkin * Sending a command causes the CMDRDY bit to clear. 126167482Sbabkin */ 126267482Sbabkin outb(base + WDS_CMD, WDSC_NOOP); 126367482Sbabkin if (inb(base + WDS_STAT) & WDS_RDY) 126467482Sbabkin return (ENXIO); 126567482Sbabkin 126667482Sbabkin /* 126767482Sbabkin * the controller exists. reset and init. 126867482Sbabkin */ 126967482Sbabkin outb(base + WDS_HCR, WDSH_ASCRESET | WDSH_SCSIRESET); 127067482Sbabkin DELAY(30); 127167482Sbabkin outb(base + WDS_HCR, 0); 127267482Sbabkin 127367482Sbabkin if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) { 127467482Sbabkin for (i = 0; i < 10; i++) { 127567482Sbabkin if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY) 127667482Sbabkin break; 127767482Sbabkin DELAY(40000); 127867482Sbabkin } 127967482Sbabkin if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) 128067482Sbabkin /* probe timeout */ 128167482Sbabkin return (ENXIO); 128267482Sbabkin } 128367482Sbabkin 128467482Sbabkin return (0); 128567482Sbabkin} 128667482Sbabkin 128767482Sbabkin/* part of initialization done in attach() */ 128867482Sbabkin/* returns 0 if OK, 1 if bad */ 128967482Sbabkin 129067482Sbabkinstatic int 129167482Sbabkinwds_init(struct wds *wp) 129267482Sbabkin{ 129367482Sbabkin struct wds_setup init; 129467482Sbabkin int base; 129567482Sbabkin int i; 129667482Sbabkin struct wds_cmd wc; 129767482Sbabkin 129867482Sbabkin base = wp->addr; 129967482Sbabkin 130067482Sbabkin outb(base + WDS_HCR, WDSH_DRQEN); 130167482Sbabkin 130267482Sbabkin isa_dmacascade(wp->drq); 130367482Sbabkin 130467482Sbabkin if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) { 130567482Sbabkin for (i = 0; i < 10; i++) { 130667482Sbabkin if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY) 130767482Sbabkin break; 130867482Sbabkin DELAY(40000); 130967482Sbabkin } 131067482Sbabkin if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) 131167482Sbabkin /* probe timeout */ 131267482Sbabkin return (1); 131367482Sbabkin } 131467482Sbabkin bzero(&init, sizeof init); 131567482Sbabkin init.cmd = WDSC_INIT; 131667482Sbabkin init.scsi_id = WDS_HBA_ID; 131767482Sbabkin init.buson_t = 24; 131867482Sbabkin init.busoff_t = 48; 131967482Sbabkin scsi_ulto3b(WDSTOPHYS(wp, &wp->dx->ombs), init.mbaddr); 132067482Sbabkin init.xx = 0; 132167482Sbabkin init.nomb = WDS_NOMB; 132267482Sbabkin init.nimb = WDS_NIMB; 132367482Sbabkin 132467482Sbabkin wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY); 132567482Sbabkin if (wds_cmd(base, (u_int8_t *) & init, sizeof init) != 0) { 132667482Sbabkin device_printf(wp->dev, "wds_cmd init failed\n"); 132767482Sbabkin return (1); 132867482Sbabkin } 132967482Sbabkin wds_wait(base + WDS_STAT, WDS_INIT, WDS_INIT); 133067482Sbabkin 133167482Sbabkin wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY); 133267482Sbabkin 133367482Sbabkin bzero(&wc, sizeof wc); 133467482Sbabkin wc.cmd = WDSC_DISUNSOL; 133567482Sbabkin if (wds_cmd(base, (char *) &wc, sizeof wc) != 0) { 133667482Sbabkin device_printf(wp->dev, "wds_cmd init2 failed\n"); 133767482Sbabkin return (1); 133867482Sbabkin } 133967482Sbabkin return (0); 134067482Sbabkin} 134167482Sbabkin 134267482Sbabkinstatic int 134367482Sbabkinwds_cmd(int base, u_int8_t * p, int l) 134467482Sbabkin{ 134567482Sbabkin int s = splcam(); 134667482Sbabkin 134767482Sbabkin while (l--) { 134867482Sbabkin do { 134967482Sbabkin outb(base + WDS_CMD, *p); 135067482Sbabkin wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY); 135167482Sbabkin } while (inb(base + WDS_STAT) & WDS_REJ); 135267482Sbabkin p++; 135367482Sbabkin } 135467482Sbabkin 135567482Sbabkin wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY); 135667482Sbabkin 135767482Sbabkin splx(s); 135867482Sbabkin 135967482Sbabkin return (0); 136067482Sbabkin} 136167482Sbabkin 136267482Sbabkinstatic void 136367482Sbabkinwds_wait(int reg, int mask, int val) 136467482Sbabkin{ 136567482Sbabkin while ((inb(reg) & mask) != val) 136667482Sbabkin ; 136767482Sbabkin} 136867482Sbabkin 136967482Sbabkinstatic struct wds_req * 137067482Sbabkincmdtovirt(struct wds *wp, u_int32_t phys) 137167482Sbabkin{ 137267482Sbabkin char *a; 137367482Sbabkin 1374106592Sjhb a = WDSTOVIRT(wp, (uintptr_t)phys); 137567482Sbabkin if( a < (char *)&wp->dx->req[0] || a>= (char *)&wp->dx->req[MAXSIMUL]) { 137667482Sbabkin device_printf(wp->dev, "weird phys address 0x%x\n", phys); 137767482Sbabkin return (NULL); 137867482Sbabkin } 137967482Sbabkin a -= (int)offsetof(struct wds_req, cmd); /* convert cmd to request */ 138067482Sbabkin return ((struct wds_req *)a); 138167482Sbabkin} 138267482Sbabkin 138367482Sbabkin/* for debugging, print out all the data about the status of devices */ 138467482Sbabkinvoid 138567482Sbabkinwds_print(void) 138667482Sbabkin{ 138767482Sbabkin int unit; 138867482Sbabkin int i; 138967482Sbabkin struct wds_req *r; 139067482Sbabkin struct wds *wp; 139167482Sbabkin 139267482Sbabkin for (unit = 0; unit < devclass_get_maxunit(wds_devclass); unit++) { 139367482Sbabkin wp = (struct wds *) devclass_get_device(wds_devclass, unit); 139467482Sbabkin if (wp == NULL) 139567482Sbabkin continue; 139667482Sbabkin printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n", 139767482Sbabkin unit, wp->want_wdsr, inb(wp->addr + WDS_STAT) & 0xff, 139867482Sbabkin (inb(wp->addr + WDS_STAT) & WDS_IRQ) ? "ready" : "no", 139967482Sbabkin inb(wp->addr + WDS_IRQSTAT) & 0xff); 140067482Sbabkin for (i = 0; i < MAXSIMUL; i++) { 140167482Sbabkin r = &wp->dx->req[i]; 140267482Sbabkin if( wp->wdsr_free & (1 << r->id) ) { 140367482Sbabkin printf("req=%d flg=0x%x ombn=%d ombstat=%d " 140467482Sbabkin "mask=0x%x targ=%d lun=%d cmd=0x%x\n", 140567482Sbabkin i, r->flags, r->ombn, 140667482Sbabkin wp->dx->ombs[r->ombn].stat, 140767482Sbabkin r->mask, r->cmd.targ >> 5, 140867482Sbabkin r->cmd.targ & 7, r->cmd.scb[0]); 140967482Sbabkin } 141067482Sbabkin } 141167482Sbabkin } 141267482Sbabkin} 141367482Sbabkin 141467482Sbabkin#if WDS_DEBUG == 2 141567482Sbabkin/* create circular log buffer */ 141667482Sbabkinstatic char * 141767482Sbabkinwds_nextlog(void) 141867482Sbabkin{ 141967482Sbabkin int n = logwrite; 142067482Sbabkin 142167482Sbabkin if (++logwrite >= NLOGLINES) 142267482Sbabkin logwrite = 0; 142367482Sbabkin if (logread == logwrite) 142467482Sbabkin if (++logread >= NLOGLINES) 142567482Sbabkin logread = 0; 142667482Sbabkin return (wds_log[n]); 142767482Sbabkin} 142867482Sbabkin 142967482Sbabkinvoid 143067482Sbabkinwds_printlog(void) 143167482Sbabkin{ 143267482Sbabkin /* print the circular buffer */ 143367482Sbabkin int i; 143467482Sbabkin 143567482Sbabkin for (i = logread; i != logwrite;) { 143667482Sbabkin printf("%s", wds_log[i]); 143767482Sbabkin if (i == NLOGLINES) 143867482Sbabkin i = 0; 143967482Sbabkin else 144067482Sbabkin i++; 144167482Sbabkin } 144267482Sbabkin} 144367482Sbabkin#endif /* WDS_DEBUG */ 1444