1 /* $NetBSD: mlx_pci.c,v 1.11 2002/10/02 16:51:43 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 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 Michael Smith 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * from FreeBSD: mlx_pci.c,v 1.4.2.4 2000/10/28 10:48:09 msmith Exp 65 */ 66 67 /* 68 * PCI front-end for the mlx(4) driver. 69 */ 70 71 #include <sys/cdefs.h> 72 __KERNEL_RCSID(0, "$NetBSD: mlx_pci.c,v 1.11 2002/10/02 16:51:43 thorpej Exp $"); 73 74 #include <sys/param.h> 75 #include <sys/systm.h> 76 #include <sys/kernel.h> 77 #include <sys/device.h> 78 #include <sys/queue.h> 79 #include <sys/callout.h> 80 81 #include <machine/endian.h> 82 #include <machine/bus.h> 83 84 #include <dev/ic/mlxreg.h> 85 #include <dev/ic/mlxio.h> 86 #include <dev/ic/mlxvar.h> 87 88 #include <dev/pci/pcireg.h> 89 #include <dev/pci/pcivar.h> 90 #include <dev/pci/pcidevs.h> 91 92 static void mlx_pci_attach(struct device *, struct device *, void *); 93 static int mlx_pci_match(struct device *, struct cfdata *, void *); 94 static const struct mlx_pci_ident *mlx_pci_findmpi(struct pci_attach_args *); 95 96 static int mlx_v3_submit(struct mlx_softc *, struct mlx_ccb *); 97 static int mlx_v3_findcomplete(struct mlx_softc *, u_int *, u_int *); 98 static void mlx_v3_intaction(struct mlx_softc *, int); 99 static int mlx_v3_fw_handshake(struct mlx_softc *, int *, int *, int *); 100 #ifdef MLX_RESET 101 static int mlx_v3_reset(struct mlx_softc *); 102 #endif 103 104 static int mlx_v4_submit(struct mlx_softc *, struct mlx_ccb *); 105 static int mlx_v4_findcomplete(struct mlx_softc *, u_int *, u_int *); 106 static void mlx_v4_intaction(struct mlx_softc *, int); 107 static int mlx_v4_fw_handshake(struct mlx_softc *, int *, int *, int *); 108 109 static int mlx_v5_submit(struct mlx_softc *, struct mlx_ccb *); 110 static int mlx_v5_findcomplete(struct mlx_softc *, u_int *, u_int *); 111 static void mlx_v5_intaction(struct mlx_softc *, int); 112 static int mlx_v5_fw_handshake(struct mlx_softc *, int *, int *, int *); 113 114 struct mlx_pci_ident { 115 u_short mpi_vendor; 116 u_short mpi_product; 117 u_short mpi_subvendor; 118 u_short mpi_subproduct; 119 int mpi_iftype; 120 } static const mlx_pci_ident[] = { 121 { 122 PCI_VENDOR_MYLEX, 123 PCI_PRODUCT_MYLEX_RAID_V2, 124 0x0000, 125 0x0000, 126 2, 127 }, 128 { 129 PCI_VENDOR_MYLEX, 130 PCI_PRODUCT_MYLEX_RAID_V3, 131 0x0000, 132 0x0000, 133 3, 134 }, 135 { 136 PCI_VENDOR_MYLEX, 137 PCI_PRODUCT_MYLEX_RAID_V4, 138 0x0000, 139 0x0000, 140 4, 141 }, 142 { 143 PCI_VENDOR_DEC, 144 PCI_PRODUCT_DEC_SWXCR, 145 PCI_VENDOR_MYLEX, 146 PCI_PRODUCT_MYLEX_RAID_V5, 147 5, 148 }, 149 }; 150 151 CFATTACH_DECL(mlx_pci, sizeof(struct mlx_softc), 152 mlx_pci_match, mlx_pci_attach, NULL, NULL); 153 154 /* 155 * Try to find a `mlx_pci_ident' entry corresponding to this board. 156 */ 157 static const struct mlx_pci_ident * 158 mlx_pci_findmpi(struct pci_attach_args *pa) 159 { 160 const struct mlx_pci_ident *mpi, *maxmpi; 161 pcireg_t reg; 162 163 mpi = mlx_pci_ident; 164 maxmpi = mpi + sizeof(mlx_pci_ident) / sizeof(mlx_pci_ident[0]); 165 166 for (; mpi < maxmpi; mpi++) { 167 if (PCI_VENDOR(pa->pa_id) != mpi->mpi_vendor || 168 PCI_PRODUCT(pa->pa_id) != mpi->mpi_product) 169 continue; 170 171 if (mpi->mpi_subvendor == 0x0000) 172 return (mpi); 173 174 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 175 176 if (PCI_VENDOR(reg) == mpi->mpi_subvendor && 177 PCI_PRODUCT(reg) == mpi->mpi_subproduct) 178 return (mpi); 179 } 180 181 return (NULL); 182 } 183 184 /* 185 * Match a supported board. 186 */ 187 static int 188 mlx_pci_match(struct device *parent, struct cfdata *cfdata, void *aux) 189 { 190 191 return (mlx_pci_findmpi(aux) != NULL); 192 } 193 194 /* 195 * Attach a supported board. 196 */ 197 static void 198 mlx_pci_attach(struct device *parent, struct device *self, void *aux) 199 { 200 struct pci_attach_args *pa; 201 struct mlx_softc *mlx; 202 pci_chipset_tag_t pc; 203 pci_intr_handle_t ih; 204 bus_space_handle_t memh, ioh; 205 bus_space_tag_t memt, iot; 206 pcireg_t reg; 207 const char *intrstr; 208 int ior, memr, i; 209 const struct mlx_pci_ident *mpi; 210 211 mlx = (struct mlx_softc *)self; 212 pa = aux; 213 pc = pa->pa_pc; 214 mpi = mlx_pci_findmpi(aux); 215 216 mlx->mlx_dmat = pa->pa_dmat; 217 mlx->mlx_ci.ci_iftype = mpi->mpi_iftype; 218 219 printf(": Mylex RAID (v%d interface)\n", mpi->mpi_iftype); 220 221 /* 222 * Map the PCI register window. 223 */ 224 memr = -1; 225 ior = -1; 226 227 for (i = 0x10; i <= 0x14; i += 4) { 228 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i); 229 230 if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) { 231 if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0) 232 ior = i; 233 } else { 234 if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0) 235 memr = i; 236 } 237 } 238 239 if (memr != -1) 240 if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0, 241 &memt, &memh, NULL, NULL)) 242 memr = -1; 243 if (ior != -1) 244 if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0, 245 &iot, &ioh, NULL, NULL)) 246 ior = -1; 247 248 if (memr != -1) { 249 mlx->mlx_iot = memt; 250 mlx->mlx_ioh = memh; 251 } else if (ior != -1) { 252 mlx->mlx_iot = iot; 253 mlx->mlx_ioh = ioh; 254 } else { 255 printf("%s: can't map i/o or memory space\n", self->dv_xname); 256 return; 257 } 258 259 /* Enable the device. */ 260 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 261 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 262 reg | PCI_COMMAND_MASTER_ENABLE); 263 264 /* Map and establish the interrupt. */ 265 if (pci_intr_map(pa, &ih)) { 266 printf("%s: can't map interrupt\n", self->dv_xname); 267 return; 268 } 269 intrstr = pci_intr_string(pc, ih); 270 mlx->mlx_ih = pci_intr_establish(pc, ih, IPL_BIO, mlx_intr, mlx); 271 if (mlx->mlx_ih == NULL) { 272 printf("%s: can't establish interrupt", self->dv_xname); 273 if (intrstr != NULL) 274 printf(" at %s", intrstr); 275 printf("\n"); 276 return; 277 } 278 279 /* Select linkage based on controller interface type. */ 280 switch (mlx->mlx_ci.ci_iftype) { 281 case 2: 282 case 3: 283 mlx->mlx_submit = mlx_v3_submit; 284 mlx->mlx_findcomplete = mlx_v3_findcomplete; 285 mlx->mlx_intaction = mlx_v3_intaction; 286 mlx->mlx_fw_handshake = mlx_v3_fw_handshake; 287 #ifdef MLX_RESET 288 mlx->mlx_reset = mlx_v3_reset; 289 #endif 290 break; 291 292 case 4: 293 mlx->mlx_submit = mlx_v4_submit; 294 mlx->mlx_findcomplete = mlx_v4_findcomplete; 295 mlx->mlx_intaction = mlx_v4_intaction; 296 mlx->mlx_fw_handshake = mlx_v4_fw_handshake; 297 break; 298 299 case 5: 300 mlx->mlx_submit = mlx_v5_submit; 301 mlx->mlx_findcomplete = mlx_v5_findcomplete; 302 mlx->mlx_intaction = mlx_v5_intaction; 303 mlx->mlx_fw_handshake = mlx_v5_fw_handshake; 304 break; 305 } 306 307 mlx_init(mlx, intrstr); 308 } 309 310 /* 311 * ================= V3 interface linkage ================= 312 */ 313 314 /* 315 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 316 * failure (the controller is not ready to take a command). 317 * 318 * Must be called at splbio or in a fashion that prevents reentry. 319 */ 320 static int 321 mlx_v3_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 322 { 323 324 /* Ready for our command? */ 325 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_FULL) == 0) { 326 /* Copy mailbox data to window. */ 327 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 328 MLX_V3REG_MAILBOX, mc->mc_mbox, 13); 329 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 330 MLX_V3REG_MAILBOX, 13, 331 BUS_SPACE_BARRIER_WRITE); 332 333 /* Post command. */ 334 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_FULL); 335 return (1); 336 } 337 338 return (0); 339 } 340 341 /* 342 * See if a command has been completed, if so acknowledge its completion and 343 * recover the slot number and status code. 344 * 345 * Must be called at splbio or in a fashion that prevents reentry. 346 */ 347 static int 348 mlx_v3_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 349 { 350 351 /* Status available? */ 352 if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) { 353 *slot = mlx_inb(mlx, MLX_V3REG_STATUS_IDENT); 354 *status = mlx_inw(mlx, MLX_V3REG_STATUS); 355 356 /* Acknowledge completion. */ 357 mlx_outb(mlx, MLX_V3REG_ODB, MLX_V3_ODB_SAVAIL); 358 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 359 return (1); 360 } 361 362 return (0); 363 } 364 365 /* 366 * Enable/disable interrupts as requested. (No acknowledge required) 367 * 368 * Must be called at splbio or in a fashion that prevents reentry. 369 */ 370 static void 371 mlx_v3_intaction(struct mlx_softc *mlx, int action) 372 { 373 374 mlx_outb(mlx, MLX_V3REG_IE, action != 0); 375 } 376 377 /* 378 * Poll for firmware error codes during controller initialisation. 379 * 380 * Returns 0 if initialisation is complete, 1 if still in progress but no 381 * error has been fetched, 2 if an error has been retrieved. 382 */ 383 static int 384 mlx_v3_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 385 { 386 u_int8_t fwerror; 387 388 /* First time around, clear any hardware completion status. */ 389 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 390 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 391 DELAY(1000); 392 mlx->mlx_flags |= MLXF_FW_INITTED; 393 } 394 395 /* Init in progress? */ 396 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_INIT_BUSY) == 0) 397 return (0); 398 399 /* Test error value. */ 400 fwerror = mlx_inb(mlx, MLX_V3REG_FWERROR); 401 402 if ((fwerror & MLX_V3_FWERROR_PEND) == 0) 403 return (1); 404 405 /* Mask status pending bit, fetch status. */ 406 *error = fwerror & ~MLX_V3_FWERROR_PEND; 407 *param1 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM1); 408 *param2 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM2); 409 410 /* Acknowledge. */ 411 mlx_outb(mlx, MLX_V3REG_FWERROR, 0); 412 413 return (2); 414 } 415 416 #ifdef MLX_RESET 417 /* 418 * Reset the controller. Return non-zero on failure. 419 */ 420 static int 421 mlx_v3_reset(struct mlx_softc *mlx) 422 { 423 int i; 424 425 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 426 delay(1000000); 427 428 /* Wait up to 2 minutes for the bit to clear. */ 429 for (i = 120; i != 0; i--) { 430 delay(1000000); 431 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_SACK) == 0) 432 break; 433 } 434 if (i == 0) { 435 /* ZZZ */ 436 printf("mlx0: SACK didn't clear\n"); 437 return (-1); 438 } 439 440 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_RESET); 441 442 /* Wait up to 5 seconds for the bit to clear. */ 443 for (i = 5; i != 0; i--) { 444 delay(1000000); 445 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_RESET) == 0) 446 break; 447 } 448 if (i == 0) { 449 /* ZZZ */ 450 printf("mlx0: RESET didn't clear\n"); 451 return (-1); 452 } 453 454 return (0); 455 } 456 #endif /* MLX_RESET */ 457 458 /* 459 * ================= V4 interface linkage ================= 460 */ 461 462 /* 463 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 464 * failure (the controller is not ready to take a command). 465 * 466 * Must be called at splbio or in a fashion that prevents reentry. 467 */ 468 static int 469 mlx_v4_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 470 { 471 472 /* Ready for our command? */ 473 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_FULL) == 0) { 474 /* Copy mailbox data to window. */ 475 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 476 MLX_V4REG_MAILBOX, mc->mc_mbox, 13); 477 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 478 MLX_V4REG_MAILBOX, 13, 479 BUS_SPACE_BARRIER_WRITE); 480 481 /* Post command. */ 482 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD); 483 return (1); 484 } 485 486 return (0); 487 } 488 489 /* 490 * See if a command has been completed, if so acknowledge its completion and 491 * recover the slot number and status code. 492 * 493 * Must be called at splbio or in a fashion that prevents reentry. 494 */ 495 static int 496 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 497 { 498 499 /* Status available? */ 500 if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) { 501 *slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT); 502 *status = mlx_inw(mlx, MLX_V4REG_STATUS); 503 504 /* Acknowledge completion. */ 505 mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK); 506 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 507 return (1); 508 } 509 510 return (0); 511 } 512 513 /* 514 * Enable/disable interrupts as requested. 515 * 516 * Must be called at splbio or in a fashion that prevents reentry. 517 */ 518 static void 519 mlx_v4_intaction(struct mlx_softc *mlx, int action) 520 { 521 u_int32_t ier; 522 523 if (!action) 524 ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT; 525 else 526 ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT; 527 528 mlx_outl(mlx, MLX_V4REG_IE, ier); 529 } 530 531 /* 532 * Poll for firmware error codes during controller initialisation. 533 * 534 * Returns 0 if initialisation is complete, 1 if still in progress but no 535 * error has been fetched, 2 if an error has been retrieved. 536 */ 537 static int 538 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 539 { 540 u_int8_t fwerror; 541 542 /* First time around, clear any hardware completion status. */ 543 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 544 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 545 DELAY(1000); 546 mlx->mlx_flags |= MLXF_FW_INITTED; 547 } 548 549 /* Init in progress? */ 550 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0) 551 return (0); 552 553 /* Test error value */ 554 fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR); 555 if ((fwerror & MLX_V4_FWERROR_PEND) == 0) 556 return (1); 557 558 /* Mask status pending bit, fetch status. */ 559 *error = fwerror & ~MLX_V4_FWERROR_PEND; 560 *param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1); 561 *param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2); 562 563 /* Acknowledge. */ 564 mlx_outb(mlx, MLX_V4REG_FWERROR, 0); 565 566 return (2); 567 } 568 569 /* 570 * ================= V5 interface linkage ================= 571 */ 572 573 /* 574 * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure 575 * (the controller is not ready to take a command). 576 * 577 * Must be called at splbio or in a fashion that prevents reentry. 578 */ 579 static int 580 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 581 { 582 583 /* Ready for our command? */ 584 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) { 585 /* Copy mailbox data to window. */ 586 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 587 MLX_V5REG_MAILBOX, mc->mc_mbox, 13); 588 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 589 MLX_V5REG_MAILBOX, 13, 590 BUS_SPACE_BARRIER_WRITE); 591 592 /* Post command */ 593 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD); 594 return (1); 595 } 596 597 return (0); 598 } 599 600 /* 601 * See if a command has been completed, if so acknowledge its completion and 602 * recover the slot number and status code. 603 * 604 * Must be called at splbio or in a fashion that prevents reentry. 605 */ 606 static int 607 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 608 { 609 610 /* Status available? */ 611 if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) { 612 *slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT); 613 *status = mlx_inw(mlx, MLX_V5REG_STATUS); 614 615 /* Acknowledge completion. */ 616 mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK); 617 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 618 return (1); 619 } 620 621 return (0); 622 } 623 624 /* 625 * Enable/disable interrupts as requested. 626 * 627 * Must be called at splbio or in a fashion that prevents reentry. 628 */ 629 static void 630 mlx_v5_intaction(struct mlx_softc *mlx, int action) 631 { 632 u_int8_t ier; 633 634 if (!action) 635 ier = 0xff & MLX_V5_IE_DISINT; 636 else 637 ier = 0xff & ~MLX_V5_IE_DISINT; 638 639 mlx_outb(mlx, MLX_V5REG_IE, ier); 640 } 641 642 /* 643 * Poll for firmware error codes during controller initialisation. 644 * 645 * Returns 0 if initialisation is complete, 1 if still in progress but no 646 * error has been fetched, 2 if an error has been retrieved. 647 */ 648 static int 649 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 650 { 651 u_int8_t fwerror; 652 653 /* First time around, clear any hardware completion status. */ 654 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 655 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 656 DELAY(1000); 657 mlx->mlx_flags |= MLXF_FW_INITTED; 658 } 659 660 /* Init in progress? */ 661 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0) 662 return (0); 663 664 /* Test for error value. */ 665 fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR); 666 if ((fwerror & MLX_V5_FWERROR_PEND) == 0) 667 return (1); 668 669 /* Mask status pending bit, fetch status. */ 670 *error = fwerror & ~MLX_V5_FWERROR_PEND; 671 *param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1); 672 *param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2); 673 674 /* Acknowledge. */ 675 mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff); 676 677 return (2); 678 } 679