1 /* $NetBSD: cac.c,v 1.43 2007/12/05 07:06:51 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2006, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Driver for Compaq array controllers. 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: cac.c,v 1.43 2007/12/05 07:06:51 ad Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/kernel.h> 49 #include <sys/device.h> 50 #include <sys/queue.h> 51 #include <sys/proc.h> 52 #include <sys/buf.h> 53 #include <sys/endian.h> 54 #include <sys/malloc.h> 55 #include <sys/pool.h> 56 57 #include <uvm/uvm_extern.h> 58 59 #include <sys/bswap.h> 60 #include <sys/bus.h> 61 62 #include <dev/ic/cacreg.h> 63 #include <dev/ic/cacvar.h> 64 65 #include "locators.h" 66 67 static struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int); 68 static void cac_ccb_done(struct cac_softc *, struct cac_ccb *); 69 static void cac_ccb_free(struct cac_softc *, struct cac_ccb *); 70 static int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int); 71 static int cac_ccb_start(struct cac_softc *, struct cac_ccb *); 72 static int cac_print(void *, const char *); 73 static void cac_shutdown(void *); 74 75 static struct cac_ccb *cac_l0_completed(struct cac_softc *); 76 static int cac_l0_fifo_full(struct cac_softc *); 77 static void cac_l0_intr_enable(struct cac_softc *, int); 78 static int cac_l0_intr_pending(struct cac_softc *); 79 static void cac_l0_submit(struct cac_softc *, struct cac_ccb *); 80 81 static void *cac_sdh; /* shutdown hook */ 82 83 const struct cac_linkage cac_l0 = { 84 cac_l0_completed, 85 cac_l0_fifo_full, 86 cac_l0_intr_enable, 87 cac_l0_intr_pending, 88 cac_l0_submit 89 }; 90 91 /* 92 * Initialise our interface to the controller. 93 */ 94 int 95 cac_init(struct cac_softc *sc, const char *intrstr, int startfw) 96 { 97 struct cac_controller_info cinfo; 98 struct cac_attach_args caca; 99 int error, rseg, size, i; 100 bus_dma_segment_t seg; 101 struct cac_ccb *ccb; 102 int locs[CACCF_NLOCS]; 103 char firm[8]; 104 105 if (intrstr != NULL) 106 aprint_normal("%s: interrupting at %s\n", sc->sc_dv.dv_xname, 107 intrstr); 108 109 SIMPLEQ_INIT(&sc->sc_ccb_free); 110 SIMPLEQ_INIT(&sc->sc_ccb_queue); 111 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); 112 cv_init(&sc->sc_ccb_cv, "cacccb"); 113 114 size = sizeof(struct cac_ccb) * CAC_MAX_CCBS; 115 116 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, 117 &rseg, BUS_DMA_NOWAIT)) != 0) { 118 aprint_error("%s: unable to allocate CCBs, error = %d\n", 119 sc->sc_dv.dv_xname, error); 120 return (-1); 121 } 122 123 if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 124 (void **)&sc->sc_ccbs, 125 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 126 aprint_error("%s: unable to map CCBs, error = %d\n", 127 sc->sc_dv.dv_xname, error); 128 return (-1); 129 } 130 131 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 132 BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { 133 aprint_error("%s: unable to create CCB DMA map, error = %d\n", 134 sc->sc_dv.dv_xname, error); 135 return (-1); 136 } 137 138 if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs, 139 size, NULL, BUS_DMA_NOWAIT)) != 0) { 140 aprint_error("%s: unable to load CCB DMA map, error = %d\n", 141 sc->sc_dv.dv_xname, error); 142 return (-1); 143 } 144 145 sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr; 146 memset(sc->sc_ccbs, 0, size); 147 ccb = (struct cac_ccb *)sc->sc_ccbs; 148 149 for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) { 150 /* Create the DMA map for this CCB's data */ 151 error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER, 152 CAC_SG_SIZE, CAC_MAX_XFER, 0, 153 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 154 &ccb->ccb_dmamap_xfer); 155 156 if (error) { 157 aprint_error("%s: can't create ccb dmamap (%d)\n", 158 sc->sc_dv.dv_xname, error); 159 break; 160 } 161 162 ccb->ccb_flags = 0; 163 ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb); 164 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain); 165 } 166 167 /* Start firmware background tasks, if needed. */ 168 if (startfw) { 169 if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo), 170 0, 0, CAC_CCB_DATA_IN, NULL)) { 171 aprint_error("%s: CAC_CMD_START_FIRMWARE failed\n", 172 sc->sc_dv.dv_xname); 173 return (-1); 174 } 175 } 176 177 if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0, 178 CAC_CCB_DATA_IN, NULL)) { 179 aprint_error("%s: CAC_CMD_GET_CTRL_INFO failed\n", 180 sc->sc_dv.dv_xname); 181 return (-1); 182 } 183 184 strlcpy(firm, cinfo.firm_rev, 4+1); 185 printf("%s: %d channels, firmware <%s>\n", sc->sc_dv.dv_xname, 186 cinfo.scsi_chips, firm); 187 188 sc->sc_nunits = cinfo.num_drvs; 189 for (i = 0; i < cinfo.num_drvs; i++) { 190 caca.caca_unit = i; 191 192 locs[CACCF_UNIT] = i; 193 194 config_found_sm_loc(&sc->sc_dv, "cac", locs, &caca, 195 cac_print, config_stdsubmatch); 196 } 197 198 /* Set our `shutdownhook' before we start any device activity. */ 199 if (cac_sdh == NULL) 200 cac_sdh = shutdownhook_establish(cac_shutdown, NULL); 201 202 mutex_enter(&sc->sc_mutex); 203 (*sc->sc_cl.cl_intr_enable)(sc, CAC_INTR_ENABLE); 204 mutex_exit(&sc->sc_mutex); 205 206 return (0); 207 } 208 209 /* 210 * Shut down all `cac' controllers. 211 */ 212 static void 213 cac_shutdown(void *cookie) 214 { 215 extern struct cfdriver cac_cd; 216 struct cac_softc *sc; 217 u_int8_t tbuf[512]; 218 int i; 219 220 for (i = 0; i < cac_cd.cd_ndevs; i++) { 221 if ((sc = device_lookup(&cac_cd, i)) == NULL) 222 continue; 223 memset(tbuf, 0, sizeof(tbuf)); 224 tbuf[0] = 1; 225 cac_cmd(sc, CAC_CMD_FLUSH_CACHE, tbuf, sizeof(tbuf), 0, 0, 226 CAC_CCB_DATA_OUT, NULL); 227 } 228 } 229 230 /* 231 * Print autoconfiguration message for a sub-device. 232 */ 233 static int 234 cac_print(void *aux, const char *pnp) 235 { 236 struct cac_attach_args *caca; 237 238 caca = (struct cac_attach_args *)aux; 239 240 if (pnp != NULL) 241 aprint_normal("block device at %s", pnp); 242 aprint_normal(" unit %d", caca->caca_unit); 243 return (UNCONF); 244 } 245 246 /* 247 * Handle an interrupt from the controller: process finished CCBs and 248 * dequeue any waiting CCBs. 249 */ 250 int 251 cac_intr(void *cookie) 252 { 253 struct cac_softc *sc; 254 struct cac_ccb *ccb; 255 int rv; 256 257 sc = (struct cac_softc *)cookie; 258 259 mutex_enter(&sc->sc_mutex); 260 261 if ((*sc->sc_cl.cl_intr_pending)(sc)) { 262 while ((ccb = (*sc->sc_cl.cl_completed)(sc)) != NULL) { 263 cac_ccb_done(sc, ccb); 264 cac_ccb_start(sc, NULL); 265 } 266 rv = 1; 267 } else 268 rv = 0; 269 270 mutex_exit(&sc->sc_mutex); 271 272 return (rv); 273 } 274 275 /* 276 * Execute a [polled] command. 277 */ 278 int 279 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, 280 int drive, int blkno, int flags, struct cac_context *context) 281 { 282 struct cac_ccb *ccb; 283 struct cac_sgb *sgb; 284 int i, rv, size, nsegs; 285 286 size = 0; 287 288 if ((ccb = cac_ccb_alloc(sc, 1)) == NULL) { 289 printf("%s: unable to alloc CCB", sc->sc_dv.dv_xname); 290 return (EAGAIN); 291 } 292 293 if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 294 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, 295 (void *)data, datasize, NULL, BUS_DMA_NOWAIT | 296 BUS_DMA_STREAMING | ((flags & CAC_CCB_DATA_IN) ? 297 BUS_DMA_READ : BUS_DMA_WRITE)); 298 299 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, datasize, 300 (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD : 301 BUS_DMASYNC_PREWRITE); 302 303 sgb = ccb->ccb_seg; 304 nsegs = min(ccb->ccb_dmamap_xfer->dm_nsegs, CAC_SG_SIZE); 305 306 for (i = 0; i < nsegs; i++, sgb++) { 307 size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len; 308 sgb->length = 309 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len); 310 sgb->addr = 311 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr); 312 } 313 } else { 314 size = datasize; 315 nsegs = 0; 316 } 317 318 ccb->ccb_hdr.drive = drive; 319 ccb->ccb_hdr.priority = 0; 320 ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) + 321 sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2); 322 323 ccb->ccb_req.next = 0; 324 ccb->ccb_req.error = 0; 325 ccb->ccb_req.reserved = 0; 326 ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE)); 327 ccb->ccb_req.command = command; 328 ccb->ccb_req.sgcount = nsegs; 329 ccb->ccb_req.blkno = htole32(blkno); 330 331 ccb->ccb_flags = flags; 332 ccb->ccb_datasize = size; 333 334 mutex_enter(&sc->sc_mutex); 335 336 if (context == NULL) { 337 memset(&ccb->ccb_context, 0, sizeof(struct cac_context)); 338 339 /* Synchronous commands musn't wait. */ 340 if ((*sc->sc_cl.cl_fifo_full)(sc)) { 341 cac_ccb_free(sc, ccb); 342 rv = EAGAIN; 343 } else { 344 #ifdef DIAGNOSTIC 345 ccb->ccb_flags |= CAC_CCB_ACTIVE; 346 #endif 347 (*sc->sc_cl.cl_submit)(sc, ccb); 348 rv = cac_ccb_poll(sc, ccb, 2000); 349 cac_ccb_free(sc, ccb); 350 } 351 } else { 352 memcpy(&ccb->ccb_context, context, sizeof(struct cac_context)); 353 (void)cac_ccb_start(sc, ccb); 354 rv = 0; 355 } 356 357 mutex_exit(&sc->sc_mutex); 358 return (rv); 359 } 360 361 /* 362 * Wait for the specified CCB to complete. 363 */ 364 static int 365 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo) 366 { 367 struct cac_ccb *ccb; 368 369 KASSERT(mutex_owned(&sc->sc_mutex)); 370 371 timo *= 1000; 372 373 do { 374 for (; timo != 0; timo--) { 375 ccb = (*sc->sc_cl.cl_completed)(sc); 376 if (ccb != NULL) 377 break; 378 DELAY(1); 379 } 380 381 if (timo == 0) { 382 printf("%s: timeout\n", sc->sc_dv.dv_xname); 383 return (EBUSY); 384 } 385 cac_ccb_done(sc, ccb); 386 } while (ccb != wantccb); 387 388 return (0); 389 } 390 391 /* 392 * Enqueue the specified command (if any) and attempt to start all enqueued 393 * commands. 394 */ 395 static int 396 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb) 397 { 398 399 KASSERT(mutex_owned(&sc->sc_mutex)); 400 401 if (ccb != NULL) 402 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain); 403 404 while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) { 405 if ((*sc->sc_cl.cl_fifo_full)(sc)) 406 return (EAGAIN); 407 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain); 408 #ifdef DIAGNOSTIC 409 ccb->ccb_flags |= CAC_CCB_ACTIVE; 410 #endif 411 (*sc->sc_cl.cl_submit)(sc, ccb); 412 } 413 414 return (0); 415 } 416 417 /* 418 * Process a finished CCB. 419 */ 420 static void 421 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb) 422 { 423 struct device *dv; 424 void *context; 425 int error; 426 427 error = 0; 428 429 KASSERT(mutex_owned(&sc->sc_mutex)); 430 431 #ifdef DIAGNOSTIC 432 if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) 433 panic("cac_ccb_done: CCB not active"); 434 ccb->ccb_flags &= ~CAC_CCB_ACTIVE; 435 #endif 436 437 if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 438 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, 439 ccb->ccb_datasize, ccb->ccb_flags & CAC_CCB_DATA_IN ? 440 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 441 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer); 442 } 443 444 error = ccb->ccb_req.error; 445 if (ccb->ccb_context.cc_handler != NULL) { 446 dv = ccb->ccb_context.cc_dv; 447 context = ccb->ccb_context.cc_context; 448 cac_ccb_free(sc, ccb); 449 (*ccb->ccb_context.cc_handler)(dv, context, error); 450 } else { 451 if ((error & CAC_RET_SOFT_ERROR) != 0) 452 printf("%s: soft error; array may be degraded\n", 453 sc->sc_dv.dv_xname); 454 if ((error & CAC_RET_HARD_ERROR) != 0) 455 printf("%s: hard error\n", sc->sc_dv.dv_xname); 456 if ((error & CAC_RET_CMD_REJECTED) != 0) { 457 error = 1; 458 printf("%s: invalid request\n", sc->sc_dv.dv_xname); 459 } 460 } 461 } 462 463 /* 464 * Allocate a CCB. 465 */ 466 static struct cac_ccb * 467 cac_ccb_alloc(struct cac_softc *sc, int nosleep) 468 { 469 struct cac_ccb *ccb; 470 471 mutex_enter(&sc->sc_mutex); 472 473 for (;;) { 474 if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) { 475 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain); 476 break; 477 } 478 if (nosleep) { 479 ccb = NULL; 480 break; 481 } 482 cv_wait(&sc->sc_ccb_cv, &sc->sc_mutex); 483 } 484 485 mutex_exit(&sc->sc_mutex); 486 return (ccb); 487 } 488 489 /* 490 * Put a CCB onto the freelist. 491 */ 492 static void 493 cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb) 494 { 495 496 KASSERT(mutex_owned(&sc->sc_mutex)); 497 498 ccb->ccb_flags = 0; 499 if (SIMPLEQ_EMPTY(&sc->sc_ccb_free)) 500 cv_signal(&sc->sc_ccb_cv); 501 SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); 502 } 503 504 /* 505 * Board specific linkage shared between multiple bus types. 506 */ 507 508 static int 509 cac_l0_fifo_full(struct cac_softc *sc) 510 { 511 512 KASSERT(mutex_owned(&sc->sc_mutex)); 513 514 return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0); 515 } 516 517 static void 518 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb) 519 { 520 521 KASSERT(mutex_owned(&sc->sc_mutex)); 522 523 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 524 (char *)ccb - (char *)sc->sc_ccbs, 525 sizeof(struct cac_ccb), BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 526 cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr); 527 } 528 529 static struct cac_ccb * 530 cac_l0_completed(struct cac_softc *sc) 531 { 532 struct cac_ccb *ccb; 533 paddr_t off; 534 535 KASSERT(mutex_owned(&sc->sc_mutex)); 536 537 if ((off = cac_inl(sc, CAC_REG_DONE_FIFO)) == 0) 538 return (NULL); 539 540 if ((off & 3) != 0) 541 printf("%s: failed command list returned: %lx\n", 542 sc->sc_dv.dv_xname, (long)off); 543 544 off = (off & ~3) - sc->sc_ccbs_paddr; 545 ccb = (struct cac_ccb *)((char *)sc->sc_ccbs + off); 546 547 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, off, sizeof(struct cac_ccb), 548 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 549 550 if ((off & 3) != 0 && ccb->ccb_req.error == 0) 551 ccb->ccb_req.error = CAC_RET_CMD_REJECTED; 552 553 return (ccb); 554 } 555 556 static int 557 cac_l0_intr_pending(struct cac_softc *sc) 558 { 559 560 KASSERT(mutex_owned(&sc->sc_mutex)); 561 562 return (cac_inl(sc, CAC_REG_INTR_PENDING) & CAC_INTR_ENABLE); 563 } 564 565 static void 566 cac_l0_intr_enable(struct cac_softc *sc, int state) 567 { 568 569 KASSERT(mutex_owned(&sc->sc_mutex)); 570 571 cac_outl(sc, CAC_REG_INTR_MASK, 572 state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE); 573 } 574