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