1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Daktari platform specific hotplug controller. This 28 * driver exports the same interfaces to user space 29 * as the generic hpc3130 driver. It adds specific 30 * functionality found on Daktari, such as slot button 31 * and platform specific LED displays. Placed in 32 * the daktari specific platform directory, it will 33 * be loaded instead of the generic module. 34 */ 35 36 37 #include <sys/types.h> 38 #include <sys/cmn_err.h> 39 #include <sys/kmem.h> 40 #include <sys/errno.h> 41 #include <sys/cpuvar.h> 42 #include <sys/open.h> 43 #include <sys/stat.h> 44 #include <sys/conf.h> 45 #include <sys/ddi.h> 46 #include <sys/sunddi.h> 47 #include <sys/modctl.h> 48 #include <sys/note.h> 49 #include <sys/hotplug/hpctrl.h> 50 #include <sys/hotplug/hpcsvc.h> 51 #include <sys/i2c/clients/hpc3130.h> 52 #include <sys/hpc3130_events.h> 53 #include <sys/daktari.h> 54 #include <sys/hpc3130_dak.h> 55 56 #ifdef DEBUG 57 static int hpc3130debug = 0; 58 59 #define D1CMN_ERR(ARGS) if (hpc3130debug & 0x1) cmn_err ARGS; 60 #define D2CMN_ERR(ARGS) if (hpc3130debug & 0x2) cmn_err ARGS; 61 62 #else 63 64 #define D1CMN_ERR(ARGS) 65 #define D2CMN_ERR(ARGS) 66 67 #endif /* DEBUG */ 68 69 #define HPC3130_REG(offset, slot) ((offset) + ((slot)*8)) 70 #define HPC3130_PIL 1 71 struct tuple { 72 uint8_t reg; 73 uint8_t val; 74 }; 75 76 struct connect_command { 77 boolean_t set_bit; 78 uint8_t value; 79 }; 80 81 struct tuple pci_sequence [] = 82 { 83 {HPC3130_GCR, HPC3130_AUTO2_SEQ}, 84 {HPC3130_INTERRUPT, HPC3130_PWRGOOD | 85 HPC3130_DETECT0 | HPC3130_PRSNT1 | HPC3130_PRSNT2}, 86 {HPC3130_EVENT_STATUS, 0xff}, 87 {HPC3130_NO_REGISTER, 0}, 88 }; 89 90 struct tuple cpu_sequence [] = 91 { 92 {HPC3130_INTERRUPT, 93 HPC3130_PRSNT1 | HPC3130_DETECT0}, 94 {HPC3130_EVENT_STATUS, 0xff}, 95 {HPC3130_NO_REGISTER, 0}, 96 }; 97 98 struct connect_command connect_sequence [] = 99 { 100 {B_TRUE, HPC3130_SLOTREQ64}, 101 {B_FALSE, HPC3130_SLOTRST}, 102 {B_FALSE, HPC3130_CLKON}, 103 {B_FALSE, HPC3130_REQ64}, 104 {B_FALSE, HPC3130_SLOTREQ64}, 105 {B_TRUE, HPC3130_SLOTRST}, 106 {B_FALSE, HPC3130_BUS_CTL}, 107 }; 108 109 #define HPC3130_CONNECT_SEQ_COUNT (sizeof (connect_sequence)/ \ 110 sizeof (struct connect_command)) 111 112 struct xlate_entry { 113 char *nexus; 114 int pcidev; 115 }; 116 /* 117 * The order here is significant. Its the order 118 * of appearance of slots from bottom to top 119 * on a Sun-Fire-880 120 */ 121 static struct xlate_entry slot_translate[] = 122 { 123 {"/pci@8,700000", 5}, /* PCI0 */ 124 {"/pci@8,700000", 4}, /* PCI1 */ 125 {"/pci@8,700000", 3}, /* PCI2 */ 126 {"/pci@8,700000", 2}, /* PCI3 */ 127 128 {"/pci@9,700000", 4}, /* PCI4 */ 129 {"/pci@9,700000", 3}, /* PCI5 */ 130 {"/pci@9,700000", 2}, /* PCI6 */ 131 132 {"/pci@9,600000", 2}, /* PCI7 */ 133 {"/pci@9,600000", 1} /* PCI8 */ 134 }; 135 136 #define HPC3130_LOOKUP_SLOTS (sizeof (slot_translate)/ \ 137 sizeof (struct xlate_entry)) 138 139 static int control_slot_control = HPC3130_SLOT_CONTROL_ENABLE; 140 141 hpc3130_unit_t *hpc3130soft_statep; 142 143 static int hpc3130_atoi(const char *); 144 int hpc3130_lookup_slot(char *, int); 145 146 static int hpc3130_init(dev_info_t *, struct tuple *); 147 static uint_t hpc3130_hard_intr(caddr_t); 148 149 static int hpc3130_cpu_init(hpc3130_unit_t *, int, i2c_client_hdl_t); 150 static int hpc3130_debounce_status(i2c_client_hdl_t, int, uint8_t *); 151 static int hpc3130_read(i2c_client_hdl_t, uint8_t, uint8_t, uint8_t *); 152 static int hpc3130_write(i2c_client_hdl_t, uint8_t, uint8_t, uint8_t); 153 static int hpc3130_rw(i2c_client_hdl_t, uint8_t, boolean_t, uint8_t *); 154 155 static int hpc3130_do_attach(dev_info_t *); 156 static int hpc3130_do_detach(dev_info_t *); 157 static int hpc3130_do_resume(void); 158 static int hpc3130_do_suspend(); 159 static int hpc3130_get(intptr_t, int, hpc3130_unit_t *, int); 160 static int hpc3130_set(intptr_t, int, hpc3130_unit_t *, int); 161 162 static int hpc3130_slot_connect(caddr_t, hpc_slot_t, void *, uint_t); 163 static int hpc3130_slot_disconnect(caddr_t, hpc_slot_t, void *, uint_t); 164 static int hpc3130_verify_slot_power(hpc3130_unit_t *, i2c_client_hdl_t, 165 uint8_t, char *, boolean_t); 166 static int hpc3130_slot_insert(caddr_t, hpc_slot_t, void *, uint_t); 167 static int hpc3130_slot_remove(caddr_t, hpc_slot_t, void *, uint_t); 168 static int hpc3130_slot_control(caddr_t, hpc_slot_t, int, caddr_t); 169 /* 170 * cb ops 171 */ 172 static int hpc3130_open(dev_t *, int, int, cred_t *); 173 static int hpc3130_close(dev_t, int, int, cred_t *); 174 static int hpc3130_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 175 static int hpc3130_poll(dev_t dev, short events, int anyyet, short 176 *reventsp, struct pollhead **phpp); 177 178 static struct cb_ops hpc3130_cbops = { 179 hpc3130_open, /* open */ 180 hpc3130_close, /* close */ 181 nodev, /* strategy */ 182 nodev, /* print */ 183 nodev, /* dump */ 184 nodev, /* read */ 185 nodev, /* write */ 186 hpc3130_ioctl, /* ioctl */ 187 nodev, /* devmap */ 188 nodev, /* mmap */ 189 nodev, /* segmap */ 190 hpc3130_poll, /* poll */ 191 ddi_prop_op, /* cb_prop_op */ 192 NULL, /* streamtab */ 193 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 194 CB_REV, /* rev */ 195 nodev, /* int (*cb_aread)() */ 196 nodev /* int (*cb_awrite)() */ 197 }; 198 199 /* 200 * dev ops 201 */ 202 static int hpc3130_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 203 void **result); 204 static int hpc3130_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 205 static int hpc3130_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 206 207 static struct dev_ops hpc3130_ops = { 208 DEVO_REV, 209 0, 210 hpc3130_info, 211 nulldev, 212 nulldev, 213 hpc3130_attach, 214 hpc3130_detach, 215 nodev, 216 &hpc3130_cbops, 217 NULL, /* bus_ops */ 218 NULL, /* power */ 219 ddi_quiesce_not_needed, /* quiesce */ 220 }; 221 222 extern struct mod_ops mod_driverops; 223 224 static struct modldrv hpc3130_modldrv = { 225 &mod_driverops, /* type of module - driver */ 226 "Hotplug controller driver", 227 &hpc3130_ops 228 }; 229 230 static struct modlinkage hpc3130_modlinkage = { 231 MODREV_1, 232 &hpc3130_modldrv, 233 0 234 }; 235 236 int 237 _init(void) 238 { 239 int error; 240 241 error = mod_install(&hpc3130_modlinkage); 242 243 if (!error) 244 (void) ddi_soft_state_init((void *)&hpc3130soft_statep, 245 sizeof (hpc3130_unit_t), 4); 246 return (error); 247 } 248 249 int 250 _fini(void) 251 { 252 int error; 253 254 error = mod_remove(&hpc3130_modlinkage); 255 if (!error) 256 ddi_soft_state_fini((void *)&hpc3130soft_statep); 257 258 return (error); 259 } 260 261 int 262 _info(struct modinfo *modinfop) 263 { 264 return (mod_info(&hpc3130_modlinkage, modinfop)); 265 } 266 267 static int 268 hpc3130_open(dev_t *devp, int flags, int otyp, cred_t *credp) 269 { 270 _NOTE(ARGUNUSED(credp)) 271 hpc3130_unit_t *unitp; 272 int instance; 273 int error = 0; 274 275 if (otyp != OTYP_CHR) { 276 return (EINVAL); 277 } 278 279 instance = MINOR_TO_INST(getminor(*devp)); 280 281 unitp = (hpc3130_unit_t *) 282 ddi_get_soft_state(hpc3130soft_statep, instance); 283 284 if (unitp == NULL) { 285 return (ENXIO); 286 } 287 288 mutex_enter(&unitp->hpc3130_mutex); 289 290 if (flags & FEXCL) { 291 if (unitp->hpc3130_oflag != 0) { 292 error = EBUSY; 293 } else { 294 unitp->hpc3130_oflag = FEXCL; 295 } 296 } else { 297 if (unitp->hpc3130_oflag == FEXCL) { 298 error = EBUSY; 299 } else { 300 unitp->hpc3130_oflag = FOPEN; 301 } 302 } 303 304 mutex_exit(&unitp->hpc3130_mutex); 305 306 return (error); 307 } 308 309 static int 310 hpc3130_close(dev_t dev, int flags, int otyp, cred_t *credp) 311 { 312 _NOTE(ARGUNUSED(flags, otyp, credp)) 313 hpc3130_unit_t *unitp; 314 int instance; 315 316 instance = MINOR_TO_INST(getminor(dev)); 317 318 unitp = (hpc3130_unit_t *) 319 ddi_get_soft_state(hpc3130soft_statep, instance); 320 321 if (unitp == NULL) { 322 return (ENXIO); 323 } 324 325 mutex_enter(&unitp->hpc3130_mutex); 326 327 unitp->hpc3130_oflag = 0; 328 329 mutex_exit(&unitp->hpc3130_mutex); 330 return (DDI_SUCCESS); 331 } 332 333 static int 334 hpc3130_get(intptr_t arg, int reg, hpc3130_unit_t *unitp, int mode) 335 { 336 i2c_transfer_t *i2c_tran_pointer; 337 int err = DDI_SUCCESS; 338 339 if (arg == NULL) { 340 D2CMN_ERR((CE_WARN, "ioctl: arg passed in to " 341 "ioctl = NULL")); 342 return (EINVAL); 343 } 344 (void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer, 345 1, 1, I2C_SLEEP); 346 if (i2c_tran_pointer == NULL) { 347 D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS" 348 " i2c_tran_pointer not allocated")); 349 return (ENOMEM); 350 } 351 352 i2c_tran_pointer->i2c_flags = I2C_WR_RD; 353 i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg; 354 355 err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer); 356 if (err) { 357 D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS" 358 " i2c_trasfer routine")); 359 i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 360 return (err); 361 } 362 D1CMN_ERR((CE_NOTE, "The i2c_rbuf contains %x", 363 i2c_tran_pointer->i2c_rbuf[0])); 364 365 if (ddi_copyout((caddr_t)i2c_tran_pointer->i2c_rbuf, 366 (caddr_t)arg, 367 sizeof (uint8_t), mode) != DDI_SUCCESS) { 368 D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS" 369 " ddi_copyout routine")); 370 err = EFAULT; 371 } 372 i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 373 return (err); 374 } 375 376 static int 377 hpc3130_set(intptr_t arg, int reg, hpc3130_unit_t *unitp, int mode) 378 { 379 i2c_transfer_t *i2c_tran_pointer; 380 int err = DDI_SUCCESS; 381 uint8_t passin_byte; 382 383 if (arg == NULL) { 384 D2CMN_ERR((CE_WARN, "ioctl: arg passed in to " 385 "ioctl = NULL")); 386 return (EINVAL); 387 } 388 if (ddi_copyin((caddr_t)arg, (caddr_t)&passin_byte, 389 sizeof (uint8_t), mode) != DDI_SUCCESS) { 390 D2CMN_ERR((CE_WARN, "Failed in HPC3130_SET_CONTROL " 391 "ddi_copyin routine")); 392 393 return (EFAULT); 394 } 395 (void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer, 396 2, 0, I2C_SLEEP); 397 if (i2c_tran_pointer == NULL) { 398 D2CMN_ERR((CE_WARN, "Failed in " 399 "HPC3130_SET_CONTROL i2c_tran_pointer not allocated")); 400 401 return (ENOMEM); 402 } 403 404 i2c_tran_pointer->i2c_flags = I2C_WR; 405 i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg; 406 i2c_tran_pointer->i2c_wbuf[1] = passin_byte; 407 408 err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer); 409 i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 410 411 return (err); 412 } 413 414 static int 415 hpc3130_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 416 int *rvalp) 417 { 418 _NOTE(ARGUNUSED(credp, rvalp)) 419 hpc3130_unit_t *unitp; 420 int err = DDI_SUCCESS; 421 i2c_transfer_t *i2c_tran_pointer; 422 i2c_reg_t ioctl_reg; 423 int port = MINOR_TO_PORT(getminor(dev)); 424 int instance = MINOR_TO_INST(getminor(dev)); 425 hpc3130_slot_table_entry_t *ste; 426 427 unitp = (hpc3130_unit_t *) 428 ddi_get_soft_state(hpc3130soft_statep, instance); 429 430 if (unitp == NULL) { 431 D1CMN_ERR((CE_WARN, "unitp not filled")); 432 return (ENOMEM); 433 } 434 435 /* 436 * It should be the case that the port number is a valid 437 * index in the per instance slot table. If it is not 438 * then we should fail out. 439 */ 440 if (!(port >= 0 && port < unitp->hpc3130_slot_table_length)) { 441 return (EINVAL); 442 } 443 444 mutex_enter(&unitp->hpc3130_mutex); 445 446 ste = &unitp->hpc3130_slot_table[port]; 447 448 D2CMN_ERR((CE_NOTE, "ioctl: port = %d instance = %d", 449 port, instance)); 450 451 switch (cmd) { 452 case HPC3130_GET_STATUS: 453 err = hpc3130_get(arg, HPC3130_HP_STATUS_REG(port), unitp, 454 mode); 455 break; 456 457 case HPC3130_GET_CONTROL: 458 err = hpc3130_get(arg, HPC3130_HP_CONTROL_REG(port), unitp, 459 mode); 460 break; 461 462 case HPC3130_SET_CONTROL: 463 if (control_slot_control == HPC3130_SLOT_CONTROL_DISABLE) { 464 cmn_err(CE_WARN, "Cannot change control register."); 465 err = EINVAL; 466 break; 467 } 468 err = hpc3130_set(arg, HPC3130_HP_CONTROL_REG(port), unitp, 469 mode); 470 break; 471 472 case HPC3130_GET_EVENT_STATUS: 473 err = hpc3130_get(arg, HPC3130_INTERRUPT_STATUS_REG(port), 474 unitp, mode); 475 break; 476 477 case HPC3130_SET_EVENT_STATUS: 478 err = hpc3130_set(arg, HPC3130_INTERRUPT_STATUS_REG(port), 479 unitp, mode); 480 break; 481 482 case HPC3130_GET_GENERAL_CONFIG: 483 err = hpc3130_get(arg, HPC3130_GENERAL_CONFIG_REG(port), 484 unitp, mode); 485 break; 486 487 case HPC3130_SET_GENERAL_CONFIG: 488 err = hpc3130_set(arg, HPC3130_GENERAL_CONFIG_REG(port), 489 unitp, mode); 490 break; 491 492 case HPC3130_GET_INDICATOR_CONTROL: 493 err = hpc3130_get(arg, HPC3130_ATTENTION_INDICATOR(port), 494 unitp, mode); 495 break; 496 497 case HPC3130_SET_INDICATOR_CONTROL: 498 err = hpc3130_set(arg, HPC3130_ATTENTION_INDICATOR(port), 499 unitp, mode); 500 break; 501 502 case HPC3130_GET_EVENT_ENABLE: 503 err = hpc3130_get(arg, HPC3130_INTERRUPT_ENABLE_REG(port), 504 unitp, mode); 505 break; 506 507 case HPC3130_SET_EVENT_ENABLE: 508 err = hpc3130_set(arg, HPC3130_INTERRUPT_ENABLE_REG(port), 509 unitp, mode); 510 break; 511 512 case HPC3130_ENABLE_SLOT_CONTROL: 513 control_slot_control = HPC3130_SLOT_CONTROL_ENABLE; 514 D2CMN_ERR((CE_NOTE, "Set the control_slot_control variable to" 515 "HPC3130_SLOT_CONTROL_ENABLE")); 516 break; 517 518 case HPC3130_DISABLE_SLOT_CONTROL: 519 control_slot_control = HPC3130_SLOT_CONTROL_DISABLE; 520 D2CMN_ERR((CE_NOTE, "Set the control_slot_control variable to" 521 "HPC3130_SLOT_CONTROL_DISABLE")); 522 break; 523 524 case I2C_GET_REG: 525 if (arg == NULL) { 526 D2CMN_ERR((CE_WARN, "ioctl: arg passed in to " 527 "ioctl = NULL")); 528 err = EINVAL; 529 break; 530 } 531 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg, 532 sizeof (i2c_reg_t), mode) != DDI_SUCCESS) { 533 D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 534 "ddi_copyin routine")); 535 err = EFAULT; 536 break; 537 } 538 (void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer, 539 1, 1, I2C_SLEEP); 540 if (i2c_tran_pointer == NULL) { 541 D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 542 "i2c_tran_pointer not allocated")); 543 err = ENOMEM; 544 break; 545 } 546 547 i2c_tran_pointer->i2c_flags = I2C_WR_RD; 548 i2c_tran_pointer->i2c_wbuf[0] = ioctl_reg.reg_num; 549 550 err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer); 551 if (err) { 552 D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 553 "i2c_transfer routine")); 554 i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 555 break; 556 } 557 ioctl_reg.reg_value = i2c_tran_pointer->i2c_rbuf[0]; 558 if (ddi_copyout((caddr_t)&ioctl_reg, (caddr_t)arg, 559 sizeof (i2c_reg_t), mode) != DDI_SUCCESS) { 560 D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 561 "ddi_copyout routine")); 562 err = EFAULT; 563 } 564 565 i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 566 break; 567 568 case I2C_SET_REG: 569 if (arg == NULL) { 570 D2CMN_ERR((CE_WARN, "ioctl: arg passed in to " 571 "ioctl = NULL")); 572 err = EINVAL; 573 break; 574 } 575 if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg, 576 sizeof (i2c_reg_t), mode) != DDI_SUCCESS) { 577 D2CMN_ERR((CE_WARN, "Failed in I2C_SET_REG " 578 "ddi_copyin routine")); 579 err = EFAULT; 580 break; 581 } 582 (void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer, 583 2, 0, I2C_SLEEP); 584 if (i2c_tran_pointer == NULL) { 585 D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 586 "i2c_tran_pointer not allocated")); 587 err = ENOMEM; 588 break; 589 } 590 591 i2c_tran_pointer->i2c_flags = I2C_WR; 592 i2c_tran_pointer->i2c_wbuf[0] = ioctl_reg.reg_num; 593 i2c_tran_pointer->i2c_wbuf[1] = (uchar_t)ioctl_reg.reg_value; 594 595 err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer); 596 if (err) { 597 D2CMN_ERR((CE_WARN, "Failed in I2C_SET_REG " 598 "i2c_transfer routine")); 599 i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 600 break; 601 } 602 603 i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 604 break; 605 606 case HPC3130_GET_EVENT: { 607 struct hpc3130_event ev; 608 609 bzero(&ev, sizeof (struct hpc3130_event)); 610 611 if (unitp->slots_are == HPC3130_SLOT_TYPE_SBD) { 612 DAK_GET_SBD_APID(ev.name, sizeof (ev.name), port); 613 } else { 614 snprintf(ev.name, HPC3130_NAME_MAX, 615 "/devices%s:", ste->nexus); 616 ASSERT(strlen(ev.name) < HPC3130_NAME_MAX - 1); 617 DAK_GET_PCI_APID(ev.name + strlen(ev.name), 618 HPC3130_NAME_MAX - strlen(ev.name), 619 hpc3130_lookup_slot(ste->nexus, 620 ste->hpc3130_slot_info.pci_dev_num)); 621 } 622 623 if (unitp->events[port] & HPC3130_IEVENT_OCCUPANCY) { 624 unitp->events[port] &= ~HPC3130_IEVENT_OCCUPANCY; 625 ev.id = (unitp->present[port] == B_FALSE ? 626 HPC3130_EVENT_REMOVAL : 627 HPC3130_EVENT_INSERTION); 628 } else if (unitp->events[port] & HPC3130_IEVENT_POWER) { 629 unitp->events[port] &= ~HPC3130_IEVENT_POWER; 630 ev.id = (unitp->power[port] == B_TRUE ? 631 HPC3130_EVENT_POWERON : 632 HPC3130_EVENT_POWEROFF); 633 } else if (unitp->events[port] & HPC3130_IEVENT_BUTTON) { 634 unitp->events[port] &= ~HPC3130_IEVENT_BUTTON; 635 ev.id = HPC3130_EVENT_BUTTON; 636 } else if (unitp->events[port] & HPC3130_IEVENT_FAULT) { 637 unitp->events[port] &= ~HPC3130_IEVENT_FAULT; 638 ev.id = (unitp->fault_led[port] == HPC3130_ATTN_ON ? 639 HPC3130_LED_FAULT_ON : 640 HPC3130_LED_FAULT_OFF); 641 } else if (unitp->events[port] & HPC3130_IEVENT_OK2REM) { 642 unitp->events[port] &= ~HPC3130_IEVENT_OK2REM; 643 ev.id = (unitp->ok2rem_led[port] == HPC3130_ATTN_ON ? 644 HPC3130_LED_REMOVABLE_ON : 645 HPC3130_LED_REMOVABLE_OFF); 646 } 647 648 D1CMN_ERR((CE_NOTE, 649 "sending EVENT: ap_id=%s, event=%d", ev.name, ev.id)); 650 651 if (ddi_copyout((caddr_t)&ev, (caddr_t)arg, 652 sizeof (struct hpc3130_event), mode) != DDI_SUCCESS) { 653 D1CMN_ERR((CE_WARN, "Failed in hpc3130_ioctl" 654 " ddi_copyout routine")); 655 err = EFAULT; 656 } 657 break; 658 } 659 case HPC3130_CONF_DR: { 660 uint8_t offset; 661 int dr_conf; 662 663 if (ddi_copyin((caddr_t)arg, (caddr_t)&dr_conf, 664 sizeof (int), mode) != DDI_SUCCESS) { 665 D2CMN_ERR((CE_WARN, "Failed in HPC3130_CONF_DR " 666 "ddi_copyin routine")) 667 err = EFAULT; 668 break; 669 } 670 671 offset = ste->callback_info.offset; 672 673 unitp->enabled[offset] = 674 (dr_conf == HPC3130_DR_DISABLE ? B_FALSE : B_TRUE); 675 676 break; 677 } 678 default: 679 D2CMN_ERR((CE_WARN, "Invalid IOCTL cmd: %x", cmd)); 680 err = EINVAL; 681 } 682 683 mutex_exit(&unitp->hpc3130_mutex); 684 return (err); 685 } 686 687 static int 688 hpc3130_poll(dev_t dev, short events, int anyyet, short 689 *reventsp, struct pollhead **phpp) 690 { 691 _NOTE(ARGUNUSED(events)) 692 hpc3130_unit_t *unitp; 693 int port = MINOR_TO_PORT(getminor(dev)); 694 int instance = MINOR_TO_INST(getminor(dev)); 695 696 if (!(port >= 0 && port < HPC3130_MAX_SLOT)) { 697 return (EINVAL); 698 } 699 unitp = (hpc3130_unit_t *) 700 ddi_get_soft_state(hpc3130soft_statep, instance); 701 702 mutex_enter(&unitp->hpc3130_mutex); 703 if (unitp->events[port]) { 704 *reventsp = POLLIN; 705 } else { 706 *reventsp = 0; 707 if (!anyyet) 708 *phpp = &unitp->pollhead[port]; 709 } 710 mutex_exit(&unitp->hpc3130_mutex); 711 return (0); 712 } 713 714 /* ARGSUSED */ 715 static int 716 hpc3130_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 717 { 718 dev_t dev; 719 int instance; 720 721 if (infocmd == DDI_INFO_DEVT2INSTANCE) { 722 dev = (dev_t)arg; 723 instance = MINOR_TO_INST(getminor(dev)); 724 *result = (void *)(uintptr_t)instance; 725 return (DDI_SUCCESS); 726 } 727 return (DDI_FAILURE); 728 } 729 730 static int 731 hpc3130_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 732 { 733 switch (cmd) { 734 case DDI_ATTACH: 735 return (hpc3130_do_attach(dip)); 736 case DDI_RESUME: 737 return (hpc3130_do_resume()); 738 default: 739 return (DDI_FAILURE); 740 } 741 } 742 743 static int 744 hpc3130_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 745 { 746 switch (cmd) { 747 case DDI_DETACH: 748 return (hpc3130_do_detach(dip)); 749 case DDI_SUSPEND: 750 return (hpc3130_do_suspend()); 751 default: 752 return (DDI_FAILURE); 753 } 754 } 755 756 static int 757 hpc3130_do_attach(dev_info_t *dip) 758 { 759 hpc3130_unit_t *hpc3130_p; 760 char *s; 761 char *nexus; 762 char *pcidev; 763 char *reg_offset; 764 int r, i, n, j; 765 char name[MAXNAMELEN]; 766 minor_t minor_number; 767 int hpc3130_pil = HPC3130_PIL; 768 int instance = ddi_get_instance(dip); 769 770 /* 771 * Allocate the soft state structure for this instance. 772 */ 773 r = ddi_soft_state_zalloc(hpc3130soft_statep, instance); 774 if (r != DDI_SUCCESS) { 775 return (DDI_FAILURE); 776 } 777 778 hpc3130_p = 779 (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep, instance); 780 ASSERT(hpc3130_p); 781 782 if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 783 "interrupt-priorities", (caddr_t)&hpc3130_pil, 784 sizeof (hpc3130_pil)) != DDI_PROP_SUCCESS) { 785 goto failout0; 786 } 787 788 if (ddi_intr_hilevel(dip, 0)) { 789 cmn_err(CE_WARN, "High level interrupt not supported"); 790 goto failout0; 791 } 792 793 /* 794 * Get the "slot-table" property which defines the list of 795 * hot-pluggable slots for this controller along with the 796 * corresponding bus nexus node and device identification 797 * for each slot. 798 */ 799 r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 800 "slot-table", (caddr_t)&hpc3130_p->hpc3130_slot_table_data, 801 &hpc3130_p->hpc3130_slot_table_size); 802 803 switch (r) { 804 case DDI_PROP_SUCCESS: 805 break; 806 case DDI_PROP_NOT_FOUND: 807 cmn_err(CE_WARN, 808 "couldn't find slot-table property"); 809 return (DDI_FAILURE); 810 case DDI_PROP_UNDEFINED: 811 cmn_err(CE_WARN, 812 "slot-table undefined"); 813 return (DDI_FAILURE); 814 case DDI_PROP_NO_MEMORY: 815 cmn_err(CE_WARN, 816 "can't allocate memory for slot-table"); 817 return (DDI_FAILURE); 818 } 819 820 /* 821 * Determine the size of the slot table from the OBP property and 822 * allocate the slot table arrary.. 823 */ 824 for (i = 0, n = 0; i < hpc3130_p->hpc3130_slot_table_size; i++) { 825 if (hpc3130_p->hpc3130_slot_table_data[i] == 0) { 826 n++; 827 } 828 } 829 830 D1CMN_ERR((CE_NOTE, "hpc3130_attach(): slot table has %d entries", n)); 831 832 /* 833 * There should be HPC3130_TABLE_COLUMNS elements per entry 834 */ 835 if (n % HPC3130_TABLE_COLUMNS) { 836 cmn_err(CE_WARN, "bad format in slot-table"); 837 goto failout1; 838 } 839 840 hpc3130_p->dip = dip; 841 hpc3130_p->hpc3130_slot_table_length = n / HPC3130_TABLE_COLUMNS; 842 843 if (ddi_get_iblock_cookie(dip, 0, &hpc3130_p->ic_trap_cookie) != 844 DDI_SUCCESS) { 845 cmn_err(CE_WARN, "ddi_get_iblock_cookie FAILED"); 846 goto failout1; 847 } 848 849 mutex_init(&hpc3130_p->hpc3130_mutex, NULL, MUTEX_DRIVER, 850 (void *)hpc3130_p->ic_trap_cookie); 851 /* 852 * Create enough space for each slot table entry 853 * based on how many entries in the property 854 */ 855 hpc3130_p->hpc3130_slot_table = (hpc3130_slot_table_entry_t *) 856 kmem_zalloc(hpc3130_p->hpc3130_slot_table_length * 857 sizeof (hpc3130_slot_table_entry_t), KM_SLEEP); 858 859 /* 860 * Setup to talk to the i2c nexus 861 */ 862 if (i2c_client_register(dip, &hpc3130_p->hpc3130_hdl) != I2C_SUCCESS) { 863 cmn_err(CE_WARN, "failed to register as i2c client"); 864 goto failout2; 865 } 866 867 s = hpc3130_p->hpc3130_slot_table_data; 868 for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) { 869 hpc3130_slot_table_entry_t *ste; 870 871 /* Pick off pointer to nexus path */ 872 nexus = s; 873 s = s + strlen(s) + 1; 874 875 /* Pick off pointer to 3130 register offset */ 876 reg_offset = s; 877 s = s + strlen(s) + 1; 878 879 /* Pick off pointer to the device number */ 880 pcidev = s; 881 882 s = s + strlen(s) + 1; 883 884 j = hpc3130_atoi(reg_offset); 885 886 if (j < 0 || j >= HPC3130_MAX_SLOT) { 887 cmn_err(CE_WARN, 888 "invalid register offset value"); 889 goto failout3; 890 } 891 892 ste = &hpc3130_p->hpc3130_slot_table[j]; 893 894 strcpy(ste->nexus, nexus); 895 896 if (strncmp(ste->nexus, "/pci", 4) == 0) { 897 898 ste->hpc3130_slot_info.pci_dev_num = 899 hpc3130_atoi(pcidev); 900 901 DAK_GET_PCI_APID(ste->hpc3130_slot_info.pci_slot_name, 902 PCI_SLOT_NAME_LEN, 903 hpc3130_lookup_slot(ste->nexus, 904 hpc3130_atoi(pcidev))); 905 906 ste->hpc3130_slot_info.slot_type = HPC_SLOT_TYPE_PCI; 907 ste->hpc3130_slot_info.slot_flags = 908 HPC_SLOT_CREATE_DEVLINK; 909 hpc3130_p->slots_are = HPC3130_SLOT_TYPE_PCI; 910 911 } else { 912 913 ste->hpc3130_slot_info.sbd_slot_num = 914 hpc3130_atoi(reg_offset); 915 916 ste->hpc3130_slot_info.slot_type = HPC_SLOT_TYPE_SBD; 917 918 hpc3130_p->slots_are = HPC3130_SLOT_TYPE_SBD; 919 } 920 921 hpc3130_p->present[j] = B_FALSE; 922 hpc3130_p->enabled[j] = B_TRUE; 923 924 /* 925 * The "callback_info" structure of the slot_table is what gets 926 * passed back in the callback routines. All that is needed 927 * at that point is the device handle and the register offset 928 * within it the chip it represents. 929 */ 930 ste->callback_info.handle = (caddr_t)hpc3130_p->hpc3130_hdl; 931 932 ste->callback_info.offset = hpc3130_atoi(reg_offset); 933 934 ste->callback_info.statep = (caddr_t)hpc3130_p; 935 } 936 937 hpc3130_p->hpc3130_slot_ops = hpc_alloc_slot_ops(KM_SLEEP); 938 hpc3130_p->hpc3130_slot_ops->hpc_version = 0; 939 940 hpc3130_p->hpc3130_slot_ops->hpc_op_connect = hpc3130_slot_connect; 941 hpc3130_p->hpc3130_slot_ops->hpc_op_disconnect = 942 hpc3130_slot_disconnect; 943 hpc3130_p->hpc3130_slot_ops->hpc_op_insert = hpc3130_slot_insert; 944 hpc3130_p->hpc3130_slot_ops->hpc_op_remove = hpc3130_slot_remove; 945 hpc3130_p->hpc3130_slot_ops->hpc_op_control = hpc3130_slot_control; 946 947 cv_init(&hpc3130_p->hpc3130_cond, NULL, CV_DEFAULT, NULL); 948 949 if (hpc3130_init(dip, (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) ? 950 cpu_sequence : pci_sequence) != DDI_SUCCESS) { 951 goto failout4; 952 } 953 954 if (ddi_add_intr(dip, 0, &hpc3130_p->ic_trap_cookie, 955 NULL, hpc3130_hard_intr, 956 (caddr_t)hpc3130_p) != DDI_SUCCESS) { 957 cmn_err(CE_WARN, "failed to add interrupt"); 958 goto failout4; 959 } 960 961 /* 962 * Register with the "services" module 963 */ 964 for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) { 965 hpc3130_slot_table_entry_t *ste = 966 &hpc3130_p->hpc3130_slot_table[i]; 967 hpc3130_p->power[i] = B_TRUE; 968 if (ste->callback_info.handle != NULL) { 969 hpc_slot_register(dip, ste->nexus, 970 &ste->hpc3130_slot_info, 971 &ste->hpc3130_slot_handle, 972 hpc3130_p->hpc3130_slot_ops, 973 (caddr_t)&ste->callback_info, 0); 974 } 975 } 976 977 (void) snprintf(hpc3130_p->hpc3130_name, 978 sizeof (hpc3130_p->hpc3130_name), 979 "%s%d", ddi_node_name(dip), instance); 980 981 for (i = 0; i < HPC3130_MAX_SLOT; i++) { 982 (void) snprintf(name, MAXNAMELEN, "port_%d", i); 983 minor_number = INST_TO_MINOR(instance) | 984 PORT_TO_MINOR(I2C_PORT(i)); 985 if (ddi_create_minor_node(dip, name, S_IFCHR, minor_number, 986 "ddi_i2c:controller", NULL) == DDI_FAILURE) { 987 D1CMN_ERR((CE_WARN, "ddi_create_minor_node failed " 988 "for %s", name)); 989 ddi_remove_intr(dip, 0u, 990 hpc3130_p->ic_trap_cookie); 991 goto failout4; 992 } 993 } 994 995 return (DDI_SUCCESS); 996 997 failout4: 998 hpc_free_slot_ops(hpc3130_p->hpc3130_slot_ops); 999 failout3: 1000 i2c_client_unregister(hpc3130_p->hpc3130_hdl); 1001 failout2: 1002 mutex_destroy(&hpc3130_p->hpc3130_mutex); 1003 kmem_free(hpc3130_p->hpc3130_slot_table, 1004 hpc3130_p->hpc3130_slot_table_length * 1005 sizeof (hpc3130_slot_table_entry_t)); 1006 failout1: 1007 kmem_free(hpc3130_p->hpc3130_slot_table_data, 1008 hpc3130_p->hpc3130_slot_table_size); 1009 failout0: 1010 ddi_soft_state_free(hpc3130soft_statep, instance); 1011 1012 return (DDI_FAILURE); 1013 } 1014 1015 static int 1016 hpc3130_do_resume() 1017 { 1018 return (DDI_SUCCESS); 1019 } 1020 1021 static int 1022 hpc3130_do_suspend() 1023 { 1024 return (DDI_SUCCESS); 1025 } 1026 1027 static int 1028 hpc3130_do_detach(dev_info_t *dip) 1029 { 1030 int i; 1031 int instance = ddi_get_instance(dip); 1032 hpc3130_unit_t *hpc3130_p; 1033 1034 hpc3130_p = (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep, 1035 instance); 1036 if (hpc3130_p == NULL) 1037 return (ENXIO); 1038 1039 i2c_client_unregister(hpc3130_p->hpc3130_hdl); 1040 1041 ddi_remove_intr(dip, 0u, hpc3130_p->ic_trap_cookie); 1042 1043 cv_destroy(&hpc3130_p->hpc3130_cond); 1044 1045 for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) { 1046 hpc_slot_unregister( 1047 &hpc3130_p->hpc3130_slot_table[i].hpc3130_slot_handle); 1048 } 1049 1050 kmem_free(hpc3130_p->hpc3130_slot_table, 1051 hpc3130_p->hpc3130_slot_table_length * 1052 sizeof (hpc3130_slot_table_entry_t)); 1053 1054 kmem_free(hpc3130_p->hpc3130_slot_table_data, 1055 hpc3130_p->hpc3130_slot_table_size); 1056 1057 hpc_free_slot_ops(hpc3130_p->hpc3130_slot_ops); 1058 1059 mutex_destroy(&hpc3130_p->hpc3130_mutex); 1060 1061 ddi_soft_state_free(hpc3130soft_statep, instance); 1062 1063 return (DDI_SUCCESS); 1064 } 1065 1066 int 1067 hpc3130_set_led(hpc3130_unit_t *unitp, int slot, int led, uint8_t value) 1068 { 1069 i2c_client_hdl_t handle = unitp->hpc3130_hdl; 1070 uint8_t old; 1071 uint8_t new; 1072 1073 if (hpc3130_read(handle, HPC3130_ATTEN, slot, &old) != DDI_SUCCESS) { 1074 return (DDI_FAILURE); 1075 } 1076 new = (old & ~HPC3130_ATTN_MASK(led)) | 1077 value << HPC3130_ATTN_SHIFT(led); 1078 1079 D1CMN_ERR((CE_NOTE, "setting led %d to %x", led, value)); 1080 1081 if (hpc3130_write(handle, HPC3130_ATTEN, slot, new) != DDI_SUCCESS) { 1082 return (DDI_FAILURE); 1083 } 1084 1085 if ((value == HPC3130_ATTN_OFF || value == HPC3130_ATTN_ON) && 1086 ((old & HPC3130_ATTN_MASK(led)) != 1087 (new & HPC3130_ATTN_MASK(led)))) { 1088 /* 1089 * We're turning a LED on or off (i.e., not blinking), and 1090 * the value actually did change. 1091 */ 1092 if (led == HPC3130_LED_OK2REM) { 1093 unitp->events[slot] |= HPC3130_IEVENT_OK2REM; 1094 unitp->ok2rem_led[slot] = value; 1095 D1CMN_ERR((CE_NOTE, 1096 "recording IEVENT_OK2REM slot=%d, val=%d", 1097 slot, value)); 1098 } else { 1099 unitp->events[slot] |= HPC3130_IEVENT_FAULT; 1100 unitp->fault_led[slot] = value; 1101 D1CMN_ERR((CE_NOTE, 1102 "recording IEVENT_FAULT slot=%d, val=%d", 1103 slot, value)); 1104 } 1105 ASSERT(MUTEX_HELD(&unitp->hpc3130_mutex)); 1106 mutex_exit(&unitp->hpc3130_mutex); 1107 pollwakeup(&unitp->pollhead[slot], POLLIN); 1108 mutex_enter(&unitp->hpc3130_mutex); 1109 } 1110 return (DDI_SUCCESS); 1111 } 1112 1113 int 1114 hpc3130_get_led(i2c_client_hdl_t handle, int slot, 1115 int led, uint8_t *value) 1116 { 1117 uint8_t temp; 1118 1119 if (hpc3130_read(handle, HPC3130_ATTEN, slot, &temp) != DDI_SUCCESS) { 1120 return (DDI_FAILURE); 1121 } 1122 1123 *value = (temp & HPC3130_ATTN_MASK(led)) >> HPC3130_ATTN_SHIFT(led); 1124 return (DDI_SUCCESS); 1125 } 1126 1127 static int 1128 hpc3130_write(i2c_client_hdl_t handle, uint8_t offset, 1129 uint8_t port, uint8_t data) 1130 { 1131 ASSERT(port < HPC3130_MAX_SLOT); 1132 ASSERT(handle); 1133 1134 return (hpc3130_rw(handle, 1135 HPC3130_REG(offset, port), B_TRUE, &data)); 1136 } 1137 1138 static int 1139 hpc3130_read(i2c_client_hdl_t handle, uint8_t offset, 1140 uint8_t port, uint8_t *data) 1141 { 1142 ASSERT(port < HPC3130_MAX_SLOT); 1143 ASSERT(handle); 1144 1145 return (hpc3130_rw(handle, 1146 HPC3130_REG(offset, port), B_FALSE, data)); 1147 } 1148 1149 static int 1150 hpc3130_rw(i2c_client_hdl_t handle, uint8_t reg, 1151 boolean_t write, uint8_t *data) 1152 { 1153 i2c_transfer_t *i2c_tran_pointer; 1154 int err; 1155 int rlen; 1156 int wlen; 1157 1158 if (write == B_TRUE) { 1159 wlen = 2; 1160 rlen = 0; 1161 } else { 1162 wlen = 1; 1163 rlen = 1; 1164 } 1165 1166 (void) i2c_transfer_alloc(handle, 1167 &i2c_tran_pointer, wlen, rlen, I2C_SLEEP); 1168 1169 if (i2c_tran_pointer == NULL) { 1170 D1CMN_ERR((CE_WARN, "Failed in hpc3130_rw: " 1171 "no transfer structure 0x%x", reg)); 1172 return (DDI_FAILURE); 1173 } 1174 i2c_tran_pointer->i2c_wbuf[0] = reg; 1175 if (write == B_TRUE) { 1176 i2c_tran_pointer->i2c_flags = I2C_WR; 1177 i2c_tran_pointer->i2c_wbuf[1] = *data; 1178 } else { 1179 i2c_tran_pointer->i2c_flags = I2C_WR_RD; 1180 } 1181 1182 err = i2c_transfer(handle, i2c_tran_pointer); 1183 if (err) { 1184 D1CMN_ERR((CE_WARN, "Failed in hpc3130_rw: " 1185 "no I2C data transfered 0x%x", reg)); 1186 (void) i2c_transfer_free(handle, i2c_tran_pointer); 1187 return (DDI_FAILURE); 1188 } 1189 1190 if (write == B_FALSE) 1191 *data = i2c_tran_pointer->i2c_rbuf[0]; 1192 1193 (void) i2c_transfer_free(handle, i2c_tran_pointer); 1194 1195 return (DDI_SUCCESS); 1196 } 1197 1198 /* 1199 * Put the hot plug controller(s) in proper mode for further 1200 * operations. 1201 */ 1202 static int 1203 hpc3130_init(dev_info_t *dip, 1204 struct tuple *init_sequence) 1205 { 1206 1207 int slot; 1208 i2c_client_hdl_t handle; 1209 hpc3130_unit_t *hpc3130_p; 1210 int instance = ddi_get_instance(dip); 1211 int error = DDI_FAILURE; 1212 struct tuple *tp; 1213 1214 hpc3130_p = 1215 (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep, 1216 instance); 1217 ASSERT(hpc3130_p); 1218 1219 mutex_enter(&hpc3130_p->hpc3130_mutex); 1220 1221 handle = hpc3130_p->hpc3130_hdl; 1222 1223 for (slot = 0; slot < HPC3130_MAX_SLOT; slot++) { 1224 tp = init_sequence; 1225 while (tp->reg != HPC3130_NO_REGISTER) { 1226 if (hpc3130_write(handle, tp->reg, slot, 1227 tp->val) != DDI_SUCCESS) { 1228 goto out; 1229 } 1230 tp++; 1231 } 1232 /* 1233 * CPU slots need some special initialization 1234 * attention. 1235 */ 1236 if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) { 1237 if (hpc3130_cpu_init(hpc3130_p, slot, handle) 1238 != DDI_SUCCESS) { 1239 goto out; 1240 } 1241 } 1242 } 1243 error = DDI_SUCCESS; 1244 out: 1245 mutex_exit(&hpc3130_p->hpc3130_mutex); 1246 1247 return (error); 1248 } 1249 1250 /* 1251 * When the TI 3130 produces an interrupt, 1252 * this routine is called to sort it out. 1253 */ 1254 static uint_t 1255 hpc3130_hard_intr(caddr_t arg) 1256 { 1257 uint8_t interrupt; 1258 uint8_t status; 1259 uint8_t slot; 1260 i2c_client_hdl_t handle; 1261 hpc3130_slot_type_t slot_type; 1262 uint_t rc = DDI_INTR_UNCLAIMED; 1263 1264 hpc3130_unit_t *hpc3130_p = (hpc3130_unit_t *)arg; 1265 ASSERT(hpc3130_p); 1266 1267 mutex_enter(&hpc3130_p->hpc3130_mutex); 1268 1269 slot_type = hpc3130_p->slots_are; 1270 handle = hpc3130_p->hpc3130_hdl; 1271 1272 for (slot = 0; slot < HPC3130_MAX_SLOT; slot++) { 1273 1274 /* 1275 * Read the interrupt event register - see 1276 * which event(s) took place. 1277 */ 1278 if (hpc3130_read(handle, HPC3130_EVENT_STATUS, slot, 1279 &interrupt)) { 1280 continue; 1281 } 1282 1283 if (interrupt == 0) 1284 continue; 1285 1286 rc = DDI_INTR_CLAIMED; 1287 1288 if (hpc3130_debounce_status(handle, 1289 slot, &status) != DDI_SUCCESS) { 1290 continue; 1291 } 1292 1293 if (interrupt & HPC3130_PWRGOOD) { 1294 hpc3130_p->power[slot] = B_FALSE; 1295 if (!(status & HPC3130_PWRGOOD)) { 1296 hpc3130_p->power[slot] = B_TRUE; 1297 } 1298 cv_signal(&hpc3130_p->hpc3130_cond); 1299 hpc3130_p->events[slot] |= HPC3130_IEVENT_POWER; 1300 } 1301 1302 if (interrupt & HPC3130_DETECT0) { 1303 if (slot_type == HPC3130_SLOT_TYPE_SBD) { 1304 boolean_t present = !(status&HPC3130_DETECT0); 1305 1306 /* Turn ON/OFF OK-to-remove LED */ 1307 (void) hpc3130_set_led(hpc3130_p, 1308 slot, 1309 HPC3130_LED_OK2REM, 1310 (present ? HPC3130_ATTN_ON : 1311 HPC3130_ATTN_OFF)); 1312 if (!present) { 1313 /* Clear the FAULT LED on removal */ 1314 (void) hpc3130_set_led(hpc3130_p, 1315 slot, 1316 HPC3130_LED_FAULT, 1317 HPC3130_ATTN_OFF); 1318 } 1319 1320 hpc3130_p->present[slot] = present; 1321 hpc3130_p->events[slot] |= 1322 HPC3130_IEVENT_OCCUPANCY; 1323 } else { 1324 ASSERT(slot_type == HPC3130_SLOT_TYPE_PCI); 1325 1326 if (!(status & HPC3130_DETECT0)) { 1327 /* 1328 * Event on the downward 1329 * stroke of the button. 1330 */ 1331 hpc3130_p->events[slot] |= 1332 HPC3130_IEVENT_BUTTON; 1333 } 1334 } 1335 } 1336 1337 if (interrupt & (HPC3130_PRSNT1 | HPC3130_PRSNT2)) { 1338 if (slot_type == HPC3130_SLOT_TYPE_SBD) { 1339 if (!(status & HPC3130_PRSNT1)) { 1340 /* 1341 * Event only on the downward 1342 * stroke of the button. 1343 */ 1344 hpc3130_p->events[slot] |= 1345 HPC3130_IEVENT_BUTTON; 1346 } 1347 } else { 1348 ASSERT(slot_type == HPC3130_SLOT_TYPE_PCI); 1349 if ((status & (HPC3130_PRSNT1 | 1350 HPC3130_PRSNT2)) == 1351 (HPC3130_PRSNT1 | HPC3130_PRSNT2)) { 1352 1353 hpc3130_p->present[slot] = B_FALSE; 1354 1355 /* Turn OFF Fault LED */ 1356 (void) hpc3130_set_led(hpc3130_p, 1357 slot, 1358 HPC3130_LED_FAULT, 1359 HPC3130_ATTN_OFF); 1360 /* Turn OFF OK-to-remove LED */ 1361 (void) hpc3130_set_led(hpc3130_p, 1362 slot, 1363 HPC3130_LED_OK2REM, 1364 HPC3130_ATTN_OFF); 1365 } else { 1366 1367 hpc3130_p->present[slot] = B_TRUE; 1368 1369 /* Turn ON OK-to-remove LED */ 1370 (void) hpc3130_set_led(hpc3130_p, 1371 slot, 1372 HPC3130_LED_OK2REM, 1373 HPC3130_ATTN_ON); 1374 } 1375 1376 hpc3130_p->events[slot] |= 1377 HPC3130_IEVENT_OCCUPANCY; 1378 } 1379 } 1380 if (hpc3130_p->events[slot] && 1381 (hpc3130_p->present[slot] == B_TRUE)) { 1382 mutex_exit(&hpc3130_p->hpc3130_mutex); 1383 pollwakeup(&hpc3130_p->pollhead[slot], POLLIN); 1384 mutex_enter(&hpc3130_p->hpc3130_mutex); 1385 } 1386 (void) hpc3130_write(handle, HPC3130_EVENT_STATUS, 1387 slot, interrupt); 1388 } 1389 1390 mutex_exit(&hpc3130_p->hpc3130_mutex); 1391 1392 return (rc); 1393 } 1394 1395 static int 1396 hpc3130_cpu_init(hpc3130_unit_t *hpc3130_p, int slot, i2c_client_hdl_t handle) 1397 { 1398 uint8_t slot_status; 1399 uint8_t control_reg; 1400 1401 int result = HPC_ERR_FAILED; 1402 1403 if (hpc3130_read(handle, HPC3130_STATUS, slot, 1404 &slot_status)) { 1405 goto out; 1406 } 1407 1408 if (hpc3130_read(handle, HPC3130_CONTROL, slot, 1409 &control_reg)) { 1410 goto out; 1411 } 1412 1413 /* 1414 * For the CPU slots, the DETECT[0] pin on the HPC3130 1415 * goes low when a CPU module is in the slot. Pulled 1416 * high otherwise. 1417 */ 1418 if (slot_status & HPC3130_DETECT0) { 1419 D1CMN_ERR((CE_NOTE, "hpc3130_cpu_init(): " 1420 "[0x%x]Power off....[%d]", 1421 slot_status, slot)); 1422 control_reg = control_reg & ~HPC3130_SLTPWRCTL; 1423 } else { 1424 D1CMN_ERR((CE_NOTE, "hpc3130_cpu_init(): " 1425 "[0x%x]Power LEFT on!!!....[%d]", 1426 slot_status, slot)); 1427 hpc3130_p->present[slot] = B_TRUE; 1428 control_reg = control_reg | HPC3130_SLTPWRCTL; 1429 1430 } 1431 1432 /* 1433 * Set the control register accordingly 1434 */ 1435 if (hpc3130_write(handle, HPC3130_CONTROL, 1436 slot, control_reg) != DDI_SUCCESS) { 1437 goto out; 1438 } 1439 1440 result = DDI_SUCCESS; 1441 out: 1442 1443 return (result); 1444 } 1445 1446 static int 1447 hpc3130_debounce_status(i2c_client_hdl_t handle, 1448 int slot, uint8_t *status) 1449 { 1450 int count, limit; 1451 uint8_t old; 1452 1453 ASSERT(status); 1454 1455 /* 1456 * Get HPC3130_DEBOUNCE_COUNT consecutive equal 1457 * readings from the status register 1458 */ 1459 1460 count = 0; limit = 0; old = 0xff; 1461 do { 1462 if (hpc3130_read(handle, HPC3130_STATUS, 1463 slot, status)) { 1464 return (DDI_FAILURE); 1465 } 1466 if (old != *status) { 1467 count = 0; 1468 } else { 1469 count += 1; 1470 } 1471 1472 limit += 1; 1473 old = *status; 1474 1475 } while (count < HPC3130_DEBOUNCE_COUNT && 1476 limit < HPC3130_DEBOUNCE_LIMIT); 1477 1478 if (limit == HPC3130_DEBOUNCE_LIMIT) { 1479 return (DDI_FAILURE); 1480 } 1481 1482 return (DDI_SUCCESS); 1483 } 1484 1485 static int 1486 hpc3130_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, 1487 void *data, uint_t flags) 1488 { 1489 _NOTE(ARGUNUSED(slot_hdl, data, flags)) 1490 uint8_t control; 1491 uint8_t offset; 1492 uint8_t config; 1493 uint8_t status; 1494 hpc3130_unit_t *hpc3130_p; 1495 i2c_client_hdl_t handle; 1496 int i; 1497 int result = HPC_ERR_FAILED; 1498 hpc3130_slot_type_t slot_type; 1499 hpc3130_slot_table_entry_t *ste; 1500 char phys_slot[MAXPATHLEN]; 1501 boolean_t needs_to_be_powered_off = B_FALSE; 1502 1503 hpc3130_callback_arg_t *info_p = (hpc3130_callback_arg_t *)ops_arg; 1504 1505 /* 1506 * Callback parameter has specific device handle and offset 1507 * information in it. 1508 */ 1509 1510 hpc3130_p = (hpc3130_unit_t *)info_p->statep; 1511 ASSERT(hpc3130_p); 1512 1513 mutex_enter(&hpc3130_p->hpc3130_mutex); 1514 1515 handle = (i2c_client_hdl_t)info_p->handle; 1516 offset = info_p->offset; 1517 1518 ste = &hpc3130_p->hpc3130_slot_table[offset]; 1519 1520 if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) { 1521 DAK_GET_SBD_APID(phys_slot, MAXPATHLEN, offset); 1522 } else { 1523 DAK_GET_PCI_APID(phys_slot, MAXPATHLEN, 1524 hpc3130_lookup_slot(ste->nexus, 1525 ste->hpc3130_slot_info.pci_dev_num)); 1526 } 1527 1528 ASSERT(ste->hpc3130_slot_handle != NULL); 1529 1530 slot_type = hpc3130_p->slots_are; 1531 1532 if (hpc3130_p->enabled[offset] == B_FALSE) { 1533 cmn_err(CE_WARN, "hot-plug disabled on %s", phys_slot); 1534 goto out; 1535 } 1536 1537 /* Return (do nothing) if power already applied */ 1538 if (hpc3130_p->power[offset] == B_TRUE) { 1539 D1CMN_ERR((CE_NOTE, "Slot power already on %s", phys_slot)); 1540 mutex_exit(&hpc3130_p->hpc3130_mutex); 1541 return (HPC_SUCCESS); 1542 } 1543 1544 if (hpc3130_read(handle, HPC3130_STATUS, offset, 1545 &status)) { 1546 goto out; 1547 } 1548 1549 /* Read the slot control register to get current value */ 1550 if (hpc3130_read(handle, HPC3130_CONTROL, offset, 1551 &control)) { 1552 goto out; 1553 } 1554 1555 if (slot_type == HPC3130_SLOT_TYPE_SBD) { 1556 1557 D1CMN_ERR((CE_NOTE, "CPU connect %d control=%x status=%x", 1558 offset, control, status)); 1559 1560 control = control | HPC3130_SLTPWRCTL; 1561 if (hpc3130_write(handle, HPC3130_CONTROL, offset, 1562 control) != DDI_SUCCESS) { 1563 goto out; 1564 } 1565 1566 } else { 1567 1568 D1CMN_ERR((CE_NOTE, "PCI connect %d", offset)); 1569 1570 /* 1571 * PCI needs special sequencing of the control signals. 1572 */ 1573 1574 if (hpc3130_read(handle, HPC3130_GCR, offset, 1575 &config)) { 1576 goto out; 1577 } 1578 1579 /* Assert RST to comply with PCI spec. */ 1580 control &= ~HPC3130_SLOTRST; 1581 if (hpc3130_write(handle, HPC3130_CONTROL, offset, 1582 control) != DDI_SUCCESS) { 1583 goto out; 1584 } 1585 drv_usecwait(HPC3130_ADEQUATE_PAUSE); 1586 1587 /* Send the power on signal and verify the result */ 1588 control = control | HPC3130_SLTPWRCTL; 1589 if ((hpc3130_write(handle, HPC3130_CONTROL, offset, 1590 control) != DDI_SUCCESS) || 1591 (hpc3130_verify_slot_power(hpc3130_p, handle, offset, 1592 phys_slot, B_TRUE) == HPC_ERR_FAILED)) { 1593 goto out; 1594 } 1595 1596 /* The slot is now powered on. */ 1597 1598 drv_usecwait(HPC3130_ADEQUATE_PAUSE); 1599 1600 /* Extinguish the "OK-to-remove" indicator */ 1601 (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_OK2REM, 1602 HPC3130_ATTN_OFF); 1603 1604 /* 1605 * Perform bus/card speed check functions. 1606 */ 1607 if (hpc3130_read(handle, HPC3130_STATUS, offset, &status)) { 1608 goto out; 1609 } 1610 if ((config & HPC3130_SYSM66STAT) && 1611 !(status & HPC3130_M66EN)) { 1612 cmn_err(CE_WARN, "66Mhz bus can't accept " 1613 "33Mhz card in %s", phys_slot); 1614 needs_to_be_powered_off = B_TRUE; 1615 goto out; 1616 } 1617 if (!(config & HPC3130_SYSM66STAT) && 1618 (status & HPC3130_M66EN)) { 1619 cmn_err(CE_NOTE, "66Mhz capable card throttled " 1620 "back to 33Mhz in %s", phys_slot); 1621 } 1622 1623 /* 1624 * Send the connect sequence (see struct connect_sequence) 1625 */ 1626 for (i = 0; i < HPC3130_CONNECT_SEQ_COUNT; i++) { 1627 if (connect_sequence[i].set_bit == B_TRUE) { 1628 control |= connect_sequence[i].value; 1629 } else { 1630 control &= ~connect_sequence[i].value; 1631 } 1632 if (hpc3130_write(handle, HPC3130_CONTROL, offset, 1633 control) != DDI_SUCCESS) { 1634 goto out; 1635 } 1636 drv_usecwait(HPC3130_ADEQUATE_PAUSE); 1637 } 1638 } 1639 1640 hpc_slot_event_notify(ste->hpc3130_slot_handle, 1641 HPC_EVENT_SLOT_POWER_ON, 0); 1642 1643 /* Flash the "fault" indicator */ 1644 (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT, 1645 HPC3130_ATTN_SLO); 1646 1647 result = HPC_SUCCESS; 1648 1649 out: 1650 if (needs_to_be_powered_off == B_TRUE) { 1651 /* 1652 * We are in an error state where the slot is powered on, and 1653 * it must be powered off. 1654 */ 1655 1656 /* Send the power off signal and verify the result */ 1657 control = control & ~HPC3130_SLTPWRCTL; 1658 if ((hpc3130_write(handle, HPC3130_CONTROL, offset, 1659 control) == DDI_SUCCESS) && 1660 (hpc3130_verify_slot_power(hpc3130_p, handle, offset, 1661 phys_slot, B_FALSE) == HPC_SUCCESS)) { 1662 /* Re-light "OK-to-remove" LED */ 1663 (void) hpc3130_set_led(hpc3130_p, offset, 1664 HPC3130_LED_OK2REM, HPC3130_ATTN_ON); 1665 } 1666 } 1667 1668 mutex_exit(&hpc3130_p->hpc3130_mutex); 1669 1670 return (result); 1671 } 1672 1673 1674 static int 1675 hpc3130_slot_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, 1676 void *data, uint_t flags) 1677 { 1678 _NOTE(ARGUNUSED(slot_hdl, data, flags)) 1679 uint8_t control; 1680 uint8_t offset; 1681 i2c_client_hdl_t handle; 1682 hpc3130_unit_t *hpc3130_p; 1683 int result = HPC_ERR_FAILED; 1684 hpc3130_slot_type_t slot_type; 1685 hpc3130_slot_table_entry_t *ste; 1686 char phys_slot[MAXPATHLEN]; 1687 1688 hpc3130_callback_arg_t *info_p = (hpc3130_callback_arg_t *)ops_arg; 1689 1690 /* 1691 * Callback parameter has specific device handle and offset 1692 * information in it. 1693 */ 1694 hpc3130_p = (hpc3130_unit_t *)info_p->statep; 1695 ASSERT(hpc3130_p); 1696 1697 mutex_enter(&hpc3130_p->hpc3130_mutex); 1698 1699 handle = (i2c_client_hdl_t)info_p->handle; 1700 offset = info_p->offset; 1701 1702 ASSERT(handle == hpc3130_p->hpc3130_hdl); 1703 1704 ste = &hpc3130_p->hpc3130_slot_table[offset]; 1705 1706 if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) { 1707 DAK_GET_SBD_APID(phys_slot, MAXPATHLEN, offset); 1708 } else { 1709 DAK_GET_PCI_APID(phys_slot, MAXPATHLEN, 1710 hpc3130_lookup_slot(ste->nexus, 1711 ste->hpc3130_slot_info.pci_dev_num)); 1712 } 1713 1714 ASSERT(ste->hpc3130_slot_handle != NULL); 1715 1716 slot_type = hpc3130_p->slots_are; 1717 1718 /* 1719 * Read the slot control register to get current value 1720 */ 1721 if (hpc3130_read(handle, HPC3130_CONTROL, offset, 1722 &control)) { 1723 goto out; 1724 } 1725 1726 if (slot_type == HPC3130_SLOT_TYPE_SBD) { 1727 1728 D1CMN_ERR((CE_NOTE, "CPU disconnect %d", offset)); 1729 1730 control = control & ~HPC3130_SLTPWRCTL; 1731 /* 1732 * Write out the modified control register 1733 */ 1734 if (hpc3130_write(handle, HPC3130_CONTROL, offset, 1735 control) != DDI_SUCCESS) { 1736 goto out; 1737 } 1738 } else { 1739 1740 D1CMN_ERR((CE_NOTE, "PCI disconnect %d", offset)); 1741 1742 control &= ~HPC3130_SLOTRST; 1743 if (hpc3130_write(handle, HPC3130_CONTROL, offset, 1744 control) != DDI_SUCCESS) { 1745 goto out; 1746 } 1747 1748 control |= HPC3130_BUS_CTL; 1749 if (hpc3130_write(handle, HPC3130_CONTROL, offset, 1750 control) != DDI_SUCCESS) { 1751 goto out; 1752 } 1753 } 1754 1755 D1CMN_ERR((CE_WARN, "disconnect present[%d]==%d", 1756 offset, hpc3130_p->present[offset])); 1757 1758 if (hpc3130_verify_slot_power(hpc3130_p, handle, offset, 1759 phys_slot, B_FALSE) == HPC_ERR_FAILED) { 1760 goto out; 1761 } 1762 1763 hpc_slot_event_notify(ste->hpc3130_slot_handle, 1764 HPC_EVENT_SLOT_POWER_OFF, 0); 1765 1766 if (hpc3130_p->present[offset] == B_TRUE) { 1767 /* 1768 * Illuminate the "OK-to-remove" indicator 1769 * if there is a card in the slot. 1770 */ 1771 1772 (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_OK2REM, 1773 HPC3130_ATTN_ON); 1774 1775 /* 1776 * Turn off the "fault" indicator 1777 */ 1778 (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT, 1779 HPC3130_ATTN_OFF); 1780 } else { 1781 /* 1782 * If the slot is being powered off with 1783 * no cards in there, its at "boot time", 1784 * put the LEDs in a sane state 1785 */ 1786 if (slot_type == HPC3130_SLOT_TYPE_PCI) { 1787 (void) hpc3130_set_led(hpc3130_p, offset, 1788 HPC3130_LED_FAULT, HPC3130_ATTN_OFF); 1789 (void) hpc3130_set_led(hpc3130_p, offset, 1790 HPC3130_LED_OK2REM, HPC3130_ATTN_OFF); 1791 } 1792 } 1793 1794 result = HPC_SUCCESS; 1795 out: 1796 mutex_exit(&hpc3130_p->hpc3130_mutex); 1797 1798 return (result); 1799 } 1800 1801 static int 1802 hpc3130_verify_slot_power(hpc3130_unit_t *hpc3130_p, i2c_client_hdl_t handle, 1803 uint8_t offset, char *phys_slot, boolean_t slot_target_state) 1804 { 1805 uint8_t tries = 0; 1806 uint8_t status; 1807 int result = HPC_SUCCESS; 1808 clock_t tm, timeleft; 1809 boolean_t slot_actual_state; 1810 boolean_t failure = B_FALSE; 1811 hpc3130_slot_table_entry_t *ste; 1812 1813 /* This function is called while holding the hpc3130 mutex. */ 1814 1815 /* 1816 * For slot_target_state and slot_actual_state: 1817 * B_TRUE == the slot is powered on 1818 * B_FALSE == the slot is powered off 1819 */ 1820 1821 ste = &hpc3130_p->hpc3130_slot_table[offset]; 1822 slot_actual_state = hpc3130_p->power[offset]; 1823 1824 while ((slot_actual_state != slot_target_state) && 1825 (failure != B_TRUE)) { 1826 tm = ddi_get_lbolt(); 1827 tm += drv_usectohz(300000); 1828 timeleft = cv_timedwait(&hpc3130_p->hpc3130_cond, 1829 &hpc3130_p->hpc3130_mutex, tm); 1830 if (timeleft == -1) { 1831 if (tries++ < HPC3130_POWER_TRIES) { 1832 /* 1833 * The interrupt was missed - explicitly 1834 * check the status. 1835 */ 1836 if (hpc3130_read(handle, 1837 HPC3130_STATUS, offset, &status)) { 1838 failure = B_TRUE; 1839 continue; 1840 } 1841 if (status & HPC3130_PWRGOOD) { 1842 slot_actual_state = B_FALSE; 1843 } else { 1844 slot_actual_state = B_TRUE; 1845 } 1846 hpc3130_p->power[offset] = slot_actual_state; 1847 } else { 1848 /* Too many tries. We failed. */ 1849 failure = B_TRUE; 1850 } 1851 } 1852 } 1853 1854 if (failure == B_TRUE) { 1855 result = HPC_ERR_FAILED; 1856 if (slot_target_state == B_TRUE) { 1857 cmn_err(CE_WARN, 1858 "Could not power on slot %s", phys_slot); 1859 } else { 1860 cmn_err(CE_WARN, 1861 "Could not power off slot %s", phys_slot); 1862 } 1863 (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT, 1864 HPC3130_ATTN_ON); 1865 hpc_slot_event_notify(ste->hpc3130_slot_handle, 1866 HPC_EVENT_SLOT_NOT_HEALTHY, 0); 1867 } 1868 1869 return (result); 1870 } 1871 1872 static int 1873 hpc3130_slot_insert(caddr_t ops_arg, hpc_slot_t slot_hdl, 1874 void *data, uint_t flags) 1875 { 1876 _NOTE(ARGUNUSED(ops_arg, slot_hdl, data, flags)) 1877 return (HPC_ERR_NOTSUPPORTED); 1878 } 1879 1880 static int 1881 hpc3130_slot_remove(caddr_t ops_arg, hpc_slot_t slot_hdl, 1882 void *data, uint_t flags) 1883 { 1884 _NOTE(ARGUNUSED(ops_arg, slot_hdl, data, flags)) 1885 return (HPC_ERR_NOTSUPPORTED); 1886 } 1887 1888 static int 1889 hpc3130_slot_control(caddr_t ops_arg, hpc_slot_t slot_hdl, 1890 int request, caddr_t arg) 1891 { 1892 _NOTE(ARGUNUSED(slot_hdl)) 1893 i2c_client_hdl_t handle; 1894 uint8_t offset; 1895 uint8_t state; 1896 hpc_led_info_t *led_info; 1897 hpc3130_unit_t *hpc3130_p; 1898 hpc3130_slot_type_t slot_type; 1899 1900 hpc3130_callback_arg_t *info_p = (hpc3130_callback_arg_t *)ops_arg; 1901 1902 /* 1903 * Callback parameter has specific device handle and offset 1904 * information in it. 1905 */ 1906 1907 hpc3130_p = (hpc3130_unit_t *)info_p->statep; 1908 ASSERT(hpc3130_p); 1909 1910 mutex_enter(&hpc3130_p->hpc3130_mutex); 1911 1912 handle = (i2c_client_hdl_t)info_p->handle; 1913 offset = info_p->offset; 1914 1915 ASSERT(handle == hpc3130_p->hpc3130_hdl); 1916 1917 slot_type = hpc3130_p->slots_are; 1918 1919 switch (request) { 1920 case HPC_CTRL_GET_LED_STATE: { 1921 int led; 1922 1923 led_info = (hpc_led_info_t *)arg; 1924 if (led_info->led != HPC_FAULT_LED && 1925 led_info->led != HPC_ATTN_LED) { 1926 D1CMN_ERR((CE_WARN, 1927 "Only FAULT and ATTN leds allowed")); 1928 mutex_exit(&hpc3130_p->hpc3130_mutex); 1929 return (HPC_ERR_INVALID); 1930 } 1931 1932 if (led_info->led == HPC_FAULT_LED) 1933 led = HPC3130_LED_FAULT; 1934 else 1935 led = HPC3130_LED_OK2REM; 1936 1937 if (hpc3130_get_led(handle, offset, led, &state) != 1938 DDI_SUCCESS) { 1939 mutex_exit(&hpc3130_p->hpc3130_mutex); 1940 return (HPC_ERR_FAILED); 1941 } 1942 1943 /* Make sure that no one broke the conversion macros */ 1944 ASSERT(state < sizeof (hpc3130_to_hpc_led_map)); 1945 ASSERT(state == 1946 HPC3130_FROM_HPC_LED(HPC3130_TO_HPC_LED(state))); 1947 1948 led_info->state = HPC3130_TO_HPC_LED(state); 1949 } 1950 break; 1951 case HPC_CTRL_SET_LED_STATE: { 1952 int led; 1953 1954 /* 1955 * The HPC3130 support modifications to the Fault and 1956 * Ok-to-remove LEDs. 1957 */ 1958 led_info = (hpc_led_info_t *)arg; 1959 if (led_info->led != HPC_FAULT_LED && 1960 led_info->led != HPC_ATTN_LED) { 1961 D1CMN_ERR((CE_WARN, 1962 "Only FAULT and ATTN leds allowed")); 1963 mutex_exit(&hpc3130_p->hpc3130_mutex); 1964 return (HPC_ERR_INVALID); 1965 } 1966 1967 if (led_info->led == HPC_FAULT_LED) 1968 led = HPC3130_LED_FAULT; 1969 else 1970 led = HPC3130_LED_OK2REM; 1971 1972 state = led_info->state; 1973 if (state >= sizeof (hpc3130_from_hpc_led_map) || 1974 (state != HPC3130_TO_HPC_LED( 1975 HPC3130_FROM_HPC_LED(state)))) { 1976 D1CMN_ERR((CE_WARN, 1977 "Improper LED value: %d %d", state, 1978 HPC3130_TO_HPC_LED( 1979 HPC3130_FROM_HPC_LED(state)))); 1980 mutex_exit(&hpc3130_p->hpc3130_mutex); 1981 return (HPC_ERR_INVALID); 1982 } 1983 1984 (void) hpc3130_set_led(hpc3130_p, offset, led, 1985 HPC3130_FROM_HPC_LED(state)); 1986 } 1987 break; 1988 case HPC_CTRL_GET_SLOT_STATE: { 1989 if (hpc3130_p->power[offset] == B_FALSE) { 1990 if (hpc3130_p->present[offset] == B_FALSE) { 1991 *(ap_rstate_t *)arg = 1992 AP_RSTATE_EMPTY; 1993 } else { 1994 *(ap_rstate_t *)arg = 1995 AP_RSTATE_DISCONNECTED; 1996 } 1997 } else { 1998 *(ap_rstate_t *)arg = 1999 AP_RSTATE_CONNECTED; 2000 } 2001 } 2002 break; 2003 case HPC_CTRL_GET_BOARD_TYPE: { 2004 *(hpc_board_type_t *)arg = 2005 (slot_type == HPC3130_SLOT_TYPE_SBD ? 2006 HPC_BOARD_UNKNOWN : HPC_BOARD_PCI_HOTPLUG); 2007 } 2008 break; 2009 case HPC_CTRL_DEV_CONFIG_START: 2010 case HPC_CTRL_DEV_UNCONFIG_START: 2011 hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT, 2012 HPC3130_ATTN_SLO); 2013 break; 2014 case HPC_CTRL_DEV_CONFIG_FAILURE: 2015 hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT, 2016 HPC3130_ATTN_ON); 2017 break; 2018 case HPC_CTRL_DEV_CONFIGURED: 2019 hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT, 2020 HPC3130_ATTN_OFF); 2021 hpc3130_p->present[offset] = B_TRUE; 2022 break; 2023 case HPC_CTRL_DEV_UNCONFIGURED: 2024 if (hpc3130_p->power[offset] == B_TRUE) { 2025 hpc3130_set_led(hpc3130_p, offset, 2026 HPC3130_LED_FAULT, HPC3130_ATTN_SLO); 2027 } else { 2028 hpc3130_set_led(hpc3130_p, offset, 2029 HPC3130_LED_FAULT, HPC3130_ATTN_OFF); 2030 } 2031 break; 2032 case HPC_CTRL_DISABLE_SLOT: { 2033 hpc3130_p->enabled[offset] = B_FALSE; 2034 } 2035 break; 2036 case HPC_CTRL_ENABLE_SLOT: { 2037 hpc3130_p->enabled[offset] = B_TRUE; 2038 } 2039 break; 2040 default: 2041 mutex_exit(&hpc3130_p->hpc3130_mutex); 2042 return (HPC_ERR_FAILED); 2043 } 2044 mutex_exit(&hpc3130_p->hpc3130_mutex); 2045 return (HPC_SUCCESS); 2046 } 2047 2048 int 2049 hpc3130_lookup_slot(char *nexus, int pcidev) 2050 { 2051 int i = 0; 2052 2053 while ((slot_translate[i].pcidev != pcidev || 2054 strcmp(nexus, slot_translate[i].nexus) != 0) && 2055 i < HPC3130_LOOKUP_SLOTS) 2056 i++; 2057 ASSERT(i != HPC3130_LOOKUP_SLOTS); 2058 return (i); 2059 } 2060 2061 /* 2062 * A routine to convert a number (represented as a string) to 2063 * the integer value it represents. 2064 */ 2065 2066 static int 2067 isdigit(int ch) 2068 { 2069 return (ch >= '0' && ch <= '9'); 2070 } 2071 2072 #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') 2073 #define bad(val) (val == NULL || !isdigit(*val)) 2074 2075 static int 2076 hpc3130_atoi(const char *p) 2077 { 2078 int n; 2079 int c, neg = 0; 2080 2081 if (!isdigit(c = *p)) { 2082 while (isspace(c)) 2083 c = *++p; 2084 switch (c) { 2085 case '-': 2086 neg++; 2087 /* FALLTHROUGH */ 2088 case '+': 2089 c = *++p; 2090 } 2091 if (!isdigit(c)) 2092 return (0); 2093 } 2094 for (n = '0' - c; isdigit(c = *++p); ) { 2095 n *= 10; /* two steps to avoid unnecessary overflow */ 2096 n += '0' - c; /* accum neg to avoid surprises at MAX */ 2097 } 2098 return (neg ? n : -n); 2099 } 2100