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