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