1 /* $NetBSD: isp_netbsd.c,v 1.8 1998/12/28 19:10:43 mjacob Exp $ */ 2 /* release_12_28_98_A */ 3 /* 4 * Platform (NetBSD) dependent common attachment code for Qlogic adapters. 5 * 6 *--------------------------------------- 7 * Copyright (c) 1997, 1998 by Matthew Jacob 8 * NASA/Ames Research Center 9 * All rights reserved. 10 *--------------------------------------- 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice immediately at the beginning of the file, without modification, 17 * this list of conditions, and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. The name of the author may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * The author may be reached via electronic communications at 37 * 38 * mjacob@nas.nasa.gov 39 * mjacob@feral.com 40 * 41 * or, via United States Postal Address 42 * 43 * Matthew Jacob 44 * Feral Software 45 * 2339 3rd Street 46 * Suite 24 47 * San Francisco, CA, 94107 48 */ 49 50 #include <dev/ic/isp_netbsd.h> 51 52 static void ispminphys __P((struct buf *)); 53 static int32_t ispcmd __P((ISP_SCSI_XFER_T *)); 54 55 static struct scsipi_device isp_dev = { NULL, NULL, NULL, NULL }; 56 static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int)); 57 static void isp_watch __P ((void *)); 58 59 /* 60 * Complete attachment of hardware, include subdevices. 61 */ 62 void 63 isp_attach(isp) 64 struct ispsoftc *isp; 65 { 66 67 isp->isp_osinfo._adapter.scsipi_cmd = ispcmd; 68 isp->isp_osinfo._adapter.scsipi_minphys = ispminphys; 69 70 isp->isp_state = ISP_RUNSTATE; 71 isp->isp_osinfo._link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; 72 isp->isp_osinfo._link.adapter_softc = isp; 73 isp->isp_osinfo._link.device = &isp_dev; 74 isp->isp_osinfo._link.adapter = &isp->isp_osinfo._adapter; 75 76 if (isp->isp_type & ISP_HA_FC) { 77 isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_FC_TARG-1; 78 #ifdef SCCLUN 79 /* 80 * 16 bits worth, but let's be reasonable.. 81 */ 82 isp->isp_osinfo._link.scsipi_scsi.max_lun = 255; 83 #else 84 isp->isp_osinfo._link.scsipi_scsi.max_lun = 15; 85 #endif 86 isp->isp_osinfo._link.openings = 87 RQUEST_QUEUE_LEN / (MAX_FC_TARG-1); 88 isp->isp_osinfo._link.scsipi_scsi.adapter_target = 89 ((fcparam *)isp->isp_param)->isp_loopid; 90 } else { 91 isp->isp_osinfo._link.openings = 92 RQUEST_QUEUE_LEN / (MAX_TARGETS-1); 93 isp->isp_osinfo._link.scsipi_scsi.max_target = MAX_TARGETS-1; 94 if (isp->isp_bustype == ISP_BT_SBUS) { 95 isp->isp_osinfo._link.scsipi_scsi.max_lun = 7; 96 } else { 97 /* 98 * Too much target breakage at present. 99 */ 100 #if 0 101 if (isp->isp_fwrev >= ISP_FW_REV(7,55)) 102 isp->isp_osinfo._link.scsipi_scsi.max_lun = 31; 103 else 104 #endif 105 isp->isp_osinfo._link.scsipi_scsi.max_lun = 7; 106 } 107 isp->isp_osinfo._link.scsipi_scsi.adapter_target = 108 ((sdparam *)isp->isp_param)->isp_initiator_id; 109 } 110 if (isp->isp_osinfo._link.openings < 2) 111 isp->isp_osinfo._link.openings = 2; 112 isp->isp_osinfo._link.type = BUS_SCSI; 113 114 /* 115 * Start the watchdog. 116 */ 117 isp->isp_dogactive = 1; 118 timeout(isp_watch, isp, 30 * hz); 119 120 /* 121 * And attach children (if any). 122 */ 123 config_found((void *)isp, &isp->isp_osinfo._link, scsiprint); 124 } 125 126 /* 127 * minphys our xfers 128 * 129 * Unfortunately, the buffer pointer describes the target device- not the 130 * adapter device, so we can't use the pointer to find out what kind of 131 * adapter we are and adjust accordingly. 132 */ 133 134 static void 135 ispminphys(bp) 136 struct buf *bp; 137 { 138 /* 139 * XX: Only the 1020 has a 24 bit limit. 140 */ 141 if (bp->b_bcount >= (1 << 24)) { 142 bp->b_bcount = (1 << 24); 143 } 144 minphys(bp); 145 } 146 147 static int 148 ispcmd(xs) 149 ISP_SCSI_XFER_T *xs; 150 { 151 struct ispsoftc *isp; 152 int result; 153 ISP_LOCKVAL_DECL; 154 155 isp = XS_ISP(xs); 156 ISP_LOCK(isp); 157 /* 158 * This is less efficient than I would like in that the 159 * majority of cases will have to do some pointer deferences 160 * to find out that things don't need to be updated. 161 */ 162 if ((xs->flags & SCSI_AUTOCONF) == 0 && (isp->isp_type & ISP_HA_SCSI)) { 163 sdparam *sdp = isp->isp_param; 164 if (sdp->isp_devparam[XS_TGT(xs)].dev_flags != 165 sdp->isp_devparam[XS_TGT(xs)].cur_dflags) { 166 u_int16_t f = DPARM_WIDE|DPARM_SYNC|DPARM_TQING; 167 if (xs->sc_link->quirks & SDEV_NOSYNC) 168 f &= ~DPARM_SYNC; 169 if (xs->sc_link->quirks & SDEV_NOWIDE) 170 f &= ~DPARM_WIDE; 171 if (xs->sc_link->quirks & SDEV_NOTAG) 172 f &= ~DPARM_TQING; 173 sdp->isp_devparam[XS_TGT(xs)].dev_flags &= 174 ~(DPARM_WIDE|DPARM_SYNC|DPARM_TQING); 175 sdp->isp_devparam[XS_TGT(xs)].dev_flags |= f; 176 sdp->isp_devparam[XS_TGT(xs)].dev_update = 1; 177 isp->isp_update = 1; 178 } 179 } 180 DISABLE_INTS(isp); 181 result = ispscsicmd(xs); 182 ENABLE_INTS(isp); 183 if (result != CMD_QUEUED || (xs->flags & SCSI_POLL) == 0) { 184 ISP_UNLOCK(isp); 185 return (result); 186 } 187 188 /* 189 * If we can't use interrupts, poll on completion. 190 */ 191 if (isp_poll(isp, xs, XS_TIME(xs))) { 192 /* 193 * If no other error occurred but we didn't finish, 194 * something bad happened. 195 */ 196 if (XS_IS_CMD_DONE(xs) == 0) { 197 isp->isp_nactive--; 198 if (isp->isp_nactive < 0) 199 isp->isp_nactive = 0; 200 if (XS_NOERR(xs)) { 201 isp_lostcmd(isp, xs); 202 XS_SETERR(xs, HBA_BOTCH); 203 } 204 } 205 } 206 ISP_UNLOCK(isp); 207 return (CMD_COMPLETE); 208 } 209 210 static int 211 isp_poll(isp, xs, mswait) 212 struct ispsoftc *isp; 213 ISP_SCSI_XFER_T *xs; 214 int mswait; 215 { 216 217 while (mswait) { 218 /* Try the interrupt handling routine */ 219 (void)isp_intr((void *)isp); 220 221 /* See if the xs is now done */ 222 if (XS_IS_CMD_DONE(xs)) { 223 return (0); 224 } 225 SYS_DELAY(1000); /* wait one millisecond */ 226 mswait--; 227 } 228 return (1); 229 } 230 231 static void 232 isp_watch(arg) 233 void *arg; 234 { 235 int i; 236 struct ispsoftc *isp = arg; 237 ISP_SCSI_XFER_T *xs; 238 ISP_ILOCKVAL_DECL; 239 240 /* 241 * Look for completely dead commands (but not polled ones). 242 */ 243 ISP_ILOCK(isp); 244 for (i = 0; i < RQUEST_QUEUE_LEN; i++) { 245 if ((xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]) == NULL) { 246 continue; 247 } 248 if (XS_TIME(xs) == 0) { 249 continue; 250 } 251 XS_TIME(xs) -= (WATCH_INTERVAL * 1000); 252 /* 253 * Avoid later thinking that this 254 * transaction is not being timed. 255 * Then give ourselves to watchdog 256 * periods of grace. 257 */ 258 if (XS_TIME(xs) == 0) { 259 XS_TIME(xs) = 1; 260 } else if (XS_TIME(xs) > -(2 * WATCH_INTERVAL * 1000)) { 261 continue; 262 } 263 if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) { 264 printf("%s: isp_watch failed to abort command\n", 265 isp->isp_name); 266 isp_restart(isp); 267 break; 268 } 269 } 270 timeout(isp_watch, isp, WATCH_INTERVAL * hz); 271 isp->isp_dogactive = 1; 272 ISP_IUNLOCK(isp); 273 } 274 275 /* 276 * Free any associated resources prior to decommissioning and 277 * set the card to a known state (so it doesn't wake up and kick 278 * us when we aren't expecting it to). 279 * 280 * Locks are held before coming here. 281 */ 282 void 283 isp_uninit(isp) 284 struct ispsoftc *isp; 285 { 286 ISP_ILOCKVAL_DECL; 287 ISP_ILOCK(isp); 288 /* 289 * Leave with interrupts disabled. 290 */ 291 DISABLE_INTS(isp); 292 293 /* 294 * Turn off the watchdog (if active). 295 */ 296 if (isp->isp_dogactive) { 297 untimeout(isp_watch, isp); 298 isp->isp_dogactive = 0; 299 } 300 301 ISP_IUNLOCK(isp); 302 } 303