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