1 /* $NetBSD: mlx_pci.c,v 1.25 2014/03/29 19:28:25 christos 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.25 2014/03/29 19:28:25 christos 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(device_t, device_t, void *); 86 static int mlx_pci_match(device_t, cfdata_t, 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_NEW(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(device_t parent, cfdata_t cfdata, void *aux) 182 { 183 184 return (mlx_pci_findmpi(aux) != NULL); 185 } 186 187 /* 188 * Attach a supported board. 189 */ 190 static void 191 mlx_pci_attach(device_t parent, device_t self, void *aux) 192 { 193 struct pci_attach_args *pa; 194 struct mlx_softc *mlx; 195 pci_chipset_tag_t pc; 196 pci_intr_handle_t ih; 197 bus_space_handle_t memh, ioh; 198 bus_space_tag_t memt, iot; 199 pcireg_t reg; 200 const char *intrstr; 201 int ior, memr, i; 202 const struct mlx_pci_ident *mpi; 203 char intrbuf[PCI_INTRSTR_LEN]; 204 205 mlx = device_private(self); 206 pa = aux; 207 pc = pa->pa_pc; 208 mpi = mlx_pci_findmpi(aux); 209 210 mlx->mlx_dv = self; 211 mlx->mlx_dmat = pa->pa_dmat; 212 mlx->mlx_ci.ci_iftype = mpi->mpi_iftype; 213 214 printf(": Mylex RAID (v%d interface)\n", mpi->mpi_iftype); 215 216 /* 217 * Map the PCI register window. 218 */ 219 memr = -1; 220 ior = -1; 221 222 for (i = 0x10; i <= 0x14; i += 4) { 223 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i); 224 225 if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) { 226 if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0) 227 ior = i; 228 } else { 229 if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0) 230 memr = i; 231 } 232 } 233 234 if (memr != -1) 235 if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0, 236 &memt, &memh, NULL, NULL)) 237 memr = -1; 238 if (ior != -1) 239 if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0, 240 &iot, &ioh, NULL, NULL)) 241 ior = -1; 242 243 if (memr != -1) { 244 mlx->mlx_iot = memt; 245 mlx->mlx_ioh = memh; 246 } else if (ior != -1) { 247 mlx->mlx_iot = iot; 248 mlx->mlx_ioh = ioh; 249 } else { 250 aprint_error_dev(self, "can't map i/o or memory space\n"); 251 return; 252 } 253 254 /* Enable the device. */ 255 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 256 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 257 reg | PCI_COMMAND_MASTER_ENABLE); 258 259 /* Map and establish the interrupt. */ 260 if (pci_intr_map(pa, &ih)) { 261 aprint_error_dev(self, "can't map interrupt\n"); 262 return; 263 } 264 intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf)); 265 mlx->mlx_ih = pci_intr_establish(pc, ih, IPL_BIO, mlx_intr, mlx); 266 if (mlx->mlx_ih == NULL) { 267 aprint_error_dev(self, "can't establish interrupt"); 268 if (intrstr != NULL) 269 aprint_error(" at %s", intrstr); 270 aprint_error("\n"); 271 return; 272 } 273 274 /* Select linkage based on controller interface type. */ 275 switch (mlx->mlx_ci.ci_iftype) { 276 case 2: 277 case 3: 278 mlx->mlx_submit = mlx_v3_submit; 279 mlx->mlx_findcomplete = mlx_v3_findcomplete; 280 mlx->mlx_intaction = mlx_v3_intaction; 281 mlx->mlx_fw_handshake = mlx_v3_fw_handshake; 282 #ifdef MLX_RESET 283 mlx->mlx_reset = mlx_v3_reset; 284 #endif 285 break; 286 287 case 4: 288 mlx->mlx_submit = mlx_v4_submit; 289 mlx->mlx_findcomplete = mlx_v4_findcomplete; 290 mlx->mlx_intaction = mlx_v4_intaction; 291 mlx->mlx_fw_handshake = mlx_v4_fw_handshake; 292 break; 293 294 case 5: 295 mlx->mlx_submit = mlx_v5_submit; 296 mlx->mlx_findcomplete = mlx_v5_findcomplete; 297 mlx->mlx_intaction = mlx_v5_intaction; 298 mlx->mlx_fw_handshake = mlx_v5_fw_handshake; 299 break; 300 } 301 302 mlx_init(mlx, intrstr); 303 } 304 305 /* 306 * ================= V3 interface linkage ================= 307 */ 308 309 /* 310 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 311 * failure (the controller is not ready to take a command). 312 * 313 * Must be called at splbio or in a fashion that prevents reentry. 314 */ 315 static int 316 mlx_v3_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 317 { 318 319 /* Ready for our command? */ 320 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_FULL) == 0) { 321 /* Copy mailbox data to window. */ 322 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 323 MLX_V3REG_MAILBOX, mc->mc_mbox, 13); 324 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 325 MLX_V3REG_MAILBOX, 13, 326 BUS_SPACE_BARRIER_WRITE); 327 328 /* Post command. */ 329 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_FULL); 330 return (1); 331 } 332 333 return (0); 334 } 335 336 /* 337 * See if a command has been completed, if so acknowledge its completion and 338 * recover the slot number and status code. 339 * 340 * Must be called at splbio or in a fashion that prevents reentry. 341 */ 342 static int 343 mlx_v3_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 344 { 345 346 /* Status available? */ 347 if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) { 348 *slot = mlx_inb(mlx, MLX_V3REG_STATUS_IDENT); 349 *status = mlx_inw(mlx, MLX_V3REG_STATUS); 350 351 /* Acknowledge completion. */ 352 mlx_outb(mlx, MLX_V3REG_ODB, MLX_V3_ODB_SAVAIL); 353 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 354 return (1); 355 } 356 357 return (0); 358 } 359 360 /* 361 * Enable/disable interrupts as requested. (No acknowledge required) 362 * 363 * Must be called at splbio or in a fashion that prevents reentry. 364 */ 365 static void 366 mlx_v3_intaction(struct mlx_softc *mlx, int action) 367 { 368 369 mlx_outb(mlx, MLX_V3REG_IE, action != 0); 370 } 371 372 /* 373 * Poll for firmware error codes during controller initialisation. 374 * 375 * Returns 0 if initialisation is complete, 1 if still in progress but no 376 * error has been fetched, 2 if an error has been retrieved. 377 */ 378 static int 379 mlx_v3_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 380 { 381 u_int8_t fwerror; 382 383 /* First time around, clear any hardware completion status. */ 384 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 385 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 386 DELAY(1000); 387 mlx->mlx_flags |= MLXF_FW_INITTED; 388 } 389 390 /* Init in progress? */ 391 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_INIT_BUSY) == 0) 392 return (0); 393 394 /* Test error value. */ 395 fwerror = mlx_inb(mlx, MLX_V3REG_FWERROR); 396 397 if ((fwerror & MLX_V3_FWERROR_PEND) == 0) 398 return (1); 399 400 /* Mask status pending bit, fetch status. */ 401 *error = fwerror & ~MLX_V3_FWERROR_PEND; 402 *param1 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM1); 403 *param2 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM2); 404 405 /* Acknowledge. */ 406 mlx_outb(mlx, MLX_V3REG_FWERROR, 0); 407 408 return (2); 409 } 410 411 #ifdef MLX_RESET 412 /* 413 * Reset the controller. Return non-zero on failure. 414 */ 415 static int 416 mlx_v3_reset(struct mlx_softc *mlx) 417 { 418 int i; 419 420 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 421 delay(1000000); 422 423 /* Wait up to 2 minutes for the bit to clear. */ 424 for (i = 120; i != 0; i--) { 425 delay(1000000); 426 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_SACK) == 0) 427 break; 428 } 429 if (i == 0) { 430 /* ZZZ */ 431 printf("mlx0: SACK didn't clear\n"); 432 return (-1); 433 } 434 435 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_RESET); 436 437 /* Wait up to 5 seconds for the bit to clear. */ 438 for (i = 5; i != 0; i--) { 439 delay(1000000); 440 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_RESET) == 0) 441 break; 442 } 443 if (i == 0) { 444 /* ZZZ */ 445 printf("mlx0: RESET didn't clear\n"); 446 return (-1); 447 } 448 449 return (0); 450 } 451 #endif /* MLX_RESET */ 452 453 /* 454 * ================= V4 interface linkage ================= 455 */ 456 457 /* 458 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 459 * failure (the controller is not ready to take a command). 460 * 461 * Must be called at splbio or in a fashion that prevents reentry. 462 */ 463 static int 464 mlx_v4_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 465 { 466 467 /* Ready for our command? */ 468 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_FULL) == 0) { 469 /* Copy mailbox data to window. */ 470 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 471 MLX_V4REG_MAILBOX, mc->mc_mbox, 13); 472 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 473 MLX_V4REG_MAILBOX, 13, 474 BUS_SPACE_BARRIER_WRITE); 475 476 /* Post command. */ 477 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD); 478 return (1); 479 } 480 481 return (0); 482 } 483 484 /* 485 * See if a command has been completed, if so acknowledge its completion and 486 * recover the slot number and status code. 487 * 488 * Must be called at splbio or in a fashion that prevents reentry. 489 */ 490 static int 491 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 492 { 493 494 /* Status available? */ 495 if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) { 496 *slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT); 497 *status = mlx_inw(mlx, MLX_V4REG_STATUS); 498 499 /* Acknowledge completion. */ 500 mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK); 501 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 502 return (1); 503 } 504 505 return (0); 506 } 507 508 /* 509 * Enable/disable interrupts as requested. 510 * 511 * Must be called at splbio or in a fashion that prevents reentry. 512 */ 513 static void 514 mlx_v4_intaction(struct mlx_softc *mlx, int action) 515 { 516 u_int32_t ier; 517 518 if (!action) 519 ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT; 520 else 521 ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT; 522 523 mlx_outl(mlx, MLX_V4REG_IE, ier); 524 } 525 526 /* 527 * Poll for firmware error codes during controller initialisation. 528 * 529 * Returns 0 if initialisation is complete, 1 if still in progress but no 530 * error has been fetched, 2 if an error has been retrieved. 531 */ 532 static int 533 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 534 { 535 u_int8_t fwerror; 536 537 /* First time around, clear any hardware completion status. */ 538 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 539 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 540 DELAY(1000); 541 mlx->mlx_flags |= MLXF_FW_INITTED; 542 } 543 544 /* Init in progress? */ 545 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0) 546 return (0); 547 548 /* Test error value */ 549 fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR); 550 if ((fwerror & MLX_V4_FWERROR_PEND) == 0) 551 return (1); 552 553 /* Mask status pending bit, fetch status. */ 554 *error = fwerror & ~MLX_V4_FWERROR_PEND; 555 *param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1); 556 *param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2); 557 558 /* Acknowledge. */ 559 mlx_outb(mlx, MLX_V4REG_FWERROR, 0); 560 561 return (2); 562 } 563 564 /* 565 * ================= V5 interface linkage ================= 566 */ 567 568 /* 569 * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure 570 * (the controller is not ready to take a command). 571 * 572 * Must be called at splbio or in a fashion that prevents reentry. 573 */ 574 static int 575 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 576 { 577 578 /* Ready for our command? */ 579 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) { 580 /* Copy mailbox data to window. */ 581 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 582 MLX_V5REG_MAILBOX, mc->mc_mbox, 13); 583 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 584 MLX_V5REG_MAILBOX, 13, 585 BUS_SPACE_BARRIER_WRITE); 586 587 /* Post command */ 588 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD); 589 return (1); 590 } 591 592 return (0); 593 } 594 595 /* 596 * See if a command has been completed, if so acknowledge its completion and 597 * recover the slot number and status code. 598 * 599 * Must be called at splbio or in a fashion that prevents reentry. 600 */ 601 static int 602 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 603 { 604 605 /* Status available? */ 606 if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) { 607 *slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT); 608 *status = mlx_inw(mlx, MLX_V5REG_STATUS); 609 610 /* Acknowledge completion. */ 611 mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK); 612 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 613 return (1); 614 } 615 616 return (0); 617 } 618 619 /* 620 * Enable/disable interrupts as requested. 621 * 622 * Must be called at splbio or in a fashion that prevents reentry. 623 */ 624 static void 625 mlx_v5_intaction(struct mlx_softc *mlx, int action) 626 { 627 u_int8_t ier; 628 629 if (!action) 630 ier = 0xff & MLX_V5_IE_DISINT; 631 else 632 ier = 0xff & ~MLX_V5_IE_DISINT; 633 634 mlx_outb(mlx, MLX_V5REG_IE, ier); 635 } 636 637 /* 638 * Poll for firmware error codes during controller initialisation. 639 * 640 * Returns 0 if initialisation is complete, 1 if still in progress but no 641 * error has been fetched, 2 if an error has been retrieved. 642 */ 643 static int 644 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 645 { 646 u_int8_t fwerror; 647 648 /* First time around, clear any hardware completion status. */ 649 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 650 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 651 DELAY(1000); 652 mlx->mlx_flags |= MLXF_FW_INITTED; 653 } 654 655 /* Init in progress? */ 656 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0) 657 return (0); 658 659 /* Test for error value. */ 660 fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR); 661 if ((fwerror & MLX_V5_FWERROR_PEND) == 0) 662 return (1); 663 664 /* Mask status pending bit, fetch status. */ 665 *error = fwerror & ~MLX_V5_FWERROR_PEND; 666 *param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1); 667 *param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2); 668 669 /* Acknowledge. */ 670 mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff); 671 672 return (2); 673 } 674