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