1 /* $NetBSD: icp.c,v 1.1 2002/04/22 21:05:21 ad Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 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 * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by Niklas Hallqvist. 53 * 4. The name of the author may not be used to endorse or promote products 54 * derived from this software without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 57 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 58 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 59 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 60 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 61 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 62 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 63 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 64 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 65 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 66 * 67 * from OpenBSD: gdt_common.c,v 1.12 2001/07/04 06:43:18 niklas Exp 68 */ 69 70 /* 71 * This driver would not have written if it was not for the hardware donations 72 * from both ICP-Vortex and �ko.neT. I want to thank them for their support. 73 * 74 * Re-worked for NetBSD by Andrew Doran. Test hardware kindly supplied by 75 * Intel. 76 */ 77 78 #include <sys/cdefs.h> 79 __KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.1 2002/04/22 21:05:21 ad Exp $"); 80 81 #include <sys/param.h> 82 #include <sys/systm.h> 83 #include <sys/kernel.h> 84 #include <sys/device.h> 85 #include <sys/queue.h> 86 #include <sys/proc.h> 87 #include <sys/buf.h> 88 #include <sys/endian.h> 89 #include <sys/malloc.h> 90 #include <sys/disk.h> 91 92 #include <uvm/uvm_extern.h> 93 94 #include <machine/bswap.h> 95 #include <machine/bus.h> 96 97 #include <dev/pci/pcireg.h> 98 #include <dev/pci/pcivar.h> 99 #include <dev/pci/pcidevs.h> 100 101 #include <dev/ic/icpreg.h> 102 #include <dev/ic/icpvar.h> 103 104 int icp_async_event(struct icp_softc *, int); 105 void icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic); 106 void icp_chain(struct icp_softc *); 107 int icp_print(void *, const char *); 108 int icp_submatch(struct device *, struct cfdata *, void *); 109 void icp_watchdog(void *); 110 111 int 112 icp_init(struct icp_softc *icp, const char *intrstr) 113 { 114 struct icp_attach_args icpa; 115 struct icp_binfo binfo; 116 struct icp_ccb *ic; 117 u_int16_t cdev_cnt; 118 int i, j, state, feat, nsegs, rv, noscsi, nocache; 119 120 noscsi = 0; 121 nocache = 0; 122 123 if (intrstr != NULL) 124 printf("%s: interrupting at %s\n", icp->icp_dv.dv_xname, 125 intrstr); 126 127 SIMPLEQ_INIT(&icp->icp_ccb_queue); 128 SIMPLEQ_INIT(&icp->icp_ccb_freelist); 129 callout_init(&icp->icp_wdog_callout); 130 131 /* 132 * Allocate a scratch area. 133 */ 134 if (bus_dmamap_create(icp->icp_dmat, ICP_SCRATCH_SIZE, 1, 135 ICP_SCRATCH_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 136 &icp->icp_scr_dmamap) != 0) { 137 printf("%s: cannot create scratch dmamap\n", 138 icp->icp_dv.dv_xname); 139 return (1); 140 } 141 state++; 142 143 if (bus_dmamem_alloc(icp->icp_dmat, ICP_SCRATCH_SIZE, PAGE_SIZE, 0, 144 icp->icp_scr_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) { 145 printf("%s: cannot alloc scratch dmamem\n", 146 icp->icp_dv.dv_xname); 147 goto bail_out; 148 } 149 state++; 150 151 if (bus_dmamem_map(icp->icp_dmat, icp->icp_scr_seg, nsegs, 152 ICP_SCRATCH_SIZE, &icp->icp_scr, 0)) { 153 printf("%s: cannot map scratch dmamem\n", icp->icp_dv.dv_xname); 154 goto bail_out; 155 } 156 state++; 157 158 if (bus_dmamap_load(icp->icp_dmat, icp->icp_scr_dmamap, icp->icp_scr, 159 ICP_SCRATCH_SIZE, NULL, BUS_DMA_NOWAIT)) { 160 printf("%s: cannot load scratch dmamap\n", icp->icp_dv.dv_xname); 161 goto bail_out; 162 } 163 state++; 164 165 /* 166 * Allocate and initialize the command control blocks. 167 */ 168 ic = malloc(sizeof(*ic) * ICP_NCCBS, M_DEVBUF, M_NOWAIT | M_ZERO); 169 if ((icp->icp_ccbs = ic) == NULL) { 170 printf("%s: malloc() failed\n", icp->icp_dv.dv_xname); 171 goto bail_out; 172 } 173 state++; 174 175 for (i = 0; i < ICP_NCCBS; i++, ic++) { 176 /* 177 * The first two command indexes have special meanings, so 178 * we can't use them. 179 */ 180 ic->ic_ident = i + 2; 181 rv = bus_dmamap_create(icp->icp_dmat, ICP_MAX_XFER, 182 ICP_MAXSG, ICP_MAX_XFER, 0, 183 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 184 &ic->ic_xfer_map); 185 if (rv != 0) 186 break; 187 icp->icp_nccbs++; 188 icp_ccb_free(icp, ic); 189 } 190 #ifdef DIAGNOSTIC 191 if (icp->icp_nccbs != ICP_NCCBS) 192 printf("%s: %d/%d CCBs usable\n", icp->icp_dv.dv_xname, 193 icp->icp_nccbs, ICP_NCCBS); 194 #endif 195 196 /* 197 * Initalize the controller. 198 */ 199 if (!icp_cmd(icp, ICP_SCREENSERVICE, ICP_INIT, 0, 0, 0)) { 200 printf("%s: screen service init error %d\n", 201 icp->icp_dv.dv_xname, icp->icp_status); 202 goto bail_out; 203 } 204 205 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) { 206 printf("%s: cache service init error %d\n", 207 icp->icp_dv.dv_xname, icp->icp_status); 208 goto bail_out; 209 } 210 211 icp_cmd(icp, ICP_CACHESERVICE, ICP_UNFREEZE_IO, 0, 0, 0); 212 213 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_MOUNT, 0xffff, 1, 0)) { 214 printf("%s: cache service mount error %d\n", 215 icp->icp_dv.dv_xname, icp->icp_status); 216 goto bail_out; 217 } 218 219 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) { 220 printf("%s: cache service post-mount init error %d\n", 221 icp->icp_dv.dv_xname, icp->icp_status); 222 goto bail_out; 223 } 224 cdev_cnt = (u_int16_t)icp->icp_info; 225 226 if (!icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_INIT, 0, 0, 0)) { 227 printf("%s: raw service init error %d\n", 228 icp->icp_dv.dv_xname, icp->icp_status); 229 goto bail_out; 230 } 231 232 /* 233 * Set/get raw service features (scatter/gather). 234 */ 235 feat = 0; 236 if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_SET_FEAT, ICP_SCATTER_GATHER, 237 0, 0)) 238 if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_GET_FEAT, 0, 0, 0)) 239 feat = icp->icp_info; 240 241 if ((feat & ICP_SCATTER_GATHER) == 0) { 242 #ifdef DIAGNOSTIC 243 printf("%s: scatter/gather not supported (raw service)\n", 244 icp->icp_dv.dv_xname); 245 #endif 246 noscsi = 1; 247 } 248 249 /* 250 * Set/get cache service features (scatter/gather). 251 */ 252 feat = 0; 253 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_SET_FEAT, 0, 254 ICP_SCATTER_GATHER, 0)) 255 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_GET_FEAT, 0, 0, 0)) 256 feat = icp->icp_info; 257 258 if ((feat & ICP_SCATTER_GATHER) == 0) { 259 #ifdef DIAGNOSTIC 260 printf("%s: scatter/gather not supported (cache service)\n", 261 icp->icp_dv.dv_xname); 262 #endif 263 nocache = 1; 264 } 265 266 /* 267 * Pull some information from the board and dump. 268 */ 269 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, ICP_BOARD_INFO, 270 ICP_INVALID_CHANNEL, sizeof(struct icp_binfo))) { 271 printf("%s: unable to retrive board info\n", 272 icp->icp_dv.dv_xname); 273 goto bail_out; 274 } 275 memcpy(&binfo, icp->icp_scr, sizeof(binfo)); 276 277 printf("%s: model <%s>, firmware <%s>, %d channel(s), %dMB memory\n", 278 icp->icp_dv.dv_xname, binfo.bi_type_string, binfo.bi_raid_string, 279 binfo.bi_chan_count, le32toh(binfo.bi_memsize) >> 20); 280 281 /* 282 * Determine the number of devices, and number of openings per 283 * device. 284 */ 285 if (!nocache) { 286 for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) { 287 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, j, 0, 288 0)) 289 continue; 290 291 icp->icp_cdr[j].cd_size = icp->icp_info; 292 icp->icp_ndevs++; 293 294 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, j, 0, 295 0)) 296 icp->icp_cdr[j].cd_type = icp->icp_info; 297 } 298 } 299 300 if (!noscsi) 301 icp->icp_ndevs += binfo.bi_chan_count; 302 303 if (icp->icp_ndevs != 0) 304 icp->icp_openings = 305 (icp->icp_nccbs - ICP_NCCB_RESERVE) / icp->icp_ndevs; 306 #ifdef ICP_DEBUG 307 printf("%s: %d openings per device\n", icp->icp_dv.dv_xname, 308 icp->icp_openings); 309 #endif 310 311 /* 312 * Attach SCSI channels. 313 */ 314 if (!noscsi) { 315 struct icp_ioc_version *iv; 316 struct icp_rawioc *ri; 317 struct icp_getch *gc; 318 319 iv = (struct icp_ioc_version *)icp->icp_scr; 320 iv->iv_version = htole32(ICP_IOC_NEWEST); 321 iv->iv_listents = ICP_MAXBUS; 322 iv->iv_firstchan = 0; 323 iv->iv_lastchan = ICP_MAXBUS - 1; 324 iv->iv_listoffset = htole32(sizeof(*iv)); 325 326 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, 327 ICP_IOCHAN_RAW_DESC, ICP_INVALID_CHANNEL, 328 sizeof(*iv) + ICP_MAXBUS * sizeof(*ri))) { 329 ri = (struct icp_rawioc *)(iv + 1); 330 for (j = 0; j < binfo.bi_chan_count; j++, ri++) 331 icp->icp_bus_id[j] = ri->ri_procid; 332 } else { 333 /* 334 * Fall back to the old method. 335 */ 336 gc = (struct icp_getch *)icp->icp_scr; 337 338 for (i = 0; j < binfo.bi_chan_count; j++) { 339 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, 340 ICP_SCSI_CHAN_CNT | ICP_L_CTRL_PATTERN, 341 ICP_IO_CHANNEL | ICP_INVALID_CHANNEL, 342 sizeof(*gc))) { 343 printf("%s: unable to get chan info", 344 icp->icp_dv.dv_xname); 345 goto bail_out; 346 } 347 icp->icp_bus_id[j] = gc->gc_scsiid; 348 } 349 } 350 351 for (j = 0; j < binfo.bi_chan_count; j++) { 352 if (icp->icp_bus_id[j] > ICP_MAXID_FC) 353 icp->icp_bus_id[j] = ICP_MAXID_FC; 354 355 icpa.icpa_unit = j + ICPA_UNIT_SCSI; 356 config_found_sm(&icp->icp_dv, &icpa, icp_print, 357 icp_submatch); 358 } 359 } 360 361 /* 362 * Attach cache devices. 363 */ 364 if (!nocache) { 365 for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) { 366 if (icp->icp_cdr[j].cd_size == 0) 367 continue; 368 369 icpa.icpa_unit = j; 370 config_found_sm(&icp->icp_dv, &icpa, icp_print, 371 icp_submatch); 372 } 373 } 374 375 /* 376 * Start the watchdog. 377 */ 378 icp_watchdog(icp); 379 return (0); 380 381 bail_out: 382 if (state > 4) 383 for (j = 0; j < i; j++) 384 bus_dmamap_destroy(icp->icp_dmat, 385 icp->icp_ccbs[j].ic_xfer_map); 386 if (state > 3) 387 free(icp->icp_ccbs, M_DEVBUF); 388 if (state > 2) 389 bus_dmamap_unload(icp->icp_dmat, icp->icp_scr_dmamap); 390 if (state > 1) 391 bus_dmamem_unmap(icp->icp_dmat, icp->icp_scr, 392 ICP_SCRATCH_SIZE); 393 if (state > 0) 394 bus_dmamem_free(icp->icp_dmat, icp->icp_scr_seg, nsegs); 395 bus_dmamap_destroy(icp->icp_dmat, icp->icp_scr_dmamap); 396 397 return (1); 398 } 399 400 void 401 icp_watchdog(void *cookie) 402 { 403 struct icp_softc *icp; 404 int s; 405 406 icp = cookie; 407 408 s = splbio(); 409 icp_intr(icp); 410 if (SIMPLEQ_FIRST(&icp->icp_ccb_queue) != NULL) 411 icp_ccb_enqueue(icp, NULL); 412 splx(s); 413 414 callout_reset(&icp->icp_wdog_callout, hz * ICP_WATCHDOG_FREQ, 415 icp_watchdog, icp); 416 } 417 418 int 419 icp_print(void *aux, const char *pnp) 420 { 421 struct icp_attach_args *icpa; 422 const char *str; 423 424 icpa = (struct icp_attach_args *)aux; 425 426 if (pnp != NULL) { 427 if (icpa->icpa_unit < ICPA_UNIT_SCSI) 428 str = "block device"; 429 else 430 str = "SCSI channel"; 431 printf("%s at %s", str, pnp); 432 } 433 printf(" unit %d", icpa->icpa_unit); 434 435 return (UNCONF); 436 } 437 438 int 439 icp_submatch(struct device *parent, struct cfdata *cf, void *aux) 440 { 441 struct icp_attach_args *icpa; 442 443 icpa = (struct icp_attach_args *)aux; 444 445 if (cf->icpacf_unit != ICPCF_UNIT_DEFAULT && 446 cf->icpacf_unit != icpa->icpa_unit) 447 return (0); 448 449 return ((*cf->cf_attach->ca_match)(parent, cf, aux)); 450 } 451 452 int 453 icp_async_event(struct icp_softc *icp, int val) 454 { 455 456 /* XXX */ 457 return (1); 458 } 459 460 int 461 icp_intr(void *cookie) 462 { 463 struct icp_softc *icp; 464 struct icp_intr_ctx ctx; 465 struct icp_ccb *ic; 466 467 icp = cookie; 468 469 ctx.istatus = (*icp->icp_get_status)(icp); 470 if (!ctx.istatus) { 471 icp->icp_status = ICP_S_NO_STATUS; 472 return (0); 473 } 474 475 (*icp->icp_intr)(icp, &ctx); 476 477 icp->icp_status = ctx.cmd_status; 478 icp->icp_info = ctx.info; 479 icp->icp_info2 = ctx.info2; 480 481 switch (ctx.istatus) { 482 case ICP_ASYNCINDEX: 483 icp_async_event(icp, ctx.service); 484 return (1); 485 486 case ICP_SPEZINDEX: 487 printf("%s: uninitialized or unknown service (%d/%d)\n", 488 icp->icp_dv.dv_xname, ctx.info, ctx.info2); 489 return (1); 490 } 491 492 if ((ctx.istatus - 2) > icp->icp_nccbs) 493 panic("icp_intr: bad command index returned"); 494 495 ic = &icp->icp_ccbs[ctx.istatus - 2]; 496 ic->ic_status = icp->icp_status; 497 498 if ((ic->ic_flags & IC_ALLOCED) == 0) 499 panic("icp_intr: inactive CCB identified"); 500 501 switch (icp->icp_status) { 502 case ICP_S_BSY: 503 #ifdef ICP_DEBUG 504 printf("%s: ICP_S_BSY received\n", icp->icp_dv.dv_xname); 505 #endif 506 SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_queue, ic, ic_chain); 507 break; 508 509 default: 510 ic->ic_flags |= IC_COMPLETE; 511 512 if ((ic->ic_flags & IC_WAITING) != 0) 513 wakeup(ic); 514 else if (ic->ic_intr != NULL) 515 (*ic->ic_intr)(ic); 516 517 if (SIMPLEQ_FIRST(&icp->icp_ccb_queue) != NULL) 518 icp_ccb_enqueue(icp, NULL); 519 520 break; 521 } 522 523 return (1); 524 } 525 526 int 527 icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode, 528 u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) 529 { 530 struct icp_ioctlcmd *icmd; 531 struct icp_cachecmd *cc; 532 struct icp_rawcmd *rc; 533 int retries, rv; 534 struct icp_ccb *ic; 535 536 retries = ICP_RETRIES; 537 538 do { 539 ic = icp_ccb_alloc(icp); 540 memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd)); 541 ic->ic_cmd.cmd_opcode = htole16(opcode); 542 543 switch (service) { 544 case ICP_CACHESERVICE: 545 if (opcode == ICP_IOCTL) { 546 icmd = &ic->ic_cmd.cmd_packet.ic; 547 icmd->ic_subfunc = htole16(arg1); 548 icmd->ic_channel = htole32(arg2); 549 icmd->ic_bufsize = htole32(arg3); 550 icmd->ic_addr = 551 htole32(icp->icp_scr_seg[0].ds_addr); 552 553 bus_dmamap_sync(icp->icp_dmat, 554 icp->icp_scr_dmamap, 0, arg3, 555 BUS_DMASYNC_PREWRITE | 556 BUS_DMASYNC_PREREAD); 557 } else { 558 cc = &ic->ic_cmd.cmd_packet.cc; 559 cc->cc_deviceno = htole16(arg1); 560 cc->cc_blockno = htole32(arg2); 561 } 562 break; 563 564 case ICP_SCSIRAWSERVICE: 565 rc = &ic->ic_cmd.cmd_packet.rc; 566 rc->rc_direction = htole32(arg1); 567 rc->rc_bus = arg2; 568 rc->rc_target = arg3; 569 rc->rc_lun = arg3 >> 8; 570 break; 571 } 572 573 ic->ic_service = service; 574 ic->ic_cmdlen = sizeof(ic->ic_cmd); 575 rv = icp_ccb_poll(icp, ic, 10000); 576 577 switch (service) { 578 case ICP_CACHESERVICE: 579 if (opcode == ICP_IOCTL) { 580 bus_dmamap_sync(icp->icp_dmat, 581 icp->icp_scr_dmamap, 0, arg3, 582 BUS_DMASYNC_POSTWRITE | 583 BUS_DMASYNC_POSTREAD); 584 } 585 break; 586 } 587 588 icp_ccb_free(icp, ic); 589 } while (rv != 0 && --retries > 0); 590 591 return (icp->icp_status == ICP_S_OK); 592 } 593 594 struct icp_ccb * 595 icp_ccb_alloc(struct icp_softc *icp) 596 { 597 struct icp_ccb *ic; 598 int s; 599 600 s = splbio(); 601 ic = SIMPLEQ_FIRST(&icp->icp_ccb_freelist); 602 SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic, ic_chain); 603 splx(s); 604 605 ic->ic_flags = IC_ALLOCED; 606 return (ic); 607 } 608 609 void 610 icp_ccb_free(struct icp_softc *icp, struct icp_ccb *ic) 611 { 612 int s; 613 614 s = splbio(); 615 ic->ic_flags = 0; 616 ic->ic_intr = NULL; 617 SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_freelist, ic, ic_chain); 618 splx(s); 619 } 620 621 void 622 icp_ccb_enqueue(struct icp_softc *icp, struct icp_ccb *ic) 623 { 624 int s; 625 626 s = splbio(); 627 628 if (ic != NULL) 629 SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain); 630 631 while ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_queue)) != NULL) { 632 if ((*icp->icp_test_busy)(icp)) 633 break; 634 icp_ccb_submit(icp, ic); 635 SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_queue, ic, ic_chain); 636 } 637 638 splx(s); 639 } 640 641 int 642 icp_ccb_map(struct icp_softc *icp, struct icp_ccb *ic, void *data, int size, 643 int dir) 644 { 645 struct icp_sg *sg; 646 int nsegs, i, rv; 647 bus_dmamap_t xfer; 648 649 xfer = ic->ic_xfer_map; 650 651 rv = bus_dmamap_load(icp->icp_dmat, xfer, data, size, NULL, 652 BUS_DMA_NOWAIT | BUS_DMA_STREAMING | 653 ((dir & IC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE)); 654 if (rv != 0) 655 return (rv); 656 657 nsegs = xfer->dm_nsegs; 658 ic->ic_xfer_size = size; 659 ic->ic_nsgent = nsegs; 660 ic->ic_flags |= dir; 661 sg = ic->ic_sg; 662 663 if (sg != NULL) { 664 for (i = 0; i < nsegs; i++, sg++) { 665 sg->sg_addr = htole32(xfer->dm_segs[i].ds_addr); 666 sg->sg_len = htole32(xfer->dm_segs[i].ds_len); 667 } 668 } else if (nsegs > 1) 669 panic("icp_ccb_map: no SG list specified, but nsegs > 1\n"); 670 671 if ((dir & IC_XFER_OUT) != 0) 672 i = BUS_DMASYNC_PREWRITE; 673 else /* if ((dir & IC_XFER_IN) != 0) */ 674 i = BUS_DMASYNC_PREREAD; 675 676 bus_dmamap_sync(icp->icp_dmat, xfer, 0, ic->ic_xfer_size, i); 677 return (0); 678 } 679 680 void 681 icp_ccb_unmap(struct icp_softc *icp, struct icp_ccb *ic) 682 { 683 int i; 684 685 if ((ic->ic_flags & IC_XFER_OUT) != 0) 686 i = BUS_DMASYNC_POSTWRITE; 687 else /* if ((ic->ic_flags & IC_XFER_IN) != 0) */ 688 i = BUS_DMASYNC_POSTREAD; 689 690 bus_dmamap_sync(icp->icp_dmat, ic->ic_xfer_map, 0, ic->ic_xfer_size, i); 691 bus_dmamap_unload(icp->icp_dmat, ic->ic_xfer_map); 692 } 693 694 int 695 icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo) 696 { 697 int rv; 698 699 for (timo = ICP_BUSY_WAIT_MS * 100; timo != 0; timo--) { 700 if (!(*icp->icp_test_busy)(icp)) 701 break; 702 DELAY(10); 703 } 704 if (timo == 0) { 705 printf("%s: submit: busy\n", icp->icp_dv.dv_xname); 706 return (EAGAIN); 707 } 708 709 icp_ccb_submit(icp, ic); 710 711 for (timo *= 10; timo != 0; timo--) { 712 DELAY(100); 713 icp_intr(icp); 714 if ((ic->ic_flags & IC_COMPLETE) != 0) 715 break; 716 } 717 718 if (timo != 0) { 719 if (ic->ic_status != ICP_S_OK) { 720 #ifdef ICP_DEBUG 721 printf("%s: request failed; status=0x%04x\n", 722 icp->icp_dv.dv_xname, ic->ic_status); 723 #endif 724 rv = EIO; 725 } else 726 rv = 0; 727 } else { 728 printf("%s: command timed out\n", icp->icp_dv.dv_xname); 729 rv = EIO; 730 } 731 732 while ((*icp->icp_test_busy)(icp) != 0) 733 DELAY(10); 734 735 return (rv); 736 } 737 738 int 739 icp_ccb_wait(struct icp_softc *icp, struct icp_ccb *ic, int timo) 740 { 741 int s, rv; 742 743 ic->ic_flags |= IC_WAITING; 744 745 s = splbio(); 746 icp_ccb_enqueue(icp, ic); 747 if ((rv = tsleep(ic, PRIBIO, "icpwccb", mstohz(timo))) != 0) { 748 splx(s); 749 return (rv); 750 } 751 splx(s); 752 753 if (ic->ic_status != ICP_S_OK) { 754 printf("%s: command failed; status=%x\n", icp->icp_dv.dv_xname, 755 ic->ic_status); 756 return (EIO); 757 } 758 759 return (0); 760 } 761 762 void 763 icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic) 764 { 765 766 ic->ic_cmdlen = (ic->ic_cmdlen + 3) & ~3; 767 768 (*icp->icp_set_sema0)(icp); 769 DELAY(10); 770 771 ic->ic_cmd.cmd_boardnode = htole32(ICP_LOCALBOARD); 772 ic->ic_cmd.cmd_cmdindex = htole32(ic->ic_ident); 773 774 (*icp->icp_copy_cmd)(icp, ic); 775 (*icp->icp_release_event)(icp, ic); 776 } 777