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