1 /* $OpenBSD: uha.c,v 1.30 2020/02/15 18:02:00 krw Exp $ */ 2 /* $NetBSD: uha.c,v 1.3 1996/10/13 01:37:29 christos Exp $ */ 3 4 #undef UHADEBUG 5 6 /* 7 * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Charles M. Hannum. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu) 37 * Slight fixes to timeouts to run with the 34F 38 * Thanks to Julian Elischer for advice and help with this port. 39 * 40 * Originally written by Julian Elischer (julian@tfs.com) 41 * for TRW Financial Systems for use under the MACH(2.5) operating system. 42 * 43 * TRW Financial Systems, in accordance with their agreement with Carnegie 44 * Mellon University, makes this software available to CMU to distribute 45 * or use in any manner that they see fit as long as this message is kept with 46 * the software. For this reason TFS also grants any other persons or 47 * organisations permission to use or modify this software. 48 * 49 * TFS supplies this software to be publicly redistributed 50 * on the understanding that TFS is not responsible for the correct 51 * functioning of this software in any circumstances. 52 * 53 * commenced: Sun Sep 27 18:14:01 PDT 1992 54 * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993 55 */ 56 57 #include <sys/param.h> 58 #include <sys/systm.h> 59 #include <sys/kernel.h> 60 #include <sys/errno.h> 61 #include <sys/ioctl.h> 62 #include <sys/device.h> 63 #include <sys/malloc.h> 64 #include <sys/buf.h> 65 #include <uvm/uvm_extern.h> 66 67 #include <machine/bus.h> 68 #include <machine/intr.h> 69 70 #include <scsi/scsi_all.h> 71 #include <scsi/scsiconf.h> 72 73 #include <dev/ic/uhareg.h> 74 #include <dev/ic/uhavar.h> 75 76 #define KVTOPHYS(x) vtophys((vaddr_t)x) 77 78 void uha_reset_mscp(struct uha_softc *, struct uha_mscp *); 79 void uha_mscp_free(void *, void *); 80 void *uha_mscp_alloc(void *); 81 void uha_scsi_cmd(struct scsi_xfer *); 82 83 struct scsi_adapter uha_switch = { 84 uha_scsi_cmd, NULL, NULL, NULL, NULL 85 }; 86 87 struct cfdriver uha_cd = { 88 NULL, "uha", DV_DULL 89 }; 90 91 #define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ 92 93 #ifdef __OpenBSD__ 94 int uhaprint(void *, const char *); 95 96 int 97 uhaprint(aux, name) 98 void *aux; 99 const char *name; 100 { 101 102 if (name != NULL) 103 printf("%s: scsibus ", name); 104 return UNCONF; 105 } 106 #endif 107 108 /* 109 * Attach all the sub-devices we can find 110 */ 111 void 112 uha_attach(sc) 113 struct uha_softc *sc; 114 { 115 struct scsibus_attach_args saa; 116 117 (sc->init)(sc); 118 SLIST_INIT(&sc->sc_free_mscp); 119 120 mtx_init(&sc->sc_mscp_mtx, IPL_BIO); 121 scsi_iopool_init(&sc->sc_iopool, sc, uha_mscp_alloc, uha_mscp_free); 122 123 /* 124 * fill in the prototype scsi_link. 125 */ 126 sc->sc_link.adapter_softc = sc; 127 sc->sc_link.adapter_target = sc->sc_scsi_dev; 128 sc->sc_link.adapter = &uha_switch; 129 sc->sc_link.openings = 2; 130 sc->sc_link.pool = &sc->sc_iopool; 131 132 bzero(&saa, sizeof(saa)); 133 saa.saa_sc_link = &sc->sc_link; 134 135 /* 136 * ask the adapter what subunits are present 137 */ 138 config_found(&sc->sc_dev, &saa, uhaprint); 139 } 140 141 void 142 uha_reset_mscp(sc, mscp) 143 struct uha_softc *sc; 144 struct uha_mscp *mscp; 145 { 146 147 mscp->flags = 0; 148 } 149 150 /* 151 * A mscp (and hence a mbx-out) is put onto the free list. 152 */ 153 void 154 uha_mscp_free(xsc, xmscp) 155 void *xsc, *xmscp; 156 { 157 struct uha_softc *sc = xsc; 158 struct uha_mscp *mscp = xmscp; 159 160 uha_reset_mscp(sc, mscp); 161 162 mtx_enter(&sc->sc_mscp_mtx); 163 SLIST_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain); 164 mtx_leave(&sc->sc_mscp_mtx); 165 } 166 167 /* 168 * Get a free mscp 169 */ 170 void * 171 uha_mscp_alloc(xsc) 172 void *xsc; 173 { 174 struct uha_softc *sc = xsc; 175 struct uha_mscp *mscp; 176 177 mtx_enter(&sc->sc_mscp_mtx); 178 mscp = SLIST_FIRST(&sc->sc_free_mscp); 179 if (mscp) { 180 SLIST_REMOVE_HEAD(&sc->sc_free_mscp, chain); 181 mscp->flags |= MSCP_ALLOC; 182 } 183 mtx_leave(&sc->sc_mscp_mtx); 184 185 return (mscp); 186 } 187 188 /* 189 * given a physical address, find the mscp that it corresponds to. 190 */ 191 struct uha_mscp * 192 uha_mscp_phys_kv(sc, mscp_phys) 193 struct uha_softc *sc; 194 u_long mscp_phys; 195 { 196 int hashnum = MSCP_HASH(mscp_phys); 197 struct uha_mscp *mscp = sc->sc_mscphash[hashnum]; 198 199 while (mscp) { 200 if (mscp->hashkey == mscp_phys) 201 break; 202 mscp = mscp->nexthash; 203 } 204 return (mscp); 205 } 206 207 /* 208 * We have a mscp which has been processed by the adaptor, now we look to see 209 * how the operation went. 210 */ 211 void 212 uha_done(sc, mscp) 213 struct uha_softc *sc; 214 struct uha_mscp *mscp; 215 { 216 struct scsi_sense_data *s1, *s2; 217 struct scsi_xfer *xs = mscp->xs; 218 219 SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); 220 /* 221 * Otherwise, put the results of the operation 222 * into the xfer and call whoever started it 223 */ 224 if ((mscp->flags & MSCP_ALLOC) == 0) { 225 panic("%s: exiting ccb not allocated!", sc->sc_dev.dv_xname); 226 return; 227 } 228 if (xs->error == XS_NOERROR) { 229 if (mscp->host_stat != UHA_NO_ERR) { 230 switch (mscp->host_stat) { 231 case UHA_SBUS_TIMEOUT: /* No response */ 232 xs->error = XS_SELTIMEOUT; 233 break; 234 default: /* Other scsi protocol messes */ 235 printf("%s: host_stat %x\n", 236 sc->sc_dev.dv_xname, mscp->host_stat); 237 xs->error = XS_DRIVER_STUFFUP; 238 } 239 } else if (mscp->target_stat != SCSI_OK) { 240 switch (mscp->target_stat) { 241 case SCSI_CHECK: 242 s1 = &mscp->mscp_sense; 243 s2 = &xs->sense; 244 *s2 = *s1; 245 xs->error = XS_SENSE; 246 break; 247 case SCSI_BUSY: 248 xs->error = XS_BUSY; 249 break; 250 default: 251 printf("%s: target_stat %x\n", 252 sc->sc_dev.dv_xname, mscp->target_stat); 253 xs->error = XS_DRIVER_STUFFUP; 254 } 255 } else 256 xs->resid = 0; 257 } 258 259 scsi_done(xs); 260 } 261 262 /* 263 * start a scsi operation given the command and the data address. Also 264 * needs the unit, target and lu. 265 */ 266 void 267 uha_scsi_cmd(xs) 268 struct scsi_xfer *xs; 269 { 270 struct scsi_link *sc_link = xs->sc_link; 271 struct uha_softc *sc = sc_link->adapter_softc; 272 struct uha_mscp *mscp; 273 struct uha_dma_seg *sg; 274 int seg; /* scatter gather seg being worked on */ 275 u_long thiskv, thisphys, nextphys; 276 int bytes_this_seg, bytes_this_page, datalen, flags; 277 int s; 278 279 SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); 280 /* 281 * get a mscp (mbox-out) to use. If the transfer 282 * is from a buf (possibly from interrupt time) 283 * then we can't allow it to sleep 284 */ 285 flags = xs->flags; 286 mscp = xs->io; 287 288 mscp->xs = xs; 289 mscp->timeout = xs->timeout; 290 timeout_set(&xs->stimeout, uha_timeout, xs); 291 292 /* 293 * Put all the arguments for the xfer in the mscp 294 */ 295 if (flags & SCSI_RESET) { 296 mscp->opcode = UHA_SDR; 297 mscp->ca = 0x01; 298 } else { 299 mscp->opcode = UHA_TSP; 300 /* XXX Not for tapes. */ 301 mscp->ca = 0x01; 302 bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length); 303 } 304 mscp->xdir = UHA_SDET; 305 mscp->dcn = 0x00; 306 mscp->chan = 0x00; 307 mscp->target = sc_link->target; 308 mscp->lun = sc_link->lun; 309 mscp->scsi_cmd_length = xs->cmdlen; 310 mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense); 311 mscp->req_sense_length = sizeof(mscp->mscp_sense); 312 mscp->host_stat = 0x00; 313 mscp->target_stat = 0x00; 314 315 if (xs->datalen) { 316 sg = mscp->uha_dma; 317 seg = 0; 318 319 /* 320 * Set up the scatter gather block 321 */ 322 SC_DEBUG(sc_link, SDEV_DB4, 323 ("%d @0x%x:- ", xs->datalen, xs->data)); 324 datalen = xs->datalen; 325 thiskv = (int) xs->data; 326 thisphys = KVTOPHYS(thiskv); 327 328 while (datalen && seg < UHA_NSEG) { 329 bytes_this_seg = 0; 330 331 /* put in the base address */ 332 sg->seg_addr = thisphys; 333 334 SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys)); 335 336 /* do it at least once */ 337 nextphys = thisphys; 338 while (datalen && thisphys == nextphys) { 339 /* 340 * This page is contiguous (physically) 341 * with the last, just extend the 342 * length 343 */ 344 /* how far to the end of the page */ 345 nextphys = (thisphys & ~PGOFSET) + NBPG; 346 bytes_this_page = nextphys - thisphys; 347 /**** or the data ****/ 348 bytes_this_page = min(bytes_this_page, 349 datalen); 350 bytes_this_seg += bytes_this_page; 351 datalen -= bytes_this_page; 352 353 /* get more ready for the next page */ 354 thiskv = (thiskv & ~PGOFSET) + NBPG; 355 if (datalen) 356 thisphys = KVTOPHYS(thiskv); 357 } 358 /* 359 * next page isn't contiguous, finish the seg 360 */ 361 SC_DEBUGN(sc_link, SDEV_DB4, 362 ("(0x%x)", bytes_this_seg)); 363 sg->seg_len = bytes_this_seg; 364 sg++; 365 seg++; 366 } 367 368 SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); 369 if (datalen) { 370 /* 371 * there's still data, must have run out of segs! 372 */ 373 printf("%s: uha_scsi_cmd, more than %d dma segs\n", 374 sc->sc_dev.dv_xname, UHA_NSEG); 375 goto bad; 376 } 377 mscp->data_addr = KVTOPHYS(mscp->uha_dma); 378 mscp->data_length = xs->datalen; 379 mscp->sgth = 0x01; 380 mscp->sg_num = seg; 381 } else { /* No data xfer, use non S/G values */ 382 mscp->data_addr = (physaddr)0; 383 mscp->data_length = 0; 384 mscp->sgth = 0x00; 385 mscp->sg_num = 0; 386 } 387 mscp->link_id = 0; 388 mscp->link_addr = (physaddr)0; 389 390 s = splbio(); 391 (sc->start_mbox)(sc, mscp); 392 splx(s); 393 394 /* 395 * Usually return SUCCESSFULLY QUEUED 396 */ 397 if ((flags & SCSI_POLL) == 0) 398 return; 399 400 /* 401 * If we can't use interrupts, poll on completion 402 */ 403 if ((sc->poll)(sc, xs, mscp->timeout)) { 404 uha_timeout(mscp); 405 if ((sc->poll)(sc, xs, mscp->timeout)) 406 uha_timeout(mscp); 407 } 408 return; 409 410 bad: 411 xs->error = XS_DRIVER_STUFFUP; 412 scsi_done(xs); 413 return; 414 } 415 416 void 417 uha_timeout(arg) 418 void *arg; 419 { 420 struct uha_mscp *mscp = arg; 421 struct scsi_xfer *xs = mscp->xs; 422 struct scsi_link *sc_link = xs->sc_link; 423 struct uha_softc *sc = sc_link->adapter_softc; 424 int s; 425 426 sc_print_addr(sc_link); 427 printf("timed out"); 428 429 s = splbio(); 430 431 if (mscp->flags & MSCP_ABORT) { 432 /* abort timed out */ 433 printf(" AGAIN\n"); 434 /* XXX Must reset! */ 435 } else { 436 /* abort the operation that has timed out */ 437 printf("\n"); 438 mscp->xs->error = XS_TIMEOUT; 439 mscp->timeout = UHA_ABORT_TIMEOUT; 440 mscp->flags |= MSCP_ABORT; 441 (sc->start_mbox)(sc, mscp); 442 } 443 444 splx(s); 445 } 446