1 /* $OpenBSD: uha.c,v 1.12 2009/02/16 21:19:07 miod 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 <sys/proc.h> 72 #include <sys/user.h> 73 74 #include <machine/bus.h> 75 #include <machine/intr.h> 76 77 #include <scsi/scsi_all.h> 78 #include <scsi/scsiconf.h> 79 80 #include <dev/ic/uhareg.h> 81 #include <dev/ic/uhavar.h> 82 83 #ifndef DDB 84 #define Debugger() panic("should call debugger here (ultra14f.c)") 85 #endif /* ! DDB */ 86 87 #define KVTOPHYS(x) vtophys((vaddr_t)x) 88 89 integrate void uha_reset_mscp(struct uha_softc *, struct uha_mscp *); 90 void uha_free_mscp(struct uha_softc *, struct uha_mscp *); 91 integrate void uha_init_mscp(struct uha_softc *, struct uha_mscp *); 92 struct uha_mscp *uha_get_mscp(struct uha_softc *, int); 93 void uhaminphys(struct buf *, struct scsi_link *); 94 int uha_scsi_cmd(struct scsi_xfer *); 95 96 struct scsi_adapter uha_switch = { 97 uha_scsi_cmd, 98 uhaminphys, 99 0, 100 0, 101 }; 102 103 /* the below structure is so we have a default dev struct for out link struct */ 104 struct scsi_device uha_dev = { 105 NULL, /* Use default error handler */ 106 NULL, /* have a queue, served by this */ 107 NULL, /* have no async handler */ 108 NULL, /* Use default 'done' routine */ 109 }; 110 111 struct cfdriver uha_cd = { 112 NULL, "uha", DV_DULL 113 }; 114 115 #define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */ 116 117 #ifdef __OpenBSD__ 118 int uhaprint(void *, const char *); 119 120 int 121 uhaprint(aux, name) 122 void *aux; 123 const char *name; 124 { 125 126 if (name != NULL) 127 printf("%s: scsibus ", name); 128 return UNCONF; 129 } 130 #endif 131 132 /* 133 * Attach all the sub-devices we can find 134 */ 135 void 136 uha_attach(sc) 137 struct uha_softc *sc; 138 { 139 struct scsibus_attach_args saa; 140 141 (sc->init)(sc); 142 TAILQ_INIT(&sc->sc_free_mscp); 143 144 /* 145 * fill in the prototype scsi_link. 146 */ 147 sc->sc_link.adapter_softc = sc; 148 sc->sc_link.adapter_target = sc->sc_scsi_dev; 149 sc->sc_link.adapter = &uha_switch; 150 sc->sc_link.device = &uha_dev; 151 sc->sc_link.openings = 2; 152 153 bzero(&saa, sizeof(saa)); 154 saa.saa_sc_link = &sc->sc_link; 155 156 /* 157 * ask the adapter what subunits are present 158 */ 159 config_found(&sc->sc_dev, &saa, uhaprint); 160 } 161 162 integrate void 163 uha_reset_mscp(sc, mscp) 164 struct uha_softc *sc; 165 struct uha_mscp *mscp; 166 { 167 168 mscp->flags = 0; 169 } 170 171 /* 172 * A mscp (and hence a mbx-out) is put onto the free list. 173 */ 174 void 175 uha_free_mscp(sc, mscp) 176 struct uha_softc *sc; 177 struct uha_mscp *mscp; 178 { 179 int s; 180 181 s = splbio(); 182 183 uha_reset_mscp(sc, mscp); 184 TAILQ_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain); 185 186 /* 187 * If there were none, wake anybody waiting for one to come free, 188 * starting with queued entries. 189 */ 190 if (TAILQ_NEXT(mscp, chain) == NULL) 191 wakeup(&sc->sc_free_mscp); 192 193 splx(s); 194 } 195 196 integrate void 197 uha_init_mscp(sc, mscp) 198 struct uha_softc *sc; 199 struct uha_mscp *mscp; 200 { 201 int hashnum; 202 203 bzero(mscp, sizeof(struct uha_mscp)); 204 /* 205 * put in the phystokv hash table 206 * Never gets taken out. 207 */ 208 mscp->hashkey = KVTOPHYS(mscp); 209 hashnum = MSCP_HASH(mscp->hashkey); 210 mscp->nexthash = sc->sc_mscphash[hashnum]; 211 sc->sc_mscphash[hashnum] = mscp; 212 uha_reset_mscp(sc, mscp); 213 } 214 215 /* 216 * Get a free mscp 217 * 218 * If there are none, see if we can allocate a new one. If so, put it in the 219 * hash table too otherwise either return an error or sleep. 220 */ 221 struct uha_mscp * 222 uha_get_mscp(sc, flags) 223 struct uha_softc *sc; 224 int flags; 225 { 226 struct uha_mscp *mscp; 227 int s; 228 229 s = splbio(); 230 231 /* 232 * If we can and have to, sleep waiting for one to come free 233 * but only if we can't allocate a new one 234 */ 235 for (;;) { 236 mscp = TAILQ_FIRST(&sc->sc_free_mscp); 237 if (mscp) { 238 TAILQ_REMOVE(&sc->sc_free_mscp, mscp, chain); 239 break; 240 } 241 if (sc->sc_nummscps < UHA_MSCP_MAX) { 242 mscp = (struct uha_mscp *) malloc(sizeof(struct uha_mscp), 243 M_TEMP, M_NOWAIT); 244 if (!mscp) { 245 printf("%s: can't malloc mscp\n", 246 sc->sc_dev.dv_xname); 247 goto out; 248 } 249 uha_init_mscp(sc, mscp); 250 sc->sc_nummscps++; 251 break; 252 } 253 if ((flags & SCSI_NOSLEEP) != 0) 254 goto out; 255 tsleep(&sc->sc_free_mscp, PRIBIO, "uhamsc", 0); 256 } 257 258 mscp->flags |= MSCP_ALLOC; 259 260 out: 261 splx(s); 262 return (mscp); 263 } 264 265 /* 266 * given a physical address, find the mscp that it corresponds to. 267 */ 268 struct uha_mscp * 269 uha_mscp_phys_kv(sc, mscp_phys) 270 struct uha_softc *sc; 271 u_long mscp_phys; 272 { 273 int hashnum = MSCP_HASH(mscp_phys); 274 struct uha_mscp *mscp = sc->sc_mscphash[hashnum]; 275 276 while (mscp) { 277 if (mscp->hashkey == mscp_phys) 278 break; 279 mscp = mscp->nexthash; 280 } 281 return (mscp); 282 } 283 284 /* 285 * We have a mscp which has been processed by the adaptor, now we look to see 286 * how the operation went. 287 */ 288 void 289 uha_done(sc, mscp) 290 struct uha_softc *sc; 291 struct uha_mscp *mscp; 292 { 293 struct scsi_sense_data *s1, *s2; 294 struct scsi_xfer *xs = mscp->xs; 295 296 SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); 297 /* 298 * Otherwise, put the results of the operation 299 * into the xfer and call whoever started it 300 */ 301 if ((mscp->flags & MSCP_ALLOC) == 0) { 302 printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname); 303 Debugger(); 304 return; 305 } 306 if (xs->error == XS_NOERROR) { 307 if (mscp->host_stat != UHA_NO_ERR) { 308 switch (mscp->host_stat) { 309 case UHA_SBUS_TIMEOUT: /* No response */ 310 xs->error = XS_SELTIMEOUT; 311 break; 312 default: /* Other scsi protocol messes */ 313 printf("%s: host_stat %x\n", 314 sc->sc_dev.dv_xname, mscp->host_stat); 315 xs->error = XS_DRIVER_STUFFUP; 316 } 317 } else if (mscp->target_stat != SCSI_OK) { 318 switch (mscp->target_stat) { 319 case SCSI_CHECK: 320 s1 = &mscp->mscp_sense; 321 s2 = &xs->sense; 322 *s2 = *s1; 323 xs->error = XS_SENSE; 324 break; 325 case SCSI_BUSY: 326 xs->error = XS_BUSY; 327 break; 328 default: 329 printf("%s: target_stat %x\n", 330 sc->sc_dev.dv_xname, mscp->target_stat); 331 xs->error = XS_DRIVER_STUFFUP; 332 } 333 } else 334 xs->resid = 0; 335 } 336 uha_free_mscp(sc, mscp); 337 xs->flags |= ITSDONE; 338 scsi_done(xs); 339 } 340 341 void 342 uhaminphys(struct buf *bp, struct scsi_link *sl) 343 { 344 if (bp->b_bcount > ((UHA_NSEG - 1) << PGSHIFT)) 345 bp->b_bcount = ((UHA_NSEG - 1) << PGSHIFT); 346 minphys(bp); 347 } 348 349 /* 350 * start a scsi operation given the command and the data address. Also 351 * needs the unit, target and lu. 352 */ 353 int 354 uha_scsi_cmd(xs) 355 struct scsi_xfer *xs; 356 { 357 struct scsi_link *sc_link = xs->sc_link; 358 struct uha_softc *sc = sc_link->adapter_softc; 359 struct uha_mscp *mscp; 360 struct uha_dma_seg *sg; 361 int seg; /* scatter gather seg being worked on */ 362 u_long thiskv, thisphys, nextphys; 363 int bytes_this_seg, bytes_this_page, datalen, flags; 364 int s; 365 366 SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); 367 /* 368 * get a mscp (mbox-out) to use. If the transfer 369 * is from a buf (possibly from interrupt time) 370 * then we can't allow it to sleep 371 */ 372 flags = xs->flags; 373 if ((mscp = uha_get_mscp(sc, flags)) == NULL) { 374 return (NO_CCB); 375 } 376 mscp->xs = xs; 377 mscp->timeout = xs->timeout; 378 timeout_set(&xs->stimeout, uha_timeout, xs); 379 380 /* 381 * Put all the arguments for the xfer in the mscp 382 */ 383 if (flags & SCSI_RESET) { 384 mscp->opcode = UHA_SDR; 385 mscp->ca = 0x01; 386 } else { 387 mscp->opcode = UHA_TSP; 388 /* XXX Not for tapes. */ 389 mscp->ca = 0x01; 390 bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length); 391 } 392 mscp->xdir = UHA_SDET; 393 mscp->dcn = 0x00; 394 mscp->chan = 0x00; 395 mscp->target = sc_link->target; 396 mscp->lun = sc_link->lun; 397 mscp->scsi_cmd_length = xs->cmdlen; 398 mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense); 399 mscp->req_sense_length = sizeof(mscp->mscp_sense); 400 mscp->host_stat = 0x00; 401 mscp->target_stat = 0x00; 402 403 if (xs->datalen) { 404 sg = mscp->uha_dma; 405 seg = 0; 406 407 /* 408 * Set up the scatter gather block 409 */ 410 SC_DEBUG(sc_link, SDEV_DB4, 411 ("%d @0x%x:- ", xs->datalen, xs->data)); 412 datalen = xs->datalen; 413 thiskv = (int) xs->data; 414 thisphys = KVTOPHYS(thiskv); 415 416 while (datalen && seg < UHA_NSEG) { 417 bytes_this_seg = 0; 418 419 /* put in the base address */ 420 sg->seg_addr = thisphys; 421 422 SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys)); 423 424 /* do it at least once */ 425 nextphys = thisphys; 426 while (datalen && thisphys == nextphys) { 427 /* 428 * This page is contiguous (physically) 429 * with the last, just extend the 430 * length 431 */ 432 /* how far to the end of the page */ 433 nextphys = (thisphys & ~PGOFSET) + NBPG; 434 bytes_this_page = nextphys - thisphys; 435 /**** or the data ****/ 436 bytes_this_page = min(bytes_this_page, 437 datalen); 438 bytes_this_seg += bytes_this_page; 439 datalen -= bytes_this_page; 440 441 /* get more ready for the next page */ 442 thiskv = (thiskv & ~PGOFSET) + NBPG; 443 if (datalen) 444 thisphys = KVTOPHYS(thiskv); 445 } 446 /* 447 * next page isn't contiguous, finish the seg 448 */ 449 SC_DEBUGN(sc_link, SDEV_DB4, 450 ("(0x%x)", bytes_this_seg)); 451 sg->seg_len = bytes_this_seg; 452 sg++; 453 seg++; 454 } 455 456 SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); 457 if (datalen) { 458 /* 459 * there's still data, must have run out of segs! 460 */ 461 printf("%s: uha_scsi_cmd, more than %d dma segs\n", 462 sc->sc_dev.dv_xname, UHA_NSEG); 463 goto bad; 464 } 465 mscp->data_addr = KVTOPHYS(mscp->uha_dma); 466 mscp->data_length = xs->datalen; 467 mscp->sgth = 0x01; 468 mscp->sg_num = seg; 469 } else { /* No data xfer, use non S/G values */ 470 mscp->data_addr = (physaddr)0; 471 mscp->data_length = 0; 472 mscp->sgth = 0x00; 473 mscp->sg_num = 0; 474 } 475 mscp->link_id = 0; 476 mscp->link_addr = (physaddr)0; 477 478 s = splbio(); 479 (sc->start_mbox)(sc, mscp); 480 splx(s); 481 482 /* 483 * Usually return SUCCESSFULLY QUEUED 484 */ 485 if ((flags & SCSI_POLL) == 0) 486 return (SUCCESSFULLY_QUEUED); 487 488 /* 489 * If we can't use interrupts, poll on completion 490 */ 491 if ((sc->poll)(sc, xs, mscp->timeout)) { 492 uha_timeout(mscp); 493 if ((sc->poll)(sc, xs, mscp->timeout)) 494 uha_timeout(mscp); 495 } 496 return (COMPLETE); 497 498 bad: 499 xs->error = XS_DRIVER_STUFFUP; 500 uha_free_mscp(sc, mscp); 501 return (COMPLETE); 502 } 503 504 void 505 uha_timeout(arg) 506 void *arg; 507 { 508 struct uha_mscp *mscp = arg; 509 struct scsi_xfer *xs = mscp->xs; 510 struct scsi_link *sc_link = xs->sc_link; 511 struct uha_softc *sc = sc_link->adapter_softc; 512 int s; 513 514 sc_print_addr(sc_link); 515 printf("timed out"); 516 517 s = splbio(); 518 519 if (mscp->flags & MSCP_ABORT) { 520 /* abort timed out */ 521 printf(" AGAIN\n"); 522 /* XXX Must reset! */ 523 } else { 524 /* abort the operation that has timed out */ 525 printf("\n"); 526 mscp->xs->error = XS_TIMEOUT; 527 mscp->timeout = UHA_ABORT_TIMEOUT; 528 mscp->flags |= MSCP_ABORT; 529 (sc->start_mbox)(sc, mscp); 530 } 531 532 splx(s); 533 } 534