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