1 /* $NetBSD: cac.c,v 1.26 2003/12/05 10:23:00 pk Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 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.26 2003/12/05 10:23:00 pk 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 <machine/bswap.h> 60 #include <machine/bus.h> 61 62 #include <dev/ic/cacreg.h> 63 #include <dev/ic/cacvar.h> 64 65 struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int); 66 void cac_ccb_done(struct cac_softc *, struct cac_ccb *); 67 void cac_ccb_free(struct cac_softc *, struct cac_ccb *); 68 int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int); 69 int cac_ccb_start(struct cac_softc *, struct cac_ccb *); 70 int cac_print(void *, const char *); 71 void cac_shutdown(void *); 72 int cac_submatch(struct device *, struct cfdata *, void *); 73 74 struct cac_ccb *cac_l0_completed(struct cac_softc *); 75 int cac_l0_fifo_full(struct cac_softc *); 76 void cac_l0_intr_enable(struct cac_softc *, int); 77 int cac_l0_intr_pending(struct cac_softc *); 78 void cac_l0_submit(struct cac_softc *, struct cac_ccb *); 79 80 static void *cac_sdh; /* shutdown hook */ 81 82 const struct cac_linkage cac_l0 = { 83 cac_l0_completed, 84 cac_l0_fifo_full, 85 cac_l0_intr_enable, 86 cac_l0_intr_pending, 87 cac_l0_submit 88 }; 89 90 /* 91 * Initialise our interface to the controller. 92 */ 93 int 94 cac_init(struct cac_softc *sc, const char *intrstr, int startfw) 95 { 96 struct cac_controller_info cinfo; 97 struct cac_attach_args caca; 98 int error, rseg, size, i; 99 bus_dma_segment_t seg; 100 struct cac_ccb *ccb; 101 102 if (intrstr != NULL) 103 aprint_normal("%s: interrupting at %s\n", sc->sc_dv.dv_xname, 104 intrstr); 105 106 SIMPLEQ_INIT(&sc->sc_ccb_free); 107 SIMPLEQ_INIT(&sc->sc_ccb_queue); 108 109 size = sizeof(struct cac_ccb) * CAC_MAX_CCBS; 110 111 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, 112 &rseg, BUS_DMA_NOWAIT)) != 0) { 113 aprint_error("%s: unable to allocate CCBs, error = %d\n", 114 sc->sc_dv.dv_xname, error); 115 return (-1); 116 } 117 118 if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, 119 (caddr_t *)&sc->sc_ccbs, 120 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 121 aprint_error("%s: unable to map CCBs, error = %d\n", 122 sc->sc_dv.dv_xname, error); 123 return (-1); 124 } 125 126 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 127 BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { 128 aprint_error("%s: unable to create CCB DMA map, error = %d\n", 129 sc->sc_dv.dv_xname, error); 130 return (-1); 131 } 132 133 if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs, 134 size, NULL, BUS_DMA_NOWAIT)) != 0) { 135 aprint_error("%s: unable to load CCB DMA map, error = %d\n", 136 sc->sc_dv.dv_xname, error); 137 return (-1); 138 } 139 140 sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr; 141 memset(sc->sc_ccbs, 0, size); 142 ccb = (struct cac_ccb *)sc->sc_ccbs; 143 144 for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) { 145 /* Create the DMA map for this CCB's data */ 146 error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER, 147 CAC_SG_SIZE, CAC_MAX_XFER, 0, 148 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 149 &ccb->ccb_dmamap_xfer); 150 151 if (error) { 152 aprint_error("%s: can't create ccb dmamap (%d)\n", 153 sc->sc_dv.dv_xname, error); 154 break; 155 } 156 157 ccb->ccb_flags = 0; 158 ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb); 159 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain); 160 } 161 162 /* Start firmware background tasks, if needed. */ 163 if (startfw) { 164 if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo), 165 0, 0, CAC_CCB_DATA_IN, NULL)) { 166 aprint_error("%s: CAC_CMD_START_FIRMWARE failed\n", 167 sc->sc_dv.dv_xname); 168 return (-1); 169 } 170 } 171 172 if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0, 173 CAC_CCB_DATA_IN, NULL)) { 174 aprint_error("%s: CAC_CMD_GET_CTRL_INFO failed\n", 175 sc->sc_dv.dv_xname); 176 return (-1); 177 } 178 179 sc->sc_nunits = cinfo.num_drvs; 180 for (i = 0; i < cinfo.num_drvs; i++) { 181 caca.caca_unit = i; 182 config_found_sm(&sc->sc_dv, &caca, cac_print, cac_submatch); 183 } 184 185 /* Set our `shutdownhook' before we start any device activity. */ 186 if (cac_sdh == NULL) 187 cac_sdh = shutdownhook_establish(cac_shutdown, NULL); 188 189 (*sc->sc_cl.cl_intr_enable)(sc, CAC_INTR_ENABLE); 190 return (0); 191 } 192 193 /* 194 * Shut down all `cac' controllers. 195 */ 196 void 197 cac_shutdown(void *cookie) 198 { 199 extern struct cfdriver cac_cd; 200 struct cac_softc *sc; 201 u_int8_t buf[512]; 202 int i; 203 204 for (i = 0; i < cac_cd.cd_ndevs; i++) { 205 if ((sc = device_lookup(&cac_cd, i)) == NULL) 206 continue; 207 memset(buf, 0, sizeof(buf)); 208 buf[0] = 1; 209 cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0, 210 CAC_CCB_DATA_OUT, NULL); 211 } 212 } 213 214 /* 215 * Print autoconfiguration message for a sub-device. 216 */ 217 int 218 cac_print(void *aux, const char *pnp) 219 { 220 struct cac_attach_args *caca; 221 222 caca = (struct cac_attach_args *)aux; 223 224 if (pnp != NULL) 225 aprint_normal("block device at %s", pnp); 226 aprint_normal(" unit %d", caca->caca_unit); 227 return (UNCONF); 228 } 229 230 /* 231 * Match a sub-device. 232 */ 233 int 234 cac_submatch(struct device *parent, struct cfdata *cf, void *aux) 235 { 236 struct cac_attach_args *caca; 237 238 caca = (struct cac_attach_args *)aux; 239 240 if (cf->cacacf_unit != CACCF_UNIT_DEFAULT && 241 cf->cacacf_unit != caca->caca_unit) 242 return (0); 243 244 return (config_match(parent, cf, aux)); 245 } 246 247 /* 248 * Handle an interrupt from the controller: process finished CCBs and 249 * dequeue any waiting CCBs. 250 */ 251 int 252 cac_intr(void *cookie) 253 { 254 struct cac_softc *sc; 255 struct cac_ccb *ccb; 256 257 sc = (struct cac_softc *)cookie; 258 259 if (!(*sc->sc_cl.cl_intr_pending)(sc)) { 260 #ifdef DEBUG 261 printf("%s: spurious intr\n", sc->sc_dv.dv_xname); 262 #endif 263 return (0); 264 } 265 266 while ((ccb = (*sc->sc_cl.cl_completed)(sc)) != NULL) { 267 cac_ccb_done(sc, ccb); 268 cac_ccb_start(sc, NULL); 269 } 270 271 return (1); 272 } 273 274 /* 275 * Execute a [polled] command. 276 */ 277 int 278 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, 279 int drive, int blkno, int flags, struct cac_context *context) 280 { 281 struct cac_ccb *ccb; 282 struct cac_sgb *sgb; 283 int s, i, rv, size, nsegs; 284 285 size = 0; 286 287 if ((ccb = cac_ccb_alloc(sc, 1)) == NULL) { 288 printf("%s: unable to alloc CCB", sc->sc_dv.dv_xname); 289 return (EAGAIN); 290 } 291 292 if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 293 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, 294 (void *)data, datasize, NULL, BUS_DMA_NOWAIT | 295 BUS_DMA_STREAMING | ((flags & CAC_CCB_DATA_IN) ? 296 BUS_DMA_READ : BUS_DMA_WRITE)); 297 298 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, datasize, 299 (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD : 300 BUS_DMASYNC_PREWRITE); 301 302 sgb = ccb->ccb_seg; 303 nsegs = min(ccb->ccb_dmamap_xfer->dm_nsegs, CAC_SG_SIZE); 304 305 for (i = 0; i < nsegs; i++, sgb++) { 306 size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len; 307 sgb->length = 308 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len); 309 sgb->addr = 310 htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr); 311 } 312 } else { 313 size = datasize; 314 nsegs = 0; 315 } 316 317 ccb->ccb_hdr.drive = drive; 318 ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) + 319 sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2); 320 321 ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE)); 322 ccb->ccb_req.command = command; 323 ccb->ccb_req.sgcount = nsegs; 324 ccb->ccb_req.blkno = htole32(blkno); 325 326 ccb->ccb_flags = flags; 327 ccb->ccb_datasize = size; 328 329 if (context == NULL) { 330 memset(&ccb->ccb_context, 0, sizeof(struct cac_context)); 331 s = splbio(); 332 333 /* Synchronous commands musn't wait. */ 334 if ((*sc->sc_cl.cl_fifo_full)(sc)) { 335 cac_ccb_free(sc, ccb); 336 rv = EAGAIN; 337 } else { 338 #ifdef DIAGNOSTIC 339 ccb->ccb_flags |= CAC_CCB_ACTIVE; 340 #endif 341 (*sc->sc_cl.cl_submit)(sc, ccb); 342 rv = cac_ccb_poll(sc, ccb, 2000); 343 cac_ccb_free(sc, ccb); 344 } 345 } else { 346 memcpy(&ccb->ccb_context, context, sizeof(struct cac_context)); 347 s = splbio(); 348 (void)cac_ccb_start(sc, ccb); 349 rv = 0; 350 } 351 352 splx(s); 353 return (rv); 354 } 355 356 /* 357 * Wait for the specified CCB to complete. Must be called at splbio. 358 */ 359 int 360 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo) 361 { 362 struct cac_ccb *ccb; 363 364 timo *= 10; 365 366 do { 367 for (; timo != 0; timo--) { 368 ccb = (*sc->sc_cl.cl_completed)(sc); 369 if (ccb != NULL) 370 break; 371 DELAY(100); 372 } 373 374 if (timo == 0) { 375 printf("%s: timeout\n", sc->sc_dv.dv_xname); 376 return (EBUSY); 377 } 378 cac_ccb_done(sc, ccb); 379 } while (ccb != wantccb); 380 381 return (0); 382 } 383 384 /* 385 * Enqueue the specified command (if any) and attempt to start all enqueued 386 * commands. Must be called at splbio. 387 */ 388 int 389 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb) 390 { 391 392 if (ccb != NULL) 393 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain); 394 395 while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) { 396 if ((*sc->sc_cl.cl_fifo_full)(sc)) 397 return (EAGAIN); 398 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain); 399 #ifdef DIAGNOSTIC 400 ccb->ccb_flags |= CAC_CCB_ACTIVE; 401 #endif 402 (*sc->sc_cl.cl_submit)(sc, ccb); 403 } 404 405 return (0); 406 } 407 408 /* 409 * Process a finished CCB. 410 */ 411 void 412 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb) 413 { 414 struct device *dv; 415 void *context; 416 int error; 417 418 error = 0; 419 420 #ifdef DIAGNOSTIC 421 if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) 422 panic("cac_ccb_done: CCB not active"); 423 ccb->ccb_flags &= ~CAC_CCB_ACTIVE; 424 #endif 425 426 if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { 427 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, 428 ccb->ccb_datasize, ccb->ccb_flags & CAC_CCB_DATA_IN ? 429 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 430 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer); 431 } 432 433 error = ccb->ccb_req.error; 434 if (ccb->ccb_context.cc_handler != NULL) { 435 dv = ccb->ccb_context.cc_dv; 436 context = ccb->ccb_context.cc_context; 437 cac_ccb_free(sc, ccb); 438 (*ccb->ccb_context.cc_handler)(dv, context, error); 439 } else { 440 if ((error & CAC_RET_SOFT_ERROR) != 0) 441 printf("%s: soft error; array may be degraded\n", 442 sc->sc_dv.dv_xname); 443 if ((error & CAC_RET_HARD_ERROR) != 0) 444 printf("%s: hard error\n", sc->sc_dv.dv_xname); 445 if ((error & CAC_RET_CMD_REJECTED) != 0) { 446 error = 1; 447 printf("%s: invalid request\n", sc->sc_dv.dv_xname); 448 } 449 } 450 } 451 452 /* 453 * Allocate a CCB. 454 */ 455 struct cac_ccb * 456 cac_ccb_alloc(struct cac_softc *sc, int nosleep) 457 { 458 struct cac_ccb *ccb; 459 int s; 460 461 s = splbio(); 462 463 for (;;) { 464 if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) { 465 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain); 466 break; 467 } 468 if (nosleep) { 469 ccb = NULL; 470 break; 471 } 472 tsleep(&sc->sc_ccb_free, PRIBIO, "cacccb", 0); 473 } 474 475 splx(s); 476 return (ccb); 477 } 478 479 /* 480 * Put a CCB onto the freelist. 481 */ 482 void 483 cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb) 484 { 485 int s; 486 487 ccb->ccb_flags = 0; 488 s = splbio(); 489 SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); 490 if (SIMPLEQ_NEXT(ccb, ccb_chain) == NULL) 491 wakeup_one(&sc->sc_ccb_free); 492 splx(s); 493 } 494 495 /* 496 * Board specific linkage shared between multiple bus types. 497 */ 498 499 int 500 cac_l0_fifo_full(struct cac_softc *sc) 501 { 502 503 return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0); 504 } 505 506 void 507 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb) 508 { 509 510 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, (caddr_t)ccb - sc->sc_ccbs, 511 sizeof(struct cac_ccb), BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 512 cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr); 513 } 514 515 struct cac_ccb * 516 cac_l0_completed(struct cac_softc *sc) 517 { 518 struct cac_ccb *ccb; 519 paddr_t off; 520 521 if ((off = cac_inl(sc, CAC_REG_DONE_FIFO)) == 0) 522 return (NULL); 523 524 if ((off & 3) != 0) 525 printf("%s: failed command list returned: %lx\n", 526 sc->sc_dv.dv_xname, (long)off); 527 528 off = (off & ~3) - sc->sc_ccbs_paddr; 529 ccb = (struct cac_ccb *)(sc->sc_ccbs + off); 530 531 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, off, sizeof(struct cac_ccb), 532 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 533 534 return (ccb); 535 } 536 537 int 538 cac_l0_intr_pending(struct cac_softc *sc) 539 { 540 541 return (cac_inl(sc, CAC_REG_INTR_PENDING) & CAC_INTR_ENABLE); 542 } 543 544 void 545 cac_l0_intr_enable(struct cac_softc *sc, int state) 546 { 547 548 cac_outl(sc, CAC_REG_INTR_MASK, 549 state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE); 550 } 551