1 /* $NetBSD: mlx_pci.c,v 1.2 2001/02/18 21:02:54 mjacob 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/param.h> 72 #include <sys/systm.h> 73 #include <sys/kernel.h> 74 #include <sys/device.h> 75 #include <sys/queue.h> 76 #include <sys/callout.h> 77 78 #include <machine/endian.h> 79 #include <machine/bus.h> 80 81 #include <dev/ic/mlxreg.h> 82 #include <dev/ic/mlxio.h> 83 #include <dev/ic/mlxvar.h> 84 85 #include <dev/pci/pcireg.h> 86 #include <dev/pci/pcivar.h> 87 #include <dev/pci/pcidevs.h> 88 89 static void mlx_pci_attach(struct device *, struct device *, void *); 90 static int mlx_pci_match(struct device *, struct cfdata *, void *); 91 static const struct mlx_pci_ident *mlx_pci_findmpi(struct pci_attach_args *); 92 93 static int mlx_v3_submit(struct mlx_softc *, struct mlx_ccb *); 94 static int mlx_v3_findcomplete(struct mlx_softc *, u_int *, u_int *); 95 static void mlx_v3_intaction(struct mlx_softc *, int); 96 static int mlx_v3_fw_handshake(struct mlx_softc *, int *, int *, int *); 97 98 static int mlx_v4_submit(struct mlx_softc *, struct mlx_ccb *); 99 static int mlx_v4_findcomplete(struct mlx_softc *, u_int *, u_int *); 100 static void mlx_v4_intaction(struct mlx_softc *, int); 101 static int mlx_v4_fw_handshake(struct mlx_softc *, int *, int *, int *); 102 103 static int mlx_v5_submit(struct mlx_softc *, struct mlx_ccb *); 104 static int mlx_v5_findcomplete(struct mlx_softc *, u_int *, u_int *); 105 static void mlx_v5_intaction(struct mlx_softc *, int); 106 static int mlx_v5_fw_handshake(struct mlx_softc *, int *, int *, int *); 107 108 struct mlx_pci_ident { 109 u_short mpi_vendor; 110 u_short mpi_product; 111 u_short mpi_subvendor; 112 u_short mpi_subproduct; 113 int mpi_iftype; 114 } static const mlx_pci_ident[] = { 115 { 116 PCI_VENDOR_MYLEX, 117 PCI_PRODUCT_MYLEX_RAID_V2, 118 0x0000, 119 0x0000, 120 2, 121 }, 122 { 123 PCI_VENDOR_MYLEX, 124 PCI_PRODUCT_MYLEX_RAID_V3, 125 0x0000, 126 0x0000, 127 3, 128 }, 129 { 130 PCI_VENDOR_MYLEX, 131 PCI_PRODUCT_MYLEX_RAID_V4, 132 0x0000, 133 0x0000, 134 4, 135 }, 136 { 137 PCI_VENDOR_DEC, 138 PCI_PRODUCT_DEC_SWXCR, 139 PCI_VENDOR_MYLEX, 140 PCI_PRODUCT_MYLEX_RAID_V5, 141 5, 142 }, 143 }; 144 145 struct cfattach mlx_pci_ca = { 146 sizeof(struct mlx_softc), mlx_pci_match, mlx_pci_attach 147 }; 148 149 /* 150 * Try to find a `mlx_pci_ident' entry corresponding to this board. 151 */ 152 static const struct mlx_pci_ident * 153 mlx_pci_findmpi(struct pci_attach_args *pa) 154 { 155 const struct mlx_pci_ident *mpi, *maxmpi; 156 pcireg_t reg; 157 158 mpi = mlx_pci_ident; 159 maxmpi = mpi + sizeof(mlx_pci_ident) / sizeof(mlx_pci_ident[0]); 160 161 for (; mpi < maxmpi; mpi++) { 162 if (PCI_VENDOR(pa->pa_id) != mpi->mpi_vendor || 163 PCI_PRODUCT(pa->pa_id) != mpi->mpi_product) 164 continue; 165 166 if (mpi->mpi_subvendor == 0x0000) 167 return (mpi); 168 169 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); 170 171 if (PCI_VENDOR(reg) == mpi->mpi_subvendor && 172 PCI_PRODUCT(reg) == mpi->mpi_subproduct) 173 return (mpi); 174 } 175 176 return (NULL); 177 } 178 179 /* 180 * Match a supported board. 181 */ 182 static int 183 mlx_pci_match(struct device *parent, struct cfdata *cfdata, void *aux) 184 { 185 186 return (mlx_pci_findmpi(aux) != NULL); 187 } 188 189 /* 190 * Attach a supported board. 191 */ 192 static void 193 mlx_pci_attach(struct device *parent, struct device *self, void *aux) 194 { 195 struct pci_attach_args *pa; 196 struct mlx_softc *mlx; 197 pci_chipset_tag_t pc; 198 pci_intr_handle_t ih; 199 pcireg_t reg; 200 const char *intrstr; 201 int ior, memr, i; 202 const struct mlx_pci_ident *mpi; 203 204 mlx = (struct mlx_softc *)self; 205 pa = aux; 206 pc = pa->pa_pc; 207 mpi = mlx_pci_findmpi(aux); 208 209 mlx->mlx_dmat = pa->pa_dmat; 210 mlx->mlx_iftype = mpi->mpi_iftype; 211 212 printf(": Mylex RAID (v%d interface)\n", mpi->mpi_iftype); 213 214 /* 215 * Map the PCI register window. 216 */ 217 memr = -1; 218 ior = -1; 219 220 for (i = 0x10; i <= 0x14; i += 4) { 221 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, i); 222 223 if (PCI_MAPREG_TYPE(reg) == PCI_MAPREG_TYPE_IO) { 224 if (ior == -1 && PCI_MAPREG_IO_SIZE(reg) != 0) 225 ior = i; 226 } else { 227 if (memr == -1 && PCI_MAPREG_MEM_SIZE(reg) != 0) 228 memr = i; 229 } 230 } 231 232 if (memr != -1) 233 if (pci_mapreg_map(pa, memr, PCI_MAPREG_TYPE_MEM, 0, 234 &mlx->mlx_iot, &mlx->mlx_ioh, NULL, NULL)) 235 memr = -1; 236 if (ior != -1) 237 if (pci_mapreg_map(pa, ior, PCI_MAPREG_TYPE_IO, 0, 238 &mlx->mlx_iot, &mlx->mlx_ioh, NULL, NULL)) 239 ior = -1; 240 if (memr == -1 && ior == -1) { 241 printf("%s: can't map i/o or memory space\n", self->dv_xname); 242 return; 243 } 244 245 /* Enable the device. */ 246 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 247 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 248 reg | PCI_COMMAND_MASTER_ENABLE); 249 250 /* Map and establish the interrupt. */ 251 if (pci_intr_map(pa, &ih)) { 252 printf("%s: can't map interrupt\n", self->dv_xname); 253 return; 254 } 255 intrstr = pci_intr_string(pc, ih); 256 mlx->mlx_ih = pci_intr_establish(pc, ih, IPL_BIO, mlx_intr, mlx); 257 if (mlx->mlx_ih == NULL) { 258 printf("%s: can't establish interrupt", self->dv_xname); 259 if (intrstr != NULL) 260 printf(" at %s", intrstr); 261 printf("\n"); 262 return; 263 } 264 265 /* Select linkage based on controller interface type. */ 266 switch (mlx->mlx_iftype) { 267 case 2: 268 case 3: 269 mlx->mlx_submit = mlx_v3_submit; 270 mlx->mlx_findcomplete = mlx_v3_findcomplete; 271 mlx->mlx_intaction = mlx_v3_intaction; 272 mlx->mlx_fw_handshake = mlx_v3_fw_handshake; 273 break; 274 275 case 4: 276 mlx->mlx_submit = mlx_v4_submit; 277 mlx->mlx_findcomplete = mlx_v4_findcomplete; 278 mlx->mlx_intaction = mlx_v4_intaction; 279 mlx->mlx_fw_handshake = mlx_v4_fw_handshake; 280 break; 281 282 case 5: 283 mlx->mlx_submit = mlx_v5_submit; 284 mlx->mlx_findcomplete = mlx_v5_findcomplete; 285 mlx->mlx_intaction = mlx_v5_intaction; 286 mlx->mlx_fw_handshake = mlx_v5_fw_handshake; 287 break; 288 } 289 290 mlx_init(mlx, intrstr); 291 } 292 293 /* 294 * ================= V3 interface linkage ================= 295 */ 296 297 /* 298 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 299 * failure (the controller is not ready to take a command). 300 * 301 * Must be called at splbio or in a fashion that prevents reentry. 302 */ 303 static int 304 mlx_v3_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 305 { 306 307 /* Ready for our command? */ 308 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_FULL) == 0) { 309 /* Copy mailbox data to window. */ 310 bus_space_write_region_1(mlx->mlx_iot, mlx->mlx_ioh, 311 MLX_V3REG_MAILBOX, mc->mc_mbox, MLX_V3_MAILBOX_LEN); 312 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 313 MLX_V3REG_MAILBOX, MLX_V3_MAILBOX_LEN, 314 BUS_SPACE_BARRIER_WRITE); 315 316 /* Post command. */ 317 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_FULL); 318 return (1); 319 } 320 321 return (0); 322 } 323 324 /* 325 * See if a command has been completed, if so acknowledge its completion and 326 * recover the slot number and status code. 327 * 328 * Must be called at splbio or in a fashion that prevents reentry. 329 */ 330 static int 331 mlx_v3_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 332 { 333 334 /* Status available? */ 335 if ((mlx_inb(mlx, MLX_V3REG_ODB) & MLX_V3_ODB_SAVAIL) != 0) { 336 *slot = mlx_inb(mlx, MLX_V3REG_STATUS_IDENT); 337 *status = mlx_inw(mlx, MLX_V3REG_STATUS); 338 339 /* Acknowledge completion. */ 340 mlx_outb(mlx, MLX_V3REG_ODB, MLX_V3_ODB_SAVAIL); 341 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 342 return (1); 343 } 344 345 return (0); 346 } 347 348 /* 349 * Enable/disable interrupts as requested. (No acknowledge required) 350 * 351 * Must be called at splbio or in a fashion that prevents reentry. 352 */ 353 static void 354 mlx_v3_intaction(struct mlx_softc *mlx, int action) 355 { 356 357 mlx_outb(mlx, MLX_V3REG_IE, action != 0); 358 } 359 360 /* 361 * Poll for firmware error codes during controller initialisation. 362 * 363 * Returns 0 if initialisation is complete, 1 if still in progress but no 364 * error has been fetched, 2 if an error has been retrieved. 365 */ 366 static int 367 mlx_v3_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 368 { 369 u_int8_t fwerror; 370 371 /* First time around, clear any hardware completion status. */ 372 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 373 mlx_outb(mlx, MLX_V3REG_IDB, MLX_V3_IDB_SACK); 374 DELAY(1000); 375 mlx->mlx_flags |= MLXF_FW_INITTED; 376 } 377 378 /* Init in progress? */ 379 if ((mlx_inb(mlx, MLX_V3REG_IDB) & MLX_V3_IDB_INIT_BUSY) == 0) 380 return (0); 381 382 /* Test error value. */ 383 fwerror = mlx_inb(mlx, MLX_V3REG_FWERROR); 384 385 if ((fwerror & MLX_V3_FWERROR_PEND) == 0) 386 return (1); 387 388 /* Mask status pending bit, fetch status. */ 389 *error = fwerror & ~MLX_V3_FWERROR_PEND; 390 *param1 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM1); 391 *param2 = mlx_inb(mlx, MLX_V3REG_FWERROR_PARAM2); 392 393 /* Acknowledge. */ 394 mlx_outb(mlx, MLX_V3REG_FWERROR, 0); 395 396 return (2); 397 } 398 399 /* 400 * ================= V4 interface linkage ================= 401 */ 402 403 /* 404 * Try to give (mc) to the controller. Returns 1 if successful, 0 on 405 * failure (the controller is not ready to take a command). 406 * 407 * Must be called at splbio or in a fashion that prevents reentry. 408 */ 409 static int 410 mlx_v4_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 411 { 412 413 /* Ready for our command? */ 414 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_FULL) == 0) { 415 /* Copy mailbox data to window. */ 416 bus_space_write_region_4(mlx->mlx_iot, mlx->mlx_ioh, 417 MLX_V4REG_MAILBOX, (const u_int32_t *)mc->mc_mbox, 418 MLX_V4_MAILBOX_LEN >> 2); 419 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 420 MLX_V4REG_MAILBOX, MLX_V4_MAILBOX_LEN, 421 BUS_SPACE_BARRIER_WRITE); 422 423 /* Post command. */ 424 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_HWMBOX_CMD); 425 return (1); 426 } 427 428 return (0); 429 } 430 431 /* 432 * See if a command has been completed, if so acknowledge its completion and 433 * recover the slot number and status code. 434 * 435 * Must be called at splbio or in a fashion that prevents reentry. 436 */ 437 static int 438 mlx_v4_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 439 { 440 441 /* Status available? */ 442 if ((mlx_inl(mlx, MLX_V4REG_ODB) & MLX_V4_ODB_HWSAVAIL) != 0) { 443 *slot = mlx_inb(mlx, MLX_V4REG_STATUS_IDENT); 444 *status = mlx_inw(mlx, MLX_V4REG_STATUS); 445 446 /* Acknowledge completion. */ 447 mlx_outl(mlx, MLX_V4REG_ODB, MLX_V4_ODB_HWMBOX_ACK); 448 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 449 return (1); 450 } 451 452 return (0); 453 } 454 455 /* 456 * Enable/disable interrupts as requested. 457 * 458 * Must be called at splbio or in a fashion that prevents reentry. 459 */ 460 static void 461 mlx_v4_intaction(struct mlx_softc *mlx, int action) 462 { 463 u_int32_t ier; 464 465 if (!action) 466 ier = MLX_V4_IE_MASK | MLX_V4_IE_DISINT; 467 else 468 ier = MLX_V4_IE_MASK & ~MLX_V4_IE_DISINT; 469 470 mlx_outl(mlx, MLX_V4REG_IE, ier); 471 } 472 473 /* 474 * Poll for firmware error codes during controller initialisation. 475 * 476 * Returns 0 if initialisation is complete, 1 if still in progress but no 477 * error has been fetched, 2 if an error has been retrieved. 478 */ 479 static int 480 mlx_v4_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 481 { 482 u_int8_t fwerror; 483 484 /* First time around, clear any hardware completion status. */ 485 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 486 mlx_outl(mlx, MLX_V4REG_IDB, MLX_V4_IDB_SACK); 487 DELAY(1000); 488 mlx->mlx_flags |= MLXF_FW_INITTED; 489 } 490 491 /* Init in progress? */ 492 if ((mlx_inl(mlx, MLX_V4REG_IDB) & MLX_V4_IDB_INIT_BUSY) == 0) 493 return (0); 494 495 /* Test error value */ 496 fwerror = mlx_inb(mlx, MLX_V4REG_FWERROR); 497 if ((fwerror & MLX_V4_FWERROR_PEND) == 0) 498 return (1); 499 500 /* Mask status pending bit, fetch status. */ 501 *error = fwerror & ~MLX_V4_FWERROR_PEND; 502 *param1 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM1); 503 *param2 = mlx_inb(mlx, MLX_V4REG_FWERROR_PARAM2); 504 505 /* Acknowledge. */ 506 mlx_outb(mlx, MLX_V4REG_FWERROR, 0); 507 508 return (2); 509 } 510 511 /* 512 * ================= V5 interface linkage ================= 513 */ 514 515 /* 516 * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure 517 * (the controller is not ready to take a command). 518 * 519 * Must be called at splbio or in a fashion that prevents reentry. 520 */ 521 static int 522 mlx_v5_submit(struct mlx_softc *mlx, struct mlx_ccb *mc) 523 { 524 525 /* Ready for our command? */ 526 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_EMPTY) != 0) { 527 /* Copy mailbox data to window. */ 528 bus_space_write_region_4(mlx->mlx_iot, mlx->mlx_ioh, 529 MLX_V5REG_MAILBOX, (const u_int32_t *)mc->mc_mbox, 530 MLX_V5_MAILBOX_LEN >> 2); 531 bus_space_barrier(mlx->mlx_iot, mlx->mlx_ioh, 532 MLX_V5REG_MAILBOX, MLX_V5_MAILBOX_LEN, 533 BUS_SPACE_BARRIER_WRITE); 534 535 /* Post command */ 536 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_HWMBOX_CMD); 537 return (1); 538 } 539 540 return (0); 541 } 542 543 /* 544 * See if a command has been completed, if so acknowledge its completion and 545 * recover the slot number and status code. 546 * 547 * Must be called at splbio or in a fashion that prevents reentry. 548 */ 549 static int 550 mlx_v5_findcomplete(struct mlx_softc *mlx, u_int *slot, u_int *status) 551 { 552 553 /* Status available? */ 554 if ((mlx_inb(mlx, MLX_V5REG_ODB) & MLX_V5_ODB_HWSAVAIL) != 0) { 555 *slot = mlx_inb(mlx, MLX_V5REG_STATUS_IDENT); 556 *status = mlx_inw(mlx, MLX_V5REG_STATUS); 557 558 /* Acknowledge completion. */ 559 mlx_outb(mlx, MLX_V5REG_ODB, MLX_V5_ODB_HWMBOX_ACK); 560 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 561 return (1); 562 } 563 564 return (0); 565 } 566 567 /* 568 * Enable/disable interrupts as requested. 569 * 570 * Must be called at splbio or in a fashion that prevents reentry. 571 */ 572 static void 573 mlx_v5_intaction(struct mlx_softc *mlx, int action) 574 { 575 u_int8_t ier; 576 577 if (!action) 578 ier = 0xff & MLX_V5_IE_DISINT; 579 else 580 ier = 0xff & ~MLX_V5_IE_DISINT; 581 582 mlx_outb(mlx, MLX_V5REG_IE, ier); 583 } 584 585 /* 586 * Poll for firmware error codes during controller initialisation. 587 * 588 * Returns 0 if initialisation is complete, 1 if still in progress but no 589 * error has been fetched, 2 if an error has been retrieved. 590 */ 591 static int 592 mlx_v5_fw_handshake(struct mlx_softc *mlx, int *error, int *param1, int *param2) 593 { 594 u_int8_t fwerror; 595 596 /* First time around, clear any hardware completion status. */ 597 if ((mlx->mlx_flags & MLXF_FW_INITTED) == 0) { 598 mlx_outb(mlx, MLX_V5REG_IDB, MLX_V5_IDB_SACK); 599 DELAY(1000); 600 mlx->mlx_flags |= MLXF_FW_INITTED; 601 } 602 603 /* Init in progress? */ 604 if ((mlx_inb(mlx, MLX_V5REG_IDB) & MLX_V5_IDB_INIT_DONE) != 0) 605 return (0); 606 607 /* Test for error value. */ 608 fwerror = mlx_inb(mlx, MLX_V5REG_FWERROR); 609 if ((fwerror & MLX_V5_FWERROR_PEND) == 0) 610 return (1); 611 612 /* Mask status pending bit, fetch status. */ 613 *error = fwerror & ~MLX_V5_FWERROR_PEND; 614 *param1 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM1); 615 *param2 = mlx_inb(mlx, MLX_V5REG_FWERROR_PARAM2); 616 617 /* Acknowledge. */ 618 mlx_outb(mlx, MLX_V5REG_FWERROR, 0xff); 619 620 return (2); 621 } 622