17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 58e03c085Szk194757 * Common Development and Distribution License (the "License"). 68e03c085Szk194757 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Daktari platform specific hotplug controller. This 287c478bd9Sstevel@tonic-gate * driver exports the same interfaces to user space 297c478bd9Sstevel@tonic-gate * as the generic hpc3130 driver. It adds specific 307c478bd9Sstevel@tonic-gate * functionality found on Daktari, such as slot button 317c478bd9Sstevel@tonic-gate * and platform specific LED displays. Placed in 327c478bd9Sstevel@tonic-gate * the daktari specific platform directory, it will 337c478bd9Sstevel@tonic-gate * be loaded instead of the generic module. 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 397c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 407c478bd9Sstevel@tonic-gate #include <sys/errno.h> 417c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 427c478bd9Sstevel@tonic-gate #include <sys/open.h> 437c478bd9Sstevel@tonic-gate #include <sys/stat.h> 447c478bd9Sstevel@tonic-gate #include <sys/conf.h> 457c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 477c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 487c478bd9Sstevel@tonic-gate #include <sys/note.h> 497c478bd9Sstevel@tonic-gate #include <sys/hotplug/hpctrl.h> 507c478bd9Sstevel@tonic-gate #include <sys/hotplug/hpcsvc.h> 517c478bd9Sstevel@tonic-gate #include <sys/i2c/clients/hpc3130.h> 527c478bd9Sstevel@tonic-gate #include <sys/hpc3130_events.h> 537c478bd9Sstevel@tonic-gate #include <sys/daktari.h> 547c478bd9Sstevel@tonic-gate #include <sys/hpc3130_dak.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate #ifdef DEBUG 577c478bd9Sstevel@tonic-gate static int hpc3130debug = 0; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate #define D1CMN_ERR(ARGS) if (hpc3130debug & 0x1) cmn_err ARGS; 607c478bd9Sstevel@tonic-gate #define D2CMN_ERR(ARGS) if (hpc3130debug & 0x2) cmn_err ARGS; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #else 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #define D1CMN_ERR(ARGS) 657c478bd9Sstevel@tonic-gate #define D2CMN_ERR(ARGS) 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #define HPC3130_REG(offset, slot) ((offset) + ((slot)*8)) 707c478bd9Sstevel@tonic-gate #define HPC3130_PIL 1 717c478bd9Sstevel@tonic-gate struct tuple { 727c478bd9Sstevel@tonic-gate uint8_t reg; 737c478bd9Sstevel@tonic-gate uint8_t val; 747c478bd9Sstevel@tonic-gate }; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate struct connect_command { 777c478bd9Sstevel@tonic-gate boolean_t set_bit; 787c478bd9Sstevel@tonic-gate uint8_t value; 797c478bd9Sstevel@tonic-gate }; 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate struct tuple pci_sequence [] = 827c478bd9Sstevel@tonic-gate { 837c478bd9Sstevel@tonic-gate {HPC3130_GCR, HPC3130_AUTO2_SEQ}, 847c478bd9Sstevel@tonic-gate {HPC3130_INTERRUPT, HPC3130_PWRGOOD | 857c478bd9Sstevel@tonic-gate HPC3130_DETECT0 | HPC3130_PRSNT1 | HPC3130_PRSNT2}, 867c478bd9Sstevel@tonic-gate {HPC3130_EVENT_STATUS, 0xff}, 877c478bd9Sstevel@tonic-gate {HPC3130_NO_REGISTER, 0}, 887c478bd9Sstevel@tonic-gate }; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate struct tuple cpu_sequence [] = 917c478bd9Sstevel@tonic-gate { 927c478bd9Sstevel@tonic-gate {HPC3130_INTERRUPT, 937c478bd9Sstevel@tonic-gate HPC3130_PRSNT1 | HPC3130_DETECT0}, 947c478bd9Sstevel@tonic-gate {HPC3130_EVENT_STATUS, 0xff}, 957c478bd9Sstevel@tonic-gate {HPC3130_NO_REGISTER, 0}, 967c478bd9Sstevel@tonic-gate }; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate struct connect_command connect_sequence [] = 997c478bd9Sstevel@tonic-gate { 1007c478bd9Sstevel@tonic-gate {B_TRUE, HPC3130_SLOTREQ64}, 1017c478bd9Sstevel@tonic-gate {B_FALSE, HPC3130_SLOTRST}, 1027c478bd9Sstevel@tonic-gate {B_FALSE, HPC3130_CLKON}, 1037c478bd9Sstevel@tonic-gate {B_FALSE, HPC3130_REQ64}, 1047c478bd9Sstevel@tonic-gate {B_FALSE, HPC3130_SLOTREQ64}, 1057c478bd9Sstevel@tonic-gate {B_TRUE, HPC3130_SLOTRST}, 1067c478bd9Sstevel@tonic-gate {B_FALSE, HPC3130_BUS_CTL}, 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate #define HPC3130_CONNECT_SEQ_COUNT (sizeof (connect_sequence)/ \ 1107c478bd9Sstevel@tonic-gate sizeof (struct connect_command)) 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate struct xlate_entry { 1137c478bd9Sstevel@tonic-gate char *nexus; 1147c478bd9Sstevel@tonic-gate int pcidev; 1157c478bd9Sstevel@tonic-gate }; 1167c478bd9Sstevel@tonic-gate /* 1177c478bd9Sstevel@tonic-gate * The order here is significant. Its the order 1187c478bd9Sstevel@tonic-gate * of appearance of slots from bottom to top 1197c478bd9Sstevel@tonic-gate * on a Sun-Fire-880 1207c478bd9Sstevel@tonic-gate */ 1217c478bd9Sstevel@tonic-gate static struct xlate_entry slot_translate[] = 1227c478bd9Sstevel@tonic-gate { 1237c478bd9Sstevel@tonic-gate {"/pci@8,700000", 5}, /* PCI0 */ 1247c478bd9Sstevel@tonic-gate {"/pci@8,700000", 4}, /* PCI1 */ 1257c478bd9Sstevel@tonic-gate {"/pci@8,700000", 3}, /* PCI2 */ 1267c478bd9Sstevel@tonic-gate {"/pci@8,700000", 2}, /* PCI3 */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate {"/pci@9,700000", 4}, /* PCI4 */ 1297c478bd9Sstevel@tonic-gate {"/pci@9,700000", 3}, /* PCI5 */ 1307c478bd9Sstevel@tonic-gate {"/pci@9,700000", 2}, /* PCI6 */ 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate {"/pci@9,600000", 2}, /* PCI7 */ 1337c478bd9Sstevel@tonic-gate {"/pci@9,600000", 1} /* PCI8 */ 1347c478bd9Sstevel@tonic-gate }; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate #define HPC3130_LOOKUP_SLOTS (sizeof (slot_translate)/ \ 1377c478bd9Sstevel@tonic-gate sizeof (struct xlate_entry)) 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate static int control_slot_control = HPC3130_SLOT_CONTROL_ENABLE; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate hpc3130_unit_t *hpc3130soft_statep; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate static int hpc3130_atoi(const char *); 1447c478bd9Sstevel@tonic-gate int hpc3130_lookup_slot(char *, int); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate static int hpc3130_init(dev_info_t *, struct tuple *); 1477c478bd9Sstevel@tonic-gate static uint_t hpc3130_hard_intr(caddr_t); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate static int hpc3130_cpu_init(hpc3130_unit_t *, int, i2c_client_hdl_t); 1507c478bd9Sstevel@tonic-gate static int hpc3130_debounce_status(i2c_client_hdl_t, int, uint8_t *); 1517c478bd9Sstevel@tonic-gate static int hpc3130_read(i2c_client_hdl_t, uint8_t, uint8_t, uint8_t *); 1527c478bd9Sstevel@tonic-gate static int hpc3130_write(i2c_client_hdl_t, uint8_t, uint8_t, uint8_t); 1537c478bd9Sstevel@tonic-gate static int hpc3130_rw(i2c_client_hdl_t, uint8_t, boolean_t, uint8_t *); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate static int hpc3130_do_attach(dev_info_t *); 1567c478bd9Sstevel@tonic-gate static int hpc3130_do_detach(dev_info_t *); 1577c478bd9Sstevel@tonic-gate static int hpc3130_do_resume(void); 1587c478bd9Sstevel@tonic-gate static int hpc3130_do_suspend(); 1597c478bd9Sstevel@tonic-gate static int hpc3130_get(intptr_t, int, hpc3130_unit_t *, int); 1607c478bd9Sstevel@tonic-gate static int hpc3130_set(intptr_t, int, hpc3130_unit_t *, int); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate static int hpc3130_slot_connect(caddr_t, hpc_slot_t, void *, uint_t); 1637c478bd9Sstevel@tonic-gate static int hpc3130_slot_disconnect(caddr_t, hpc_slot_t, void *, uint_t); 1647c478bd9Sstevel@tonic-gate static int hpc3130_verify_slot_power(hpc3130_unit_t *, i2c_client_hdl_t, 1657c478bd9Sstevel@tonic-gate uint8_t, char *, boolean_t); 1667c478bd9Sstevel@tonic-gate static int hpc3130_slot_insert(caddr_t, hpc_slot_t, void *, uint_t); 1677c478bd9Sstevel@tonic-gate static int hpc3130_slot_remove(caddr_t, hpc_slot_t, void *, uint_t); 1687c478bd9Sstevel@tonic-gate static int hpc3130_slot_control(caddr_t, hpc_slot_t, int, caddr_t); 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * cb ops 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate static int hpc3130_open(dev_t *, int, int, cred_t *); 1737c478bd9Sstevel@tonic-gate static int hpc3130_close(dev_t, int, int, cred_t *); 1747c478bd9Sstevel@tonic-gate static int hpc3130_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1757c478bd9Sstevel@tonic-gate static int hpc3130_poll(dev_t dev, short events, int anyyet, short 1767c478bd9Sstevel@tonic-gate *reventsp, struct pollhead **phpp); 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate static struct cb_ops hpc3130_cbops = { 1797c478bd9Sstevel@tonic-gate hpc3130_open, /* open */ 1807c478bd9Sstevel@tonic-gate hpc3130_close, /* close */ 1817c478bd9Sstevel@tonic-gate nodev, /* strategy */ 1827c478bd9Sstevel@tonic-gate nodev, /* print */ 1837c478bd9Sstevel@tonic-gate nodev, /* dump */ 1847c478bd9Sstevel@tonic-gate nodev, /* read */ 1857c478bd9Sstevel@tonic-gate nodev, /* write */ 1867c478bd9Sstevel@tonic-gate hpc3130_ioctl, /* ioctl */ 1877c478bd9Sstevel@tonic-gate nodev, /* devmap */ 1887c478bd9Sstevel@tonic-gate nodev, /* mmap */ 1897c478bd9Sstevel@tonic-gate nodev, /* segmap */ 1907c478bd9Sstevel@tonic-gate hpc3130_poll, /* poll */ 1917c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1927c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 1937c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 1947c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 1957c478bd9Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 1967c478bd9Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 1977c478bd9Sstevel@tonic-gate }; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * dev ops 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate static int hpc3130_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 2037c478bd9Sstevel@tonic-gate void **result); 2047c478bd9Sstevel@tonic-gate static int hpc3130_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 2057c478bd9Sstevel@tonic-gate static int hpc3130_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate static struct dev_ops hpc3130_ops = { 2087c478bd9Sstevel@tonic-gate DEVO_REV, 2097c478bd9Sstevel@tonic-gate 0, 2107c478bd9Sstevel@tonic-gate hpc3130_info, 2117c478bd9Sstevel@tonic-gate nulldev, 2127c478bd9Sstevel@tonic-gate nulldev, 2137c478bd9Sstevel@tonic-gate hpc3130_attach, 2147c478bd9Sstevel@tonic-gate hpc3130_detach, 2157c478bd9Sstevel@tonic-gate nodev, 2167c478bd9Sstevel@tonic-gate &hpc3130_cbops, 21719397407SSherry Moore NULL, /* bus_ops */ 21819397407SSherry Moore NULL, /* power */ 21919397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 2207c478bd9Sstevel@tonic-gate }; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate static struct modldrv hpc3130_modldrv = { 2257c478bd9Sstevel@tonic-gate &mod_driverops, /* type of module - driver */ 22619397407SSherry Moore "Hotplug controller driver", 2277c478bd9Sstevel@tonic-gate &hpc3130_ops 2287c478bd9Sstevel@tonic-gate }; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate static struct modlinkage hpc3130_modlinkage = { 2317c478bd9Sstevel@tonic-gate MODREV_1, 2327c478bd9Sstevel@tonic-gate &hpc3130_modldrv, 2337c478bd9Sstevel@tonic-gate 0 2347c478bd9Sstevel@tonic-gate }; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate int 2377c478bd9Sstevel@tonic-gate _init(void) 2387c478bd9Sstevel@tonic-gate { 2397c478bd9Sstevel@tonic-gate int error; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate error = mod_install(&hpc3130_modlinkage); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate if (!error) 2447c478bd9Sstevel@tonic-gate (void) ddi_soft_state_init((void *)&hpc3130soft_statep, 2457c478bd9Sstevel@tonic-gate sizeof (hpc3130_unit_t), 4); 2467c478bd9Sstevel@tonic-gate return (error); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate int 2507c478bd9Sstevel@tonic-gate _fini(void) 2517c478bd9Sstevel@tonic-gate { 2527c478bd9Sstevel@tonic-gate int error; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate error = mod_remove(&hpc3130_modlinkage); 2557c478bd9Sstevel@tonic-gate if (!error) 2567c478bd9Sstevel@tonic-gate ddi_soft_state_fini((void *)&hpc3130soft_statep); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate return (error); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate int 2627c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate return (mod_info(&hpc3130_modlinkage, modinfop)); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate static int 2687c478bd9Sstevel@tonic-gate hpc3130_open(dev_t *devp, int flags, int otyp, cred_t *credp) 2697c478bd9Sstevel@tonic-gate { 2707c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(credp)) 2717c478bd9Sstevel@tonic-gate hpc3130_unit_t *unitp; 2727c478bd9Sstevel@tonic-gate int instance; 2737c478bd9Sstevel@tonic-gate int error = 0; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) { 2767c478bd9Sstevel@tonic-gate return (EINVAL); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate instance = MINOR_TO_INST(getminor(*devp)); 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate unitp = (hpc3130_unit_t *) 2827c478bd9Sstevel@tonic-gate ddi_get_soft_state(hpc3130soft_statep, instance); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate if (unitp == NULL) { 2857c478bd9Sstevel@tonic-gate return (ENXIO); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate mutex_enter(&unitp->hpc3130_mutex); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate if (flags & FEXCL) { 2917c478bd9Sstevel@tonic-gate if (unitp->hpc3130_oflag != 0) { 2927c478bd9Sstevel@tonic-gate error = EBUSY; 2937c478bd9Sstevel@tonic-gate } else { 2947c478bd9Sstevel@tonic-gate unitp->hpc3130_oflag = FEXCL; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate } else { 2977c478bd9Sstevel@tonic-gate if (unitp->hpc3130_oflag == FEXCL) { 2987c478bd9Sstevel@tonic-gate error = EBUSY; 2997c478bd9Sstevel@tonic-gate } else { 3007c478bd9Sstevel@tonic-gate unitp->hpc3130_oflag = FOPEN; 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate mutex_exit(&unitp->hpc3130_mutex); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate return (error); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate static int 3107c478bd9Sstevel@tonic-gate hpc3130_close(dev_t dev, int flags, int otyp, cred_t *credp) 3117c478bd9Sstevel@tonic-gate { 3127c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(flags, otyp, credp)) 3137c478bd9Sstevel@tonic-gate hpc3130_unit_t *unitp; 3147c478bd9Sstevel@tonic-gate int instance; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate instance = MINOR_TO_INST(getminor(dev)); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate unitp = (hpc3130_unit_t *) 3197c478bd9Sstevel@tonic-gate ddi_get_soft_state(hpc3130soft_statep, instance); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate if (unitp == NULL) { 3227c478bd9Sstevel@tonic-gate return (ENXIO); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate mutex_enter(&unitp->hpc3130_mutex); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate unitp->hpc3130_oflag = 0; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate mutex_exit(&unitp->hpc3130_mutex); 3307c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate static int 3347c478bd9Sstevel@tonic-gate hpc3130_get(intptr_t arg, int reg, hpc3130_unit_t *unitp, int mode) 3357c478bd9Sstevel@tonic-gate { 3367c478bd9Sstevel@tonic-gate i2c_transfer_t *i2c_tran_pointer; 3377c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if (arg == NULL) { 3407c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "ioctl: arg passed in to " 3417c478bd9Sstevel@tonic-gate "ioctl = NULL")); 3427c478bd9Sstevel@tonic-gate return (EINVAL); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer, 3457c478bd9Sstevel@tonic-gate 1, 1, I2C_SLEEP); 3467c478bd9Sstevel@tonic-gate if (i2c_tran_pointer == NULL) { 3477c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS" 3487c478bd9Sstevel@tonic-gate " i2c_tran_pointer not allocated")); 3497c478bd9Sstevel@tonic-gate return (ENOMEM); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_flags = I2C_WR_RD; 3537c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer); 3567c478bd9Sstevel@tonic-gate if (err) { 3577c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS" 3587c478bd9Sstevel@tonic-gate " i2c_trasfer routine")); 3597c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 3607c478bd9Sstevel@tonic-gate return (err); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "The i2c_rbuf contains %x", 3637c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_rbuf[0])); 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)i2c_tran_pointer->i2c_rbuf, 3667c478bd9Sstevel@tonic-gate (caddr_t)arg, 3677c478bd9Sstevel@tonic-gate sizeof (uint8_t), mode) != DDI_SUCCESS) { 3687c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS" 3697c478bd9Sstevel@tonic-gate " ddi_copyout routine")); 3707c478bd9Sstevel@tonic-gate err = EFAULT; 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 3737c478bd9Sstevel@tonic-gate return (err); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate static int 3777c478bd9Sstevel@tonic-gate hpc3130_set(intptr_t arg, int reg, hpc3130_unit_t *unitp, int mode) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate i2c_transfer_t *i2c_tran_pointer; 3807c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 3817c478bd9Sstevel@tonic-gate uint8_t passin_byte; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate if (arg == NULL) { 3847c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "ioctl: arg passed in to " 3857c478bd9Sstevel@tonic-gate "ioctl = NULL")); 3867c478bd9Sstevel@tonic-gate return (EINVAL); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&passin_byte, 3897c478bd9Sstevel@tonic-gate sizeof (uint8_t), mode) != DDI_SUCCESS) { 3907c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in HPC3130_SET_CONTROL " 3917c478bd9Sstevel@tonic-gate "ddi_copyin routine")); 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate return (EFAULT); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer, 3967c478bd9Sstevel@tonic-gate 2, 0, I2C_SLEEP); 3977c478bd9Sstevel@tonic-gate if (i2c_tran_pointer == NULL) { 3987c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in " 3997c478bd9Sstevel@tonic-gate "HPC3130_SET_CONTROL i2c_tran_pointer not allocated")); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate return (ENOMEM); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_flags = I2C_WR; 4057c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg; 4067c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[1] = passin_byte; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer); 4097c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate return (err); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate static int 4157c478bd9Sstevel@tonic-gate hpc3130_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 4167c478bd9Sstevel@tonic-gate int *rvalp) 4177c478bd9Sstevel@tonic-gate { 4187c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(credp, rvalp)) 4197c478bd9Sstevel@tonic-gate hpc3130_unit_t *unitp; 4207c478bd9Sstevel@tonic-gate int err = DDI_SUCCESS; 4217c478bd9Sstevel@tonic-gate i2c_transfer_t *i2c_tran_pointer; 4227c478bd9Sstevel@tonic-gate i2c_reg_t ioctl_reg; 4237c478bd9Sstevel@tonic-gate int port = MINOR_TO_PORT(getminor(dev)); 4247c478bd9Sstevel@tonic-gate int instance = MINOR_TO_INST(getminor(dev)); 4257c478bd9Sstevel@tonic-gate hpc3130_slot_table_entry_t *ste; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate unitp = (hpc3130_unit_t *) 4287c478bd9Sstevel@tonic-gate ddi_get_soft_state(hpc3130soft_statep, instance); 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate if (unitp == NULL) { 4317c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_WARN, "unitp not filled")); 4327c478bd9Sstevel@tonic-gate return (ENOMEM); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4358e03c085Szk194757 /* 4368e03c085Szk194757 * It should be the case that the port number is a valid 4378e03c085Szk194757 * index in the per instance slot table. If it is not 4388e03c085Szk194757 * then we should fail out. 4398e03c085Szk194757 */ 4408e03c085Szk194757 if (!(port >= 0 && port < unitp->hpc3130_slot_table_length)) { 4418e03c085Szk194757 return (EINVAL); 4428e03c085Szk194757 } 4438e03c085Szk194757 4447c478bd9Sstevel@tonic-gate mutex_enter(&unitp->hpc3130_mutex); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate ste = &unitp->hpc3130_slot_table[port]; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_NOTE, "ioctl: port = %d instance = %d", 4497c478bd9Sstevel@tonic-gate port, instance)); 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate switch (cmd) { 4527c478bd9Sstevel@tonic-gate case HPC3130_GET_STATUS: 4537c478bd9Sstevel@tonic-gate err = hpc3130_get(arg, HPC3130_HP_STATUS_REG(port), unitp, 4547c478bd9Sstevel@tonic-gate mode); 4557c478bd9Sstevel@tonic-gate break; 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate case HPC3130_GET_CONTROL: 4587c478bd9Sstevel@tonic-gate err = hpc3130_get(arg, HPC3130_HP_CONTROL_REG(port), unitp, 4597c478bd9Sstevel@tonic-gate mode); 4607c478bd9Sstevel@tonic-gate break; 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate case HPC3130_SET_CONTROL: 4637c478bd9Sstevel@tonic-gate if (control_slot_control == HPC3130_SLOT_CONTROL_DISABLE) { 4647c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Cannot change control register."); 4657c478bd9Sstevel@tonic-gate err = EINVAL; 4667c478bd9Sstevel@tonic-gate break; 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate err = hpc3130_set(arg, HPC3130_HP_CONTROL_REG(port), unitp, 4697c478bd9Sstevel@tonic-gate mode); 4707c478bd9Sstevel@tonic-gate break; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate case HPC3130_GET_EVENT_STATUS: 4737c478bd9Sstevel@tonic-gate err = hpc3130_get(arg, HPC3130_INTERRUPT_STATUS_REG(port), 4747c478bd9Sstevel@tonic-gate unitp, mode); 4757c478bd9Sstevel@tonic-gate break; 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate case HPC3130_SET_EVENT_STATUS: 4787c478bd9Sstevel@tonic-gate err = hpc3130_set(arg, HPC3130_INTERRUPT_STATUS_REG(port), 4797c478bd9Sstevel@tonic-gate unitp, mode); 4807c478bd9Sstevel@tonic-gate break; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate case HPC3130_GET_GENERAL_CONFIG: 4837c478bd9Sstevel@tonic-gate err = hpc3130_get(arg, HPC3130_GENERAL_CONFIG_REG(port), 4847c478bd9Sstevel@tonic-gate unitp, mode); 4857c478bd9Sstevel@tonic-gate break; 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate case HPC3130_SET_GENERAL_CONFIG: 4887c478bd9Sstevel@tonic-gate err = hpc3130_set(arg, HPC3130_GENERAL_CONFIG_REG(port), 4897c478bd9Sstevel@tonic-gate unitp, mode); 4907c478bd9Sstevel@tonic-gate break; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate case HPC3130_GET_INDICATOR_CONTROL: 4937c478bd9Sstevel@tonic-gate err = hpc3130_get(arg, HPC3130_ATTENTION_INDICATOR(port), 4947c478bd9Sstevel@tonic-gate unitp, mode); 4957c478bd9Sstevel@tonic-gate break; 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate case HPC3130_SET_INDICATOR_CONTROL: 4987c478bd9Sstevel@tonic-gate err = hpc3130_set(arg, HPC3130_ATTENTION_INDICATOR(port), 4997c478bd9Sstevel@tonic-gate unitp, mode); 5007c478bd9Sstevel@tonic-gate break; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate case HPC3130_GET_EVENT_ENABLE: 5037c478bd9Sstevel@tonic-gate err = hpc3130_get(arg, HPC3130_INTERRUPT_ENABLE_REG(port), 5047c478bd9Sstevel@tonic-gate unitp, mode); 5057c478bd9Sstevel@tonic-gate break; 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate case HPC3130_SET_EVENT_ENABLE: 5087c478bd9Sstevel@tonic-gate err = hpc3130_set(arg, HPC3130_INTERRUPT_ENABLE_REG(port), 5097c478bd9Sstevel@tonic-gate unitp, mode); 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate case HPC3130_ENABLE_SLOT_CONTROL: 5137c478bd9Sstevel@tonic-gate control_slot_control = HPC3130_SLOT_CONTROL_ENABLE; 5147c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_NOTE, "Set the control_slot_control variable to" 5157c478bd9Sstevel@tonic-gate "HPC3130_SLOT_CONTROL_ENABLE")); 5167c478bd9Sstevel@tonic-gate break; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate case HPC3130_DISABLE_SLOT_CONTROL: 5197c478bd9Sstevel@tonic-gate control_slot_control = HPC3130_SLOT_CONTROL_DISABLE; 5207c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_NOTE, "Set the control_slot_control variable to" 5217c478bd9Sstevel@tonic-gate "HPC3130_SLOT_CONTROL_DISABLE")); 5227c478bd9Sstevel@tonic-gate break; 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate case I2C_GET_REG: 5257c478bd9Sstevel@tonic-gate if (arg == NULL) { 5267c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "ioctl: arg passed in to " 5277c478bd9Sstevel@tonic-gate "ioctl = NULL")); 5287c478bd9Sstevel@tonic-gate err = EINVAL; 5297c478bd9Sstevel@tonic-gate break; 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg, 5327c478bd9Sstevel@tonic-gate sizeof (i2c_reg_t), mode) != DDI_SUCCESS) { 5337c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 5347c478bd9Sstevel@tonic-gate "ddi_copyin routine")); 5357c478bd9Sstevel@tonic-gate err = EFAULT; 5367c478bd9Sstevel@tonic-gate break; 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer, 5397c478bd9Sstevel@tonic-gate 1, 1, I2C_SLEEP); 5407c478bd9Sstevel@tonic-gate if (i2c_tran_pointer == NULL) { 5417c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 5427c478bd9Sstevel@tonic-gate "i2c_tran_pointer not allocated")); 5437c478bd9Sstevel@tonic-gate err = ENOMEM; 5447c478bd9Sstevel@tonic-gate break; 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_flags = I2C_WR_RD; 5487c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[0] = ioctl_reg.reg_num; 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer); 5517c478bd9Sstevel@tonic-gate if (err) { 5527c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 5537c478bd9Sstevel@tonic-gate "i2c_transfer routine")); 5547c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 5557c478bd9Sstevel@tonic-gate break; 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate ioctl_reg.reg_value = i2c_tran_pointer->i2c_rbuf[0]; 5587c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&ioctl_reg, (caddr_t)arg, 5597c478bd9Sstevel@tonic-gate sizeof (i2c_reg_t), mode) != DDI_SUCCESS) { 5607c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 5617c478bd9Sstevel@tonic-gate "ddi_copyout routine")); 5627c478bd9Sstevel@tonic-gate err = EFAULT; 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 5667c478bd9Sstevel@tonic-gate break; 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate case I2C_SET_REG: 5697c478bd9Sstevel@tonic-gate if (arg == NULL) { 5707c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "ioctl: arg passed in to " 5717c478bd9Sstevel@tonic-gate "ioctl = NULL")); 5727c478bd9Sstevel@tonic-gate err = EINVAL; 5737c478bd9Sstevel@tonic-gate break; 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg, 5767c478bd9Sstevel@tonic-gate sizeof (i2c_reg_t), mode) != DDI_SUCCESS) { 5777c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in I2C_SET_REG " 5787c478bd9Sstevel@tonic-gate "ddi_copyin routine")); 5797c478bd9Sstevel@tonic-gate err = EFAULT; 5807c478bd9Sstevel@tonic-gate break; 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer, 5837c478bd9Sstevel@tonic-gate 2, 0, I2C_SLEEP); 5847c478bd9Sstevel@tonic-gate if (i2c_tran_pointer == NULL) { 5857c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG " 5867c478bd9Sstevel@tonic-gate "i2c_tran_pointer not allocated")); 5877c478bd9Sstevel@tonic-gate err = ENOMEM; 5887c478bd9Sstevel@tonic-gate break; 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_flags = I2C_WR; 5927c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[0] = ioctl_reg.reg_num; 5937c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[1] = (uchar_t)ioctl_reg.reg_value; 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer); 5967c478bd9Sstevel@tonic-gate if (err) { 5977c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in I2C_SET_REG " 5987c478bd9Sstevel@tonic-gate "i2c_transfer routine")); 5997c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 6007c478bd9Sstevel@tonic-gate break; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer); 6047c478bd9Sstevel@tonic-gate break; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate case HPC3130_GET_EVENT: { 6077c478bd9Sstevel@tonic-gate struct hpc3130_event ev; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate bzero(&ev, sizeof (struct hpc3130_event)); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (unitp->slots_are == HPC3130_SLOT_TYPE_SBD) { 6127c478bd9Sstevel@tonic-gate DAK_GET_SBD_APID(ev.name, sizeof (ev.name), port); 6137c478bd9Sstevel@tonic-gate } else { 614*07d06da5SSurya Prakki (void) snprintf(ev.name, HPC3130_NAME_MAX, 6157c478bd9Sstevel@tonic-gate "/devices%s:", ste->nexus); 6167c478bd9Sstevel@tonic-gate ASSERT(strlen(ev.name) < HPC3130_NAME_MAX - 1); 6177c478bd9Sstevel@tonic-gate DAK_GET_PCI_APID(ev.name + strlen(ev.name), 6187c478bd9Sstevel@tonic-gate HPC3130_NAME_MAX - strlen(ev.name), 6197c478bd9Sstevel@tonic-gate hpc3130_lookup_slot(ste->nexus, 6207c478bd9Sstevel@tonic-gate ste->hpc3130_slot_info.pci_dev_num)); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate if (unitp->events[port] & HPC3130_IEVENT_OCCUPANCY) { 6247c478bd9Sstevel@tonic-gate unitp->events[port] &= ~HPC3130_IEVENT_OCCUPANCY; 6257c478bd9Sstevel@tonic-gate ev.id = (unitp->present[port] == B_FALSE ? 6267c478bd9Sstevel@tonic-gate HPC3130_EVENT_REMOVAL : 6277c478bd9Sstevel@tonic-gate HPC3130_EVENT_INSERTION); 6287c478bd9Sstevel@tonic-gate } else if (unitp->events[port] & HPC3130_IEVENT_POWER) { 6297c478bd9Sstevel@tonic-gate unitp->events[port] &= ~HPC3130_IEVENT_POWER; 6307c478bd9Sstevel@tonic-gate ev.id = (unitp->power[port] == B_TRUE ? 6317c478bd9Sstevel@tonic-gate HPC3130_EVENT_POWERON : 6327c478bd9Sstevel@tonic-gate HPC3130_EVENT_POWEROFF); 6337c478bd9Sstevel@tonic-gate } else if (unitp->events[port] & HPC3130_IEVENT_BUTTON) { 6347c478bd9Sstevel@tonic-gate unitp->events[port] &= ~HPC3130_IEVENT_BUTTON; 6357c478bd9Sstevel@tonic-gate ev.id = HPC3130_EVENT_BUTTON; 6367c478bd9Sstevel@tonic-gate } else if (unitp->events[port] & HPC3130_IEVENT_FAULT) { 6377c478bd9Sstevel@tonic-gate unitp->events[port] &= ~HPC3130_IEVENT_FAULT; 6387c478bd9Sstevel@tonic-gate ev.id = (unitp->fault_led[port] == HPC3130_ATTN_ON ? 6397c478bd9Sstevel@tonic-gate HPC3130_LED_FAULT_ON : 6407c478bd9Sstevel@tonic-gate HPC3130_LED_FAULT_OFF); 6417c478bd9Sstevel@tonic-gate } else if (unitp->events[port] & HPC3130_IEVENT_OK2REM) { 6427c478bd9Sstevel@tonic-gate unitp->events[port] &= ~HPC3130_IEVENT_OK2REM; 6437c478bd9Sstevel@tonic-gate ev.id = (unitp->ok2rem_led[port] == HPC3130_ATTN_ON ? 6447c478bd9Sstevel@tonic-gate HPC3130_LED_REMOVABLE_ON : 6457c478bd9Sstevel@tonic-gate HPC3130_LED_REMOVABLE_OFF); 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, 6497c478bd9Sstevel@tonic-gate "sending EVENT: ap_id=%s, event=%d", ev.name, ev.id)); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate if (ddi_copyout((caddr_t)&ev, (caddr_t)arg, 6527c478bd9Sstevel@tonic-gate sizeof (struct hpc3130_event), mode) != DDI_SUCCESS) { 6537c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_WARN, "Failed in hpc3130_ioctl" 6547c478bd9Sstevel@tonic-gate " ddi_copyout routine")); 6557c478bd9Sstevel@tonic-gate err = EFAULT; 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate break; 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate case HPC3130_CONF_DR: { 6607c478bd9Sstevel@tonic-gate uint8_t offset; 6617c478bd9Sstevel@tonic-gate int dr_conf; 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate if (ddi_copyin((caddr_t)arg, (caddr_t)&dr_conf, 6647c478bd9Sstevel@tonic-gate sizeof (int), mode) != DDI_SUCCESS) { 6657c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Failed in HPC3130_CONF_DR " 6667c478bd9Sstevel@tonic-gate "ddi_copyin routine")) 6677c478bd9Sstevel@tonic-gate err = EFAULT; 6687c478bd9Sstevel@tonic-gate break; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate offset = ste->callback_info.offset; 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate unitp->enabled[offset] = 6747c478bd9Sstevel@tonic-gate (dr_conf == HPC3130_DR_DISABLE ? B_FALSE : B_TRUE); 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate break; 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate default: 6797c478bd9Sstevel@tonic-gate D2CMN_ERR((CE_WARN, "Invalid IOCTL cmd: %x", cmd)); 6807c478bd9Sstevel@tonic-gate err = EINVAL; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate mutex_exit(&unitp->hpc3130_mutex); 6847c478bd9Sstevel@tonic-gate return (err); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate static int 6887c478bd9Sstevel@tonic-gate hpc3130_poll(dev_t dev, short events, int anyyet, short 6897c478bd9Sstevel@tonic-gate *reventsp, struct pollhead **phpp) 6907c478bd9Sstevel@tonic-gate { 6917c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(events)) 6927c478bd9Sstevel@tonic-gate hpc3130_unit_t *unitp; 6937c478bd9Sstevel@tonic-gate int port = MINOR_TO_PORT(getminor(dev)); 6947c478bd9Sstevel@tonic-gate int instance = MINOR_TO_INST(getminor(dev)); 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate if (!(port >= 0 && port < HPC3130_MAX_SLOT)) { 6977c478bd9Sstevel@tonic-gate return (EINVAL); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate unitp = (hpc3130_unit_t *) 7007c478bd9Sstevel@tonic-gate ddi_get_soft_state(hpc3130soft_statep, instance); 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate mutex_enter(&unitp->hpc3130_mutex); 7037c478bd9Sstevel@tonic-gate if (unitp->events[port]) { 7047c478bd9Sstevel@tonic-gate *reventsp = POLLIN; 7057c478bd9Sstevel@tonic-gate } else { 7067c478bd9Sstevel@tonic-gate *reventsp = 0; 7077c478bd9Sstevel@tonic-gate if (!anyyet) 7087c478bd9Sstevel@tonic-gate *phpp = &unitp->pollhead[port]; 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate mutex_exit(&unitp->hpc3130_mutex); 7117c478bd9Sstevel@tonic-gate return (0); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate /* ARGSUSED */ 7157c478bd9Sstevel@tonic-gate static int 7167c478bd9Sstevel@tonic-gate hpc3130_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 7177c478bd9Sstevel@tonic-gate { 7187c478bd9Sstevel@tonic-gate dev_t dev; 7197c478bd9Sstevel@tonic-gate int instance; 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate if (infocmd == DDI_INFO_DEVT2INSTANCE) { 7227c478bd9Sstevel@tonic-gate dev = (dev_t)arg; 7237c478bd9Sstevel@tonic-gate instance = MINOR_TO_INST(getminor(dev)); 7247c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 7257c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate static int 7317c478bd9Sstevel@tonic-gate hpc3130_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 7327c478bd9Sstevel@tonic-gate { 7337c478bd9Sstevel@tonic-gate switch (cmd) { 7347c478bd9Sstevel@tonic-gate case DDI_ATTACH: 7357c478bd9Sstevel@tonic-gate return (hpc3130_do_attach(dip)); 7367c478bd9Sstevel@tonic-gate case DDI_RESUME: 7377c478bd9Sstevel@tonic-gate return (hpc3130_do_resume()); 7387c478bd9Sstevel@tonic-gate default: 7397c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate static int 7447c478bd9Sstevel@tonic-gate hpc3130_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 7457c478bd9Sstevel@tonic-gate { 7467c478bd9Sstevel@tonic-gate switch (cmd) { 7477c478bd9Sstevel@tonic-gate case DDI_DETACH: 7487c478bd9Sstevel@tonic-gate return (hpc3130_do_detach(dip)); 7497c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 7507c478bd9Sstevel@tonic-gate return (hpc3130_do_suspend()); 7517c478bd9Sstevel@tonic-gate default: 7527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate static int 7577c478bd9Sstevel@tonic-gate hpc3130_do_attach(dev_info_t *dip) 7587c478bd9Sstevel@tonic-gate { 7597c478bd9Sstevel@tonic-gate hpc3130_unit_t *hpc3130_p; 7607c478bd9Sstevel@tonic-gate char *s; 7617c478bd9Sstevel@tonic-gate char *nexus; 7627c478bd9Sstevel@tonic-gate char *pcidev; 7637c478bd9Sstevel@tonic-gate char *reg_offset; 7647c478bd9Sstevel@tonic-gate int r, i, n, j; 7657c478bd9Sstevel@tonic-gate char name[MAXNAMELEN]; 7667c478bd9Sstevel@tonic-gate minor_t minor_number; 7677c478bd9Sstevel@tonic-gate int hpc3130_pil = HPC3130_PIL; 7687c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * Allocate the soft state structure for this instance. 7727c478bd9Sstevel@tonic-gate */ 7737c478bd9Sstevel@tonic-gate r = ddi_soft_state_zalloc(hpc3130soft_statep, instance); 7747c478bd9Sstevel@tonic-gate if (r != DDI_SUCCESS) { 7757c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate hpc3130_p = 7797c478bd9Sstevel@tonic-gate (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep, instance); 7807c478bd9Sstevel@tonic-gate ASSERT(hpc3130_p); 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 7837c478bd9Sstevel@tonic-gate "interrupt-priorities", (caddr_t)&hpc3130_pil, 7847c478bd9Sstevel@tonic-gate sizeof (hpc3130_pil)) != DDI_PROP_SUCCESS) { 7857c478bd9Sstevel@tonic-gate goto failout0; 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate if (ddi_intr_hilevel(dip, 0)) { 7897c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "High level interrupt not supported"); 7907c478bd9Sstevel@tonic-gate goto failout0; 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate /* 7947c478bd9Sstevel@tonic-gate * Get the "slot-table" property which defines the list of 7957c478bd9Sstevel@tonic-gate * hot-pluggable slots for this controller along with the 7967c478bd9Sstevel@tonic-gate * corresponding bus nexus node and device identification 7977c478bd9Sstevel@tonic-gate * for each slot. 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 8007c478bd9Sstevel@tonic-gate "slot-table", (caddr_t)&hpc3130_p->hpc3130_slot_table_data, 8017c478bd9Sstevel@tonic-gate &hpc3130_p->hpc3130_slot_table_size); 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate switch (r) { 8047c478bd9Sstevel@tonic-gate case DDI_PROP_SUCCESS: 8057c478bd9Sstevel@tonic-gate break; 8067c478bd9Sstevel@tonic-gate case DDI_PROP_NOT_FOUND: 8077c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8087c478bd9Sstevel@tonic-gate "couldn't find slot-table property"); 8097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8107c478bd9Sstevel@tonic-gate case DDI_PROP_UNDEFINED: 8117c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8127c478bd9Sstevel@tonic-gate "slot-table undefined"); 8137c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8147c478bd9Sstevel@tonic-gate case DDI_PROP_NO_MEMORY: 8157c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8167c478bd9Sstevel@tonic-gate "can't allocate memory for slot-table"); 8177c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * Determine the size of the slot table from the OBP property and 8227c478bd9Sstevel@tonic-gate * allocate the slot table arrary.. 8237c478bd9Sstevel@tonic-gate */ 8247c478bd9Sstevel@tonic-gate for (i = 0, n = 0; i < hpc3130_p->hpc3130_slot_table_size; i++) { 8257c478bd9Sstevel@tonic-gate if (hpc3130_p->hpc3130_slot_table_data[i] == 0) { 8267c478bd9Sstevel@tonic-gate n++; 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "hpc3130_attach(): slot table has %d entries", n)); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate /* 8337c478bd9Sstevel@tonic-gate * There should be HPC3130_TABLE_COLUMNS elements per entry 8347c478bd9Sstevel@tonic-gate */ 8357c478bd9Sstevel@tonic-gate if (n % HPC3130_TABLE_COLUMNS) { 8367c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "bad format in slot-table"); 8377c478bd9Sstevel@tonic-gate goto failout1; 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate hpc3130_p->dip = dip; 8417c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_table_length = n / HPC3130_TABLE_COLUMNS; 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, 0, &hpc3130_p->ic_trap_cookie) != 8447c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 8457c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ddi_get_iblock_cookie FAILED"); 8467c478bd9Sstevel@tonic-gate goto failout1; 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate mutex_init(&hpc3130_p->hpc3130_mutex, NULL, MUTEX_DRIVER, 8507c478bd9Sstevel@tonic-gate (void *)hpc3130_p->ic_trap_cookie); 8517c478bd9Sstevel@tonic-gate /* 8527c478bd9Sstevel@tonic-gate * Create enough space for each slot table entry 8537c478bd9Sstevel@tonic-gate * based on how many entries in the property 8547c478bd9Sstevel@tonic-gate */ 8557c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_table = (hpc3130_slot_table_entry_t *) 8567c478bd9Sstevel@tonic-gate kmem_zalloc(hpc3130_p->hpc3130_slot_table_length * 8577c478bd9Sstevel@tonic-gate sizeof (hpc3130_slot_table_entry_t), KM_SLEEP); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* 8607c478bd9Sstevel@tonic-gate * Setup to talk to the i2c nexus 8617c478bd9Sstevel@tonic-gate */ 8627c478bd9Sstevel@tonic-gate if (i2c_client_register(dip, &hpc3130_p->hpc3130_hdl) != I2C_SUCCESS) { 8637c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "failed to register as i2c client"); 8647c478bd9Sstevel@tonic-gate goto failout2; 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate s = hpc3130_p->hpc3130_slot_table_data; 8687c478bd9Sstevel@tonic-gate for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) { 8697c478bd9Sstevel@tonic-gate hpc3130_slot_table_entry_t *ste; 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate /* Pick off pointer to nexus path */ 8727c478bd9Sstevel@tonic-gate nexus = s; 8737c478bd9Sstevel@tonic-gate s = s + strlen(s) + 1; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* Pick off pointer to 3130 register offset */ 8767c478bd9Sstevel@tonic-gate reg_offset = s; 8777c478bd9Sstevel@tonic-gate s = s + strlen(s) + 1; 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate /* Pick off pointer to the device number */ 8807c478bd9Sstevel@tonic-gate pcidev = s; 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate s = s + strlen(s) + 1; 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate j = hpc3130_atoi(reg_offset); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate if (j < 0 || j >= HPC3130_MAX_SLOT) { 8877c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8887c478bd9Sstevel@tonic-gate "invalid register offset value"); 8897c478bd9Sstevel@tonic-gate goto failout3; 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate ste = &hpc3130_p->hpc3130_slot_table[j]; 8937c478bd9Sstevel@tonic-gate 894*07d06da5SSurya Prakki (void) strcpy(ste->nexus, nexus); 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate if (strncmp(ste->nexus, "/pci", 4) == 0) { 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate ste->hpc3130_slot_info.pci_dev_num = 8997c478bd9Sstevel@tonic-gate hpc3130_atoi(pcidev); 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate DAK_GET_PCI_APID(ste->hpc3130_slot_info.pci_slot_name, 9027c478bd9Sstevel@tonic-gate PCI_SLOT_NAME_LEN, 9037c478bd9Sstevel@tonic-gate hpc3130_lookup_slot(ste->nexus, 9047c478bd9Sstevel@tonic-gate hpc3130_atoi(pcidev))); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate ste->hpc3130_slot_info.slot_type = HPC_SLOT_TYPE_PCI; 9077c478bd9Sstevel@tonic-gate ste->hpc3130_slot_info.slot_flags = 9087c478bd9Sstevel@tonic-gate HPC_SLOT_CREATE_DEVLINK; 9097c478bd9Sstevel@tonic-gate hpc3130_p->slots_are = HPC3130_SLOT_TYPE_PCI; 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate } else { 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate ste->hpc3130_slot_info.sbd_slot_num = 9147c478bd9Sstevel@tonic-gate hpc3130_atoi(reg_offset); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate ste->hpc3130_slot_info.slot_type = HPC_SLOT_TYPE_SBD; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate hpc3130_p->slots_are = HPC3130_SLOT_TYPE_SBD; 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate hpc3130_p->present[j] = B_FALSE; 9227c478bd9Sstevel@tonic-gate hpc3130_p->enabled[j] = B_TRUE; 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /* 9257c478bd9Sstevel@tonic-gate * The "callback_info" structure of the slot_table is what gets 9267c478bd9Sstevel@tonic-gate * passed back in the callback routines. All that is needed 9277c478bd9Sstevel@tonic-gate * at that point is the device handle and the register offset 9287c478bd9Sstevel@tonic-gate * within it the chip it represents. 9297c478bd9Sstevel@tonic-gate */ 9307c478bd9Sstevel@tonic-gate ste->callback_info.handle = (caddr_t)hpc3130_p->hpc3130_hdl; 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate ste->callback_info.offset = hpc3130_atoi(reg_offset); 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate ste->callback_info.statep = (caddr_t)hpc3130_p; 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_ops = hpc_alloc_slot_ops(KM_SLEEP); 9387c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_ops->hpc_version = 0; 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_ops->hpc_op_connect = hpc3130_slot_connect; 9417c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_ops->hpc_op_disconnect = 9427c478bd9Sstevel@tonic-gate hpc3130_slot_disconnect; 9437c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_ops->hpc_op_insert = hpc3130_slot_insert; 9447c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_ops->hpc_op_remove = hpc3130_slot_remove; 9457c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_ops->hpc_op_control = hpc3130_slot_control; 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate cv_init(&hpc3130_p->hpc3130_cond, NULL, CV_DEFAULT, NULL); 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate if (hpc3130_init(dip, (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) ? 9507c478bd9Sstevel@tonic-gate cpu_sequence : pci_sequence) != DDI_SUCCESS) { 9517c478bd9Sstevel@tonic-gate goto failout4; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, 0, &hpc3130_p->ic_trap_cookie, 9557c478bd9Sstevel@tonic-gate NULL, hpc3130_hard_intr, 9567c478bd9Sstevel@tonic-gate (caddr_t)hpc3130_p) != DDI_SUCCESS) { 9577c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "failed to add interrupt"); 9587c478bd9Sstevel@tonic-gate goto failout4; 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate /* 9627c478bd9Sstevel@tonic-gate * Register with the "services" module 9637c478bd9Sstevel@tonic-gate */ 9647c478bd9Sstevel@tonic-gate for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) { 9657c478bd9Sstevel@tonic-gate hpc3130_slot_table_entry_t *ste = 9667c478bd9Sstevel@tonic-gate &hpc3130_p->hpc3130_slot_table[i]; 9677c478bd9Sstevel@tonic-gate hpc3130_p->power[i] = B_TRUE; 9687c478bd9Sstevel@tonic-gate if (ste->callback_info.handle != NULL) { 969*07d06da5SSurya Prakki (void) hpc_slot_register(dip, ste->nexus, 9707c478bd9Sstevel@tonic-gate &ste->hpc3130_slot_info, 9717c478bd9Sstevel@tonic-gate &ste->hpc3130_slot_handle, 9727c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_ops, 9737c478bd9Sstevel@tonic-gate (caddr_t)&ste->callback_info, 0); 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate (void) snprintf(hpc3130_p->hpc3130_name, 9787c478bd9Sstevel@tonic-gate sizeof (hpc3130_p->hpc3130_name), 9797c478bd9Sstevel@tonic-gate "%s%d", ddi_node_name(dip), instance); 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate for (i = 0; i < HPC3130_MAX_SLOT; i++) { 9827c478bd9Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "port_%d", i); 9837c478bd9Sstevel@tonic-gate minor_number = INST_TO_MINOR(instance) | 9847c478bd9Sstevel@tonic-gate PORT_TO_MINOR(I2C_PORT(i)); 9857c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, name, S_IFCHR, minor_number, 9867c478bd9Sstevel@tonic-gate "ddi_i2c:controller", NULL) == DDI_FAILURE) { 9877c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_WARN, "ddi_create_minor_node failed " 9887c478bd9Sstevel@tonic-gate "for %s", name)); 9897c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0u, 9907c478bd9Sstevel@tonic-gate hpc3130_p->ic_trap_cookie); 9917c478bd9Sstevel@tonic-gate goto failout4; 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate failout4: 9987c478bd9Sstevel@tonic-gate hpc_free_slot_ops(hpc3130_p->hpc3130_slot_ops); 9997c478bd9Sstevel@tonic-gate failout3: 10007c478bd9Sstevel@tonic-gate i2c_client_unregister(hpc3130_p->hpc3130_hdl); 10017c478bd9Sstevel@tonic-gate failout2: 10027c478bd9Sstevel@tonic-gate mutex_destroy(&hpc3130_p->hpc3130_mutex); 10037c478bd9Sstevel@tonic-gate kmem_free(hpc3130_p->hpc3130_slot_table, 10047c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_table_length * 10057c478bd9Sstevel@tonic-gate sizeof (hpc3130_slot_table_entry_t)); 10067c478bd9Sstevel@tonic-gate failout1: 10077c478bd9Sstevel@tonic-gate kmem_free(hpc3130_p->hpc3130_slot_table_data, 10087c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_table_size); 10097c478bd9Sstevel@tonic-gate failout0: 10107c478bd9Sstevel@tonic-gate ddi_soft_state_free(hpc3130soft_statep, instance); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate static int 10167c478bd9Sstevel@tonic-gate hpc3130_do_resume() 10177c478bd9Sstevel@tonic-gate { 10187c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate static int 10227c478bd9Sstevel@tonic-gate hpc3130_do_suspend() 10237c478bd9Sstevel@tonic-gate { 10247c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate static int 10287c478bd9Sstevel@tonic-gate hpc3130_do_detach(dev_info_t *dip) 10297c478bd9Sstevel@tonic-gate { 10307c478bd9Sstevel@tonic-gate int i; 10317c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 10327c478bd9Sstevel@tonic-gate hpc3130_unit_t *hpc3130_p; 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate hpc3130_p = (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep, 10357c478bd9Sstevel@tonic-gate instance); 10367c478bd9Sstevel@tonic-gate if (hpc3130_p == NULL) 10377c478bd9Sstevel@tonic-gate return (ENXIO); 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate i2c_client_unregister(hpc3130_p->hpc3130_hdl); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, 0u, hpc3130_p->ic_trap_cookie); 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate cv_destroy(&hpc3130_p->hpc3130_cond); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) { 1046*07d06da5SSurya Prakki (void) hpc_slot_unregister( 10477c478bd9Sstevel@tonic-gate &hpc3130_p->hpc3130_slot_table[i].hpc3130_slot_handle); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate kmem_free(hpc3130_p->hpc3130_slot_table, 10517c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_table_length * 10527c478bd9Sstevel@tonic-gate sizeof (hpc3130_slot_table_entry_t)); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate kmem_free(hpc3130_p->hpc3130_slot_table_data, 10557c478bd9Sstevel@tonic-gate hpc3130_p->hpc3130_slot_table_size); 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate hpc_free_slot_ops(hpc3130_p->hpc3130_slot_ops); 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate mutex_destroy(&hpc3130_p->hpc3130_mutex); 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate ddi_soft_state_free(hpc3130soft_statep, instance); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate int 10677c478bd9Sstevel@tonic-gate hpc3130_set_led(hpc3130_unit_t *unitp, int slot, int led, uint8_t value) 10687c478bd9Sstevel@tonic-gate { 10697c478bd9Sstevel@tonic-gate i2c_client_hdl_t handle = unitp->hpc3130_hdl; 10707c478bd9Sstevel@tonic-gate uint8_t old; 10717c478bd9Sstevel@tonic-gate uint8_t new; 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_ATTEN, slot, &old) != DDI_SUCCESS) { 10747c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate new = (old & ~HPC3130_ATTN_MASK(led)) | 10777c478bd9Sstevel@tonic-gate value << HPC3130_ATTN_SHIFT(led); 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "setting led %d to %x", led, value)); 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate if (hpc3130_write(handle, HPC3130_ATTEN, slot, new) != DDI_SUCCESS) { 10827c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate if ((value == HPC3130_ATTN_OFF || value == HPC3130_ATTN_ON) && 10867c478bd9Sstevel@tonic-gate ((old & HPC3130_ATTN_MASK(led)) != 10877c478bd9Sstevel@tonic-gate (new & HPC3130_ATTN_MASK(led)))) { 10887c478bd9Sstevel@tonic-gate /* 10897c478bd9Sstevel@tonic-gate * We're turning a LED on or off (i.e., not blinking), and 10907c478bd9Sstevel@tonic-gate * the value actually did change. 10917c478bd9Sstevel@tonic-gate */ 10927c478bd9Sstevel@tonic-gate if (led == HPC3130_LED_OK2REM) { 10937c478bd9Sstevel@tonic-gate unitp->events[slot] |= HPC3130_IEVENT_OK2REM; 10947c478bd9Sstevel@tonic-gate unitp->ok2rem_led[slot] = value; 10957c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, 10967c478bd9Sstevel@tonic-gate "recording IEVENT_OK2REM slot=%d, val=%d", 10977c478bd9Sstevel@tonic-gate slot, value)); 10987c478bd9Sstevel@tonic-gate } else { 10997c478bd9Sstevel@tonic-gate unitp->events[slot] |= HPC3130_IEVENT_FAULT; 11007c478bd9Sstevel@tonic-gate unitp->fault_led[slot] = value; 11017c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, 11027c478bd9Sstevel@tonic-gate "recording IEVENT_FAULT slot=%d, val=%d", 11037c478bd9Sstevel@tonic-gate slot, value)); 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&unitp->hpc3130_mutex)); 11067c478bd9Sstevel@tonic-gate mutex_exit(&unitp->hpc3130_mutex); 11077c478bd9Sstevel@tonic-gate pollwakeup(&unitp->pollhead[slot], POLLIN); 11087c478bd9Sstevel@tonic-gate mutex_enter(&unitp->hpc3130_mutex); 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate int 11147c478bd9Sstevel@tonic-gate hpc3130_get_led(i2c_client_hdl_t handle, int slot, 11157c478bd9Sstevel@tonic-gate int led, uint8_t *value) 11167c478bd9Sstevel@tonic-gate { 11177c478bd9Sstevel@tonic-gate uint8_t temp; 11187c478bd9Sstevel@tonic-gate 11197c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_ATTEN, slot, &temp) != DDI_SUCCESS) { 11207c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate *value = (temp & HPC3130_ATTN_MASK(led)) >> HPC3130_ATTN_SHIFT(led); 11247c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate static int 11287c478bd9Sstevel@tonic-gate hpc3130_write(i2c_client_hdl_t handle, uint8_t offset, 11297c478bd9Sstevel@tonic-gate uint8_t port, uint8_t data) 11307c478bd9Sstevel@tonic-gate { 1131f47a9c50Smathue ASSERT(port < HPC3130_MAX_SLOT); 11327c478bd9Sstevel@tonic-gate ASSERT(handle); 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate return (hpc3130_rw(handle, 11357c478bd9Sstevel@tonic-gate HPC3130_REG(offset, port), B_TRUE, &data)); 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate static int 11397c478bd9Sstevel@tonic-gate hpc3130_read(i2c_client_hdl_t handle, uint8_t offset, 11407c478bd9Sstevel@tonic-gate uint8_t port, uint8_t *data) 11417c478bd9Sstevel@tonic-gate { 1142f47a9c50Smathue ASSERT(port < HPC3130_MAX_SLOT); 11437c478bd9Sstevel@tonic-gate ASSERT(handle); 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate return (hpc3130_rw(handle, 11467c478bd9Sstevel@tonic-gate HPC3130_REG(offset, port), B_FALSE, data)); 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate static int 11507c478bd9Sstevel@tonic-gate hpc3130_rw(i2c_client_hdl_t handle, uint8_t reg, 11517c478bd9Sstevel@tonic-gate boolean_t write, uint8_t *data) 11527c478bd9Sstevel@tonic-gate { 11537c478bd9Sstevel@tonic-gate i2c_transfer_t *i2c_tran_pointer; 11547c478bd9Sstevel@tonic-gate int err; 11557c478bd9Sstevel@tonic-gate int rlen; 11567c478bd9Sstevel@tonic-gate int wlen; 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate if (write == B_TRUE) { 11597c478bd9Sstevel@tonic-gate wlen = 2; 11607c478bd9Sstevel@tonic-gate rlen = 0; 11617c478bd9Sstevel@tonic-gate } else { 11627c478bd9Sstevel@tonic-gate wlen = 1; 11637c478bd9Sstevel@tonic-gate rlen = 1; 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate (void) i2c_transfer_alloc(handle, 11677c478bd9Sstevel@tonic-gate &i2c_tran_pointer, wlen, rlen, I2C_SLEEP); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate if (i2c_tran_pointer == NULL) { 11707c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_WARN, "Failed in hpc3130_rw: " 11717c478bd9Sstevel@tonic-gate "no transfer structure 0x%x", reg)); 11727c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[0] = reg; 11757c478bd9Sstevel@tonic-gate if (write == B_TRUE) { 11767c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_flags = I2C_WR; 11777c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_wbuf[1] = *data; 11787c478bd9Sstevel@tonic-gate } else { 11797c478bd9Sstevel@tonic-gate i2c_tran_pointer->i2c_flags = I2C_WR_RD; 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate err = i2c_transfer(handle, i2c_tran_pointer); 11837c478bd9Sstevel@tonic-gate if (err) { 11847c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_WARN, "Failed in hpc3130_rw: " 11857c478bd9Sstevel@tonic-gate "no I2C data transfered 0x%x", reg)); 11867c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(handle, i2c_tran_pointer); 11877c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate if (write == B_FALSE) 11917c478bd9Sstevel@tonic-gate *data = i2c_tran_pointer->i2c_rbuf[0]; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate (void) i2c_transfer_free(handle, i2c_tran_pointer); 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate /* 11997c478bd9Sstevel@tonic-gate * Put the hot plug controller(s) in proper mode for further 12007c478bd9Sstevel@tonic-gate * operations. 12017c478bd9Sstevel@tonic-gate */ 12027c478bd9Sstevel@tonic-gate static int 12037c478bd9Sstevel@tonic-gate hpc3130_init(dev_info_t *dip, 12047c478bd9Sstevel@tonic-gate struct tuple *init_sequence) 12057c478bd9Sstevel@tonic-gate { 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate int slot; 12087c478bd9Sstevel@tonic-gate i2c_client_hdl_t handle; 12097c478bd9Sstevel@tonic-gate hpc3130_unit_t *hpc3130_p; 12107c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 12117c478bd9Sstevel@tonic-gate int error = DDI_FAILURE; 12127c478bd9Sstevel@tonic-gate struct tuple *tp; 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate hpc3130_p = 12157c478bd9Sstevel@tonic-gate (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep, 12167c478bd9Sstevel@tonic-gate instance); 12177c478bd9Sstevel@tonic-gate ASSERT(hpc3130_p); 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate mutex_enter(&hpc3130_p->hpc3130_mutex); 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate handle = hpc3130_p->hpc3130_hdl; 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate for (slot = 0; slot < HPC3130_MAX_SLOT; slot++) { 12247c478bd9Sstevel@tonic-gate tp = init_sequence; 12257c478bd9Sstevel@tonic-gate while (tp->reg != HPC3130_NO_REGISTER) { 12267c478bd9Sstevel@tonic-gate if (hpc3130_write(handle, tp->reg, slot, 12277c478bd9Sstevel@tonic-gate tp->val) != DDI_SUCCESS) { 12287c478bd9Sstevel@tonic-gate goto out; 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate tp++; 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate /* 12337c478bd9Sstevel@tonic-gate * CPU slots need some special initialization 12347c478bd9Sstevel@tonic-gate * attention. 12357c478bd9Sstevel@tonic-gate */ 12367c478bd9Sstevel@tonic-gate if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) { 12377c478bd9Sstevel@tonic-gate if (hpc3130_cpu_init(hpc3130_p, slot, handle) 12387c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 12397c478bd9Sstevel@tonic-gate goto out; 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 12447c478bd9Sstevel@tonic-gate out: 12457c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 12467c478bd9Sstevel@tonic-gate 12477c478bd9Sstevel@tonic-gate return (error); 12487c478bd9Sstevel@tonic-gate } 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate /* 12517c478bd9Sstevel@tonic-gate * When the TI 3130 produces an interrupt, 12527c478bd9Sstevel@tonic-gate * this routine is called to sort it out. 12537c478bd9Sstevel@tonic-gate */ 12547c478bd9Sstevel@tonic-gate static uint_t 12557c478bd9Sstevel@tonic-gate hpc3130_hard_intr(caddr_t arg) 12567c478bd9Sstevel@tonic-gate { 12577c478bd9Sstevel@tonic-gate uint8_t interrupt; 12587c478bd9Sstevel@tonic-gate uint8_t status; 12597c478bd9Sstevel@tonic-gate uint8_t slot; 12607c478bd9Sstevel@tonic-gate i2c_client_hdl_t handle; 12617c478bd9Sstevel@tonic-gate hpc3130_slot_type_t slot_type; 12627c478bd9Sstevel@tonic-gate uint_t rc = DDI_INTR_UNCLAIMED; 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate hpc3130_unit_t *hpc3130_p = (hpc3130_unit_t *)arg; 12657c478bd9Sstevel@tonic-gate ASSERT(hpc3130_p); 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate mutex_enter(&hpc3130_p->hpc3130_mutex); 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate slot_type = hpc3130_p->slots_are; 12707c478bd9Sstevel@tonic-gate handle = hpc3130_p->hpc3130_hdl; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate for (slot = 0; slot < HPC3130_MAX_SLOT; slot++) { 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate /* 12757c478bd9Sstevel@tonic-gate * Read the interrupt event register - see 12767c478bd9Sstevel@tonic-gate * which event(s) took place. 12777c478bd9Sstevel@tonic-gate */ 12787c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_EVENT_STATUS, slot, 12797c478bd9Sstevel@tonic-gate &interrupt)) { 12807c478bd9Sstevel@tonic-gate continue; 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate if (interrupt == 0) 12847c478bd9Sstevel@tonic-gate continue; 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate rc = DDI_INTR_CLAIMED; 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate if (hpc3130_debounce_status(handle, 12897c478bd9Sstevel@tonic-gate slot, &status) != DDI_SUCCESS) { 12907c478bd9Sstevel@tonic-gate continue; 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate if (interrupt & HPC3130_PWRGOOD) { 12947c478bd9Sstevel@tonic-gate hpc3130_p->power[slot] = B_FALSE; 12957c478bd9Sstevel@tonic-gate if (!(status & HPC3130_PWRGOOD)) { 12967c478bd9Sstevel@tonic-gate hpc3130_p->power[slot] = B_TRUE; 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate cv_signal(&hpc3130_p->hpc3130_cond); 12997c478bd9Sstevel@tonic-gate hpc3130_p->events[slot] |= HPC3130_IEVENT_POWER; 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate if (interrupt & HPC3130_DETECT0) { 13037c478bd9Sstevel@tonic-gate if (slot_type == HPC3130_SLOT_TYPE_SBD) { 13047c478bd9Sstevel@tonic-gate boolean_t present = !(status&HPC3130_DETECT0); 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate /* Turn ON/OFF OK-to-remove LED */ 13077c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, 13087c478bd9Sstevel@tonic-gate slot, 13097c478bd9Sstevel@tonic-gate HPC3130_LED_OK2REM, 13107c478bd9Sstevel@tonic-gate (present ? HPC3130_ATTN_ON : 13117c478bd9Sstevel@tonic-gate HPC3130_ATTN_OFF)); 13127c478bd9Sstevel@tonic-gate if (!present) { 13137c478bd9Sstevel@tonic-gate /* Clear the FAULT LED on removal */ 13147c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, 13157c478bd9Sstevel@tonic-gate slot, 13167c478bd9Sstevel@tonic-gate HPC3130_LED_FAULT, 13177c478bd9Sstevel@tonic-gate HPC3130_ATTN_OFF); 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate hpc3130_p->present[slot] = present; 13217c478bd9Sstevel@tonic-gate hpc3130_p->events[slot] |= 13227c478bd9Sstevel@tonic-gate HPC3130_IEVENT_OCCUPANCY; 13237c478bd9Sstevel@tonic-gate } else { 13247c478bd9Sstevel@tonic-gate ASSERT(slot_type == HPC3130_SLOT_TYPE_PCI); 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate if (!(status & HPC3130_DETECT0)) { 13277c478bd9Sstevel@tonic-gate /* 13287c478bd9Sstevel@tonic-gate * Event on the downward 13297c478bd9Sstevel@tonic-gate * stroke of the button. 13307c478bd9Sstevel@tonic-gate */ 13317c478bd9Sstevel@tonic-gate hpc3130_p->events[slot] |= 13327c478bd9Sstevel@tonic-gate HPC3130_IEVENT_BUTTON; 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate if (interrupt & (HPC3130_PRSNT1 | HPC3130_PRSNT2)) { 13387c478bd9Sstevel@tonic-gate if (slot_type == HPC3130_SLOT_TYPE_SBD) { 13397c478bd9Sstevel@tonic-gate if (!(status & HPC3130_PRSNT1)) { 13407c478bd9Sstevel@tonic-gate /* 13417c478bd9Sstevel@tonic-gate * Event only on the downward 13427c478bd9Sstevel@tonic-gate * stroke of the button. 13437c478bd9Sstevel@tonic-gate */ 13447c478bd9Sstevel@tonic-gate hpc3130_p->events[slot] |= 13457c478bd9Sstevel@tonic-gate HPC3130_IEVENT_BUTTON; 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate } else { 13487c478bd9Sstevel@tonic-gate ASSERT(slot_type == HPC3130_SLOT_TYPE_PCI); 13497c478bd9Sstevel@tonic-gate if ((status & (HPC3130_PRSNT1 | 13507c478bd9Sstevel@tonic-gate HPC3130_PRSNT2)) == 13517c478bd9Sstevel@tonic-gate (HPC3130_PRSNT1 | HPC3130_PRSNT2)) { 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate hpc3130_p->present[slot] = B_FALSE; 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate /* Turn OFF Fault LED */ 13567c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, 13577c478bd9Sstevel@tonic-gate slot, 13587c478bd9Sstevel@tonic-gate HPC3130_LED_FAULT, 13597c478bd9Sstevel@tonic-gate HPC3130_ATTN_OFF); 13607c478bd9Sstevel@tonic-gate /* Turn OFF OK-to-remove LED */ 13617c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, 13627c478bd9Sstevel@tonic-gate slot, 13637c478bd9Sstevel@tonic-gate HPC3130_LED_OK2REM, 13647c478bd9Sstevel@tonic-gate HPC3130_ATTN_OFF); 13657c478bd9Sstevel@tonic-gate } else { 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate hpc3130_p->present[slot] = B_TRUE; 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate /* Turn ON OK-to-remove LED */ 13707c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, 13717c478bd9Sstevel@tonic-gate slot, 13727c478bd9Sstevel@tonic-gate HPC3130_LED_OK2REM, 13737c478bd9Sstevel@tonic-gate HPC3130_ATTN_ON); 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate hpc3130_p->events[slot] |= 13777c478bd9Sstevel@tonic-gate HPC3130_IEVENT_OCCUPANCY; 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate if (hpc3130_p->events[slot] && 13817c478bd9Sstevel@tonic-gate (hpc3130_p->present[slot] == B_TRUE)) { 13827c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 13837c478bd9Sstevel@tonic-gate pollwakeup(&hpc3130_p->pollhead[slot], POLLIN); 13847c478bd9Sstevel@tonic-gate mutex_enter(&hpc3130_p->hpc3130_mutex); 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate (void) hpc3130_write(handle, HPC3130_EVENT_STATUS, 13877c478bd9Sstevel@tonic-gate slot, interrupt); 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate return (rc); 13937c478bd9Sstevel@tonic-gate } 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate static int 13967c478bd9Sstevel@tonic-gate hpc3130_cpu_init(hpc3130_unit_t *hpc3130_p, int slot, i2c_client_hdl_t handle) 13977c478bd9Sstevel@tonic-gate { 13987c478bd9Sstevel@tonic-gate uint8_t slot_status; 13997c478bd9Sstevel@tonic-gate uint8_t control_reg; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate int result = HPC_ERR_FAILED; 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_STATUS, slot, 14047c478bd9Sstevel@tonic-gate &slot_status)) { 14057c478bd9Sstevel@tonic-gate goto out; 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_CONTROL, slot, 14097c478bd9Sstevel@tonic-gate &control_reg)) { 14107c478bd9Sstevel@tonic-gate goto out; 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate /* 14147c478bd9Sstevel@tonic-gate * For the CPU slots, the DETECT[0] pin on the HPC3130 14157c478bd9Sstevel@tonic-gate * goes low when a CPU module is in the slot. Pulled 14167c478bd9Sstevel@tonic-gate * high otherwise. 14177c478bd9Sstevel@tonic-gate */ 14187c478bd9Sstevel@tonic-gate if (slot_status & HPC3130_DETECT0) { 14197c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "hpc3130_cpu_init(): " 14207c478bd9Sstevel@tonic-gate "[0x%x]Power off....[%d]", 14217c478bd9Sstevel@tonic-gate slot_status, slot)); 14227c478bd9Sstevel@tonic-gate control_reg = control_reg & ~HPC3130_SLTPWRCTL; 14237c478bd9Sstevel@tonic-gate } else { 14247c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "hpc3130_cpu_init(): " 14257c478bd9Sstevel@tonic-gate "[0x%x]Power LEFT on!!!....[%d]", 14267c478bd9Sstevel@tonic-gate slot_status, slot)); 14277c478bd9Sstevel@tonic-gate hpc3130_p->present[slot] = B_TRUE; 14287c478bd9Sstevel@tonic-gate control_reg = control_reg | HPC3130_SLTPWRCTL; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate /* 14337c478bd9Sstevel@tonic-gate * Set the control register accordingly 14347c478bd9Sstevel@tonic-gate */ 14357c478bd9Sstevel@tonic-gate if (hpc3130_write(handle, HPC3130_CONTROL, 14367c478bd9Sstevel@tonic-gate slot, control_reg) != DDI_SUCCESS) { 14377c478bd9Sstevel@tonic-gate goto out; 14387c478bd9Sstevel@tonic-gate } 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate result = DDI_SUCCESS; 14417c478bd9Sstevel@tonic-gate out: 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate return (result); 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate static int 14477c478bd9Sstevel@tonic-gate hpc3130_debounce_status(i2c_client_hdl_t handle, 14487c478bd9Sstevel@tonic-gate int slot, uint8_t *status) 14497c478bd9Sstevel@tonic-gate { 14507c478bd9Sstevel@tonic-gate int count, limit; 14517c478bd9Sstevel@tonic-gate uint8_t old; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate ASSERT(status); 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate /* 14567c478bd9Sstevel@tonic-gate * Get HPC3130_DEBOUNCE_COUNT consecutive equal 14577c478bd9Sstevel@tonic-gate * readings from the status register 14587c478bd9Sstevel@tonic-gate */ 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate count = 0; limit = 0; old = 0xff; 14617c478bd9Sstevel@tonic-gate do { 14627c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_STATUS, 14637c478bd9Sstevel@tonic-gate slot, status)) { 14647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14657c478bd9Sstevel@tonic-gate } 14667c478bd9Sstevel@tonic-gate if (old != *status) { 14677c478bd9Sstevel@tonic-gate count = 0; 14687c478bd9Sstevel@tonic-gate } else { 14697c478bd9Sstevel@tonic-gate count += 1; 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate limit += 1; 14737c478bd9Sstevel@tonic-gate old = *status; 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate } while (count < HPC3130_DEBOUNCE_COUNT && 14767c478bd9Sstevel@tonic-gate limit < HPC3130_DEBOUNCE_LIMIT); 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate if (limit == HPC3130_DEBOUNCE_LIMIT) { 14797c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate static int 14867c478bd9Sstevel@tonic-gate hpc3130_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl, 14877c478bd9Sstevel@tonic-gate void *data, uint_t flags) 14887c478bd9Sstevel@tonic-gate { 14897c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(slot_hdl, data, flags)) 14907c478bd9Sstevel@tonic-gate uint8_t control; 14917c478bd9Sstevel@tonic-gate uint8_t offset; 14927c478bd9Sstevel@tonic-gate uint8_t config; 14937c478bd9Sstevel@tonic-gate uint8_t status; 14947c478bd9Sstevel@tonic-gate hpc3130_unit_t *hpc3130_p; 14957c478bd9Sstevel@tonic-gate i2c_client_hdl_t handle; 14967c478bd9Sstevel@tonic-gate int i; 14977c478bd9Sstevel@tonic-gate int result = HPC_ERR_FAILED; 14987c478bd9Sstevel@tonic-gate hpc3130_slot_type_t slot_type; 14997c478bd9Sstevel@tonic-gate hpc3130_slot_table_entry_t *ste; 15007c478bd9Sstevel@tonic-gate char phys_slot[MAXPATHLEN]; 15017c478bd9Sstevel@tonic-gate boolean_t needs_to_be_powered_off = B_FALSE; 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate hpc3130_callback_arg_t *info_p = (hpc3130_callback_arg_t *)ops_arg; 15047c478bd9Sstevel@tonic-gate 15057c478bd9Sstevel@tonic-gate /* 15067c478bd9Sstevel@tonic-gate * Callback parameter has specific device handle and offset 15077c478bd9Sstevel@tonic-gate * information in it. 15087c478bd9Sstevel@tonic-gate */ 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate hpc3130_p = (hpc3130_unit_t *)info_p->statep; 15117c478bd9Sstevel@tonic-gate ASSERT(hpc3130_p); 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate mutex_enter(&hpc3130_p->hpc3130_mutex); 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate handle = (i2c_client_hdl_t)info_p->handle; 15167c478bd9Sstevel@tonic-gate offset = info_p->offset; 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate ste = &hpc3130_p->hpc3130_slot_table[offset]; 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) { 15217c478bd9Sstevel@tonic-gate DAK_GET_SBD_APID(phys_slot, MAXPATHLEN, offset); 15227c478bd9Sstevel@tonic-gate } else { 15237c478bd9Sstevel@tonic-gate DAK_GET_PCI_APID(phys_slot, MAXPATHLEN, 15247c478bd9Sstevel@tonic-gate hpc3130_lookup_slot(ste->nexus, 15257c478bd9Sstevel@tonic-gate ste->hpc3130_slot_info.pci_dev_num)); 15267c478bd9Sstevel@tonic-gate } 15277c478bd9Sstevel@tonic-gate 15287c478bd9Sstevel@tonic-gate ASSERT(ste->hpc3130_slot_handle != NULL); 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate slot_type = hpc3130_p->slots_are; 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate if (hpc3130_p->enabled[offset] == B_FALSE) { 15337c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "hot-plug disabled on %s", phys_slot); 15347c478bd9Sstevel@tonic-gate goto out; 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate /* Return (do nothing) if power already applied */ 15387c478bd9Sstevel@tonic-gate if (hpc3130_p->power[offset] == B_TRUE) { 15397c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "Slot power already on %s", phys_slot)); 15407c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 15417c478bd9Sstevel@tonic-gate return (HPC_SUCCESS); 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_STATUS, offset, 15457c478bd9Sstevel@tonic-gate &status)) { 15467c478bd9Sstevel@tonic-gate goto out; 15477c478bd9Sstevel@tonic-gate } 15487c478bd9Sstevel@tonic-gate 15497c478bd9Sstevel@tonic-gate /* Read the slot control register to get current value */ 15507c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_CONTROL, offset, 15517c478bd9Sstevel@tonic-gate &control)) { 15527c478bd9Sstevel@tonic-gate goto out; 15537c478bd9Sstevel@tonic-gate } 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate if (slot_type == HPC3130_SLOT_TYPE_SBD) { 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "CPU connect %d control=%x status=%x", 15587c478bd9Sstevel@tonic-gate offset, control, status)); 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate control = control | HPC3130_SLTPWRCTL; 15617c478bd9Sstevel@tonic-gate if (hpc3130_write(handle, HPC3130_CONTROL, offset, 15627c478bd9Sstevel@tonic-gate control) != DDI_SUCCESS) { 15637c478bd9Sstevel@tonic-gate goto out; 15647c478bd9Sstevel@tonic-gate } 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate } else { 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "PCI connect %d", offset)); 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate /* 15717c478bd9Sstevel@tonic-gate * PCI needs special sequencing of the control signals. 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_GCR, offset, 15757c478bd9Sstevel@tonic-gate &config)) { 15767c478bd9Sstevel@tonic-gate goto out; 15777c478bd9Sstevel@tonic-gate } 15787c478bd9Sstevel@tonic-gate 15797c478bd9Sstevel@tonic-gate /* Assert RST to comply with PCI spec. */ 15807c478bd9Sstevel@tonic-gate control &= ~HPC3130_SLOTRST; 15817c478bd9Sstevel@tonic-gate if (hpc3130_write(handle, HPC3130_CONTROL, offset, 15827c478bd9Sstevel@tonic-gate control) != DDI_SUCCESS) { 15837c478bd9Sstevel@tonic-gate goto out; 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate drv_usecwait(HPC3130_ADEQUATE_PAUSE); 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate /* Send the power on signal and verify the result */ 15887c478bd9Sstevel@tonic-gate control = control | HPC3130_SLTPWRCTL; 15897c478bd9Sstevel@tonic-gate if ((hpc3130_write(handle, HPC3130_CONTROL, offset, 15907c478bd9Sstevel@tonic-gate control) != DDI_SUCCESS) || 15917c478bd9Sstevel@tonic-gate (hpc3130_verify_slot_power(hpc3130_p, handle, offset, 15927c478bd9Sstevel@tonic-gate phys_slot, B_TRUE) == HPC_ERR_FAILED)) { 15937c478bd9Sstevel@tonic-gate goto out; 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate /* The slot is now powered on. */ 15977c478bd9Sstevel@tonic-gate 15987c478bd9Sstevel@tonic-gate drv_usecwait(HPC3130_ADEQUATE_PAUSE); 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate /* Extinguish the "OK-to-remove" indicator */ 16017c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_OK2REM, 16027c478bd9Sstevel@tonic-gate HPC3130_ATTN_OFF); 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /* 16057c478bd9Sstevel@tonic-gate * Perform bus/card speed check functions. 16067c478bd9Sstevel@tonic-gate */ 16077c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_STATUS, offset, &status)) { 16087c478bd9Sstevel@tonic-gate goto out; 16097c478bd9Sstevel@tonic-gate } 16107c478bd9Sstevel@tonic-gate if ((config & HPC3130_SYSM66STAT) && 16117c478bd9Sstevel@tonic-gate !(status & HPC3130_M66EN)) { 16127c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "66Mhz bus can't accept " 16137c478bd9Sstevel@tonic-gate "33Mhz card in %s", phys_slot); 16147c478bd9Sstevel@tonic-gate needs_to_be_powered_off = B_TRUE; 16157c478bd9Sstevel@tonic-gate goto out; 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate if (!(config & HPC3130_SYSM66STAT) && 16187c478bd9Sstevel@tonic-gate (status & HPC3130_M66EN)) { 16197c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "66Mhz capable card throttled " 16207c478bd9Sstevel@tonic-gate "back to 33Mhz in %s", phys_slot); 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate /* 16247c478bd9Sstevel@tonic-gate * Send the connect sequence (see struct connect_sequence) 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate for (i = 0; i < HPC3130_CONNECT_SEQ_COUNT; i++) { 16277c478bd9Sstevel@tonic-gate if (connect_sequence[i].set_bit == B_TRUE) { 16287c478bd9Sstevel@tonic-gate control |= connect_sequence[i].value; 16297c478bd9Sstevel@tonic-gate } else { 16307c478bd9Sstevel@tonic-gate control &= ~connect_sequence[i].value; 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate if (hpc3130_write(handle, HPC3130_CONTROL, offset, 16337c478bd9Sstevel@tonic-gate control) != DDI_SUCCESS) { 16347c478bd9Sstevel@tonic-gate goto out; 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate drv_usecwait(HPC3130_ADEQUATE_PAUSE); 16377c478bd9Sstevel@tonic-gate } 16387c478bd9Sstevel@tonic-gate } 16397c478bd9Sstevel@tonic-gate 1640*07d06da5SSurya Prakki (void) hpc_slot_event_notify(ste->hpc3130_slot_handle, 16417c478bd9Sstevel@tonic-gate HPC_EVENT_SLOT_POWER_ON, 0); 16427c478bd9Sstevel@tonic-gate 16437c478bd9Sstevel@tonic-gate /* Flash the "fault" indicator */ 16447c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT, 16457c478bd9Sstevel@tonic-gate HPC3130_ATTN_SLO); 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate result = HPC_SUCCESS; 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate out: 16507c478bd9Sstevel@tonic-gate if (needs_to_be_powered_off == B_TRUE) { 16517c478bd9Sstevel@tonic-gate /* 16527c478bd9Sstevel@tonic-gate * We are in an error state where the slot is powered on, and 16537c478bd9Sstevel@tonic-gate * it must be powered off. 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate /* Send the power off signal and verify the result */ 16577c478bd9Sstevel@tonic-gate control = control & ~HPC3130_SLTPWRCTL; 16587c478bd9Sstevel@tonic-gate if ((hpc3130_write(handle, HPC3130_CONTROL, offset, 16597c478bd9Sstevel@tonic-gate control) == DDI_SUCCESS) && 16607c478bd9Sstevel@tonic-gate (hpc3130_verify_slot_power(hpc3130_p, handle, offset, 16617c478bd9Sstevel@tonic-gate phys_slot, B_FALSE) == HPC_SUCCESS)) { 16627c478bd9Sstevel@tonic-gate /* Re-light "OK-to-remove" LED */ 16637c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, offset, 16647c478bd9Sstevel@tonic-gate HPC3130_LED_OK2REM, HPC3130_ATTN_ON); 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate return (result); 16717c478bd9Sstevel@tonic-gate } 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate static int 16757c478bd9Sstevel@tonic-gate hpc3130_slot_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl, 16767c478bd9Sstevel@tonic-gate void *data, uint_t flags) 16777c478bd9Sstevel@tonic-gate { 16787c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(slot_hdl, data, flags)) 16797c478bd9Sstevel@tonic-gate uint8_t control; 16807c478bd9Sstevel@tonic-gate uint8_t offset; 16817c478bd9Sstevel@tonic-gate i2c_client_hdl_t handle; 16827c478bd9Sstevel@tonic-gate hpc3130_unit_t *hpc3130_p; 16837c478bd9Sstevel@tonic-gate int result = HPC_ERR_FAILED; 16847c478bd9Sstevel@tonic-gate hpc3130_slot_type_t slot_type; 16857c478bd9Sstevel@tonic-gate hpc3130_slot_table_entry_t *ste; 16867c478bd9Sstevel@tonic-gate char phys_slot[MAXPATHLEN]; 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate hpc3130_callback_arg_t *info_p = (hpc3130_callback_arg_t *)ops_arg; 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate /* 16917c478bd9Sstevel@tonic-gate * Callback parameter has specific device handle and offset 16927c478bd9Sstevel@tonic-gate * information in it. 16937c478bd9Sstevel@tonic-gate */ 16947c478bd9Sstevel@tonic-gate hpc3130_p = (hpc3130_unit_t *)info_p->statep; 16957c478bd9Sstevel@tonic-gate ASSERT(hpc3130_p); 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate mutex_enter(&hpc3130_p->hpc3130_mutex); 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate handle = (i2c_client_hdl_t)info_p->handle; 17007c478bd9Sstevel@tonic-gate offset = info_p->offset; 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate ASSERT(handle == hpc3130_p->hpc3130_hdl); 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate ste = &hpc3130_p->hpc3130_slot_table[offset]; 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) { 17077c478bd9Sstevel@tonic-gate DAK_GET_SBD_APID(phys_slot, MAXPATHLEN, offset); 17087c478bd9Sstevel@tonic-gate } else { 17097c478bd9Sstevel@tonic-gate DAK_GET_PCI_APID(phys_slot, MAXPATHLEN, 17107c478bd9Sstevel@tonic-gate hpc3130_lookup_slot(ste->nexus, 17117c478bd9Sstevel@tonic-gate ste->hpc3130_slot_info.pci_dev_num)); 17127c478bd9Sstevel@tonic-gate } 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate ASSERT(ste->hpc3130_slot_handle != NULL); 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate slot_type = hpc3130_p->slots_are; 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate /* 17197c478bd9Sstevel@tonic-gate * Read the slot control register to get current value 17207c478bd9Sstevel@tonic-gate */ 17217c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, HPC3130_CONTROL, offset, 17227c478bd9Sstevel@tonic-gate &control)) { 17237c478bd9Sstevel@tonic-gate goto out; 17247c478bd9Sstevel@tonic-gate } 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate if (slot_type == HPC3130_SLOT_TYPE_SBD) { 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "CPU disconnect %d", offset)); 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate control = control & ~HPC3130_SLTPWRCTL; 17317c478bd9Sstevel@tonic-gate /* 17327c478bd9Sstevel@tonic-gate * Write out the modified control register 17337c478bd9Sstevel@tonic-gate */ 17347c478bd9Sstevel@tonic-gate if (hpc3130_write(handle, HPC3130_CONTROL, offset, 17357c478bd9Sstevel@tonic-gate control) != DDI_SUCCESS) { 17367c478bd9Sstevel@tonic-gate goto out; 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate } else { 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_NOTE, "PCI disconnect %d", offset)); 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate control &= ~HPC3130_SLOTRST; 17437c478bd9Sstevel@tonic-gate if (hpc3130_write(handle, HPC3130_CONTROL, offset, 17447c478bd9Sstevel@tonic-gate control) != DDI_SUCCESS) { 17457c478bd9Sstevel@tonic-gate goto out; 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate 17487c478bd9Sstevel@tonic-gate control |= HPC3130_BUS_CTL; 17497c478bd9Sstevel@tonic-gate if (hpc3130_write(handle, HPC3130_CONTROL, offset, 17507c478bd9Sstevel@tonic-gate control) != DDI_SUCCESS) { 17517c478bd9Sstevel@tonic-gate goto out; 17527c478bd9Sstevel@tonic-gate } 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_WARN, "disconnect present[%d]==%d", 17567c478bd9Sstevel@tonic-gate offset, hpc3130_p->present[offset])); 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate if (hpc3130_verify_slot_power(hpc3130_p, handle, offset, 17597c478bd9Sstevel@tonic-gate phys_slot, B_FALSE) == HPC_ERR_FAILED) { 17607c478bd9Sstevel@tonic-gate goto out; 17617c478bd9Sstevel@tonic-gate } 17627c478bd9Sstevel@tonic-gate 1763*07d06da5SSurya Prakki (void) hpc_slot_event_notify(ste->hpc3130_slot_handle, 17647c478bd9Sstevel@tonic-gate HPC_EVENT_SLOT_POWER_OFF, 0); 17657c478bd9Sstevel@tonic-gate 17667c478bd9Sstevel@tonic-gate if (hpc3130_p->present[offset] == B_TRUE) { 17677c478bd9Sstevel@tonic-gate /* 17687c478bd9Sstevel@tonic-gate * Illuminate the "OK-to-remove" indicator 17697c478bd9Sstevel@tonic-gate * if there is a card in the slot. 17707c478bd9Sstevel@tonic-gate */ 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_OK2REM, 17737c478bd9Sstevel@tonic-gate HPC3130_ATTN_ON); 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate /* 17767c478bd9Sstevel@tonic-gate * Turn off the "fault" indicator 17777c478bd9Sstevel@tonic-gate */ 17787c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT, 17797c478bd9Sstevel@tonic-gate HPC3130_ATTN_OFF); 17807c478bd9Sstevel@tonic-gate } else { 17817c478bd9Sstevel@tonic-gate /* 17827c478bd9Sstevel@tonic-gate * If the slot is being powered off with 17837c478bd9Sstevel@tonic-gate * no cards in there, its at "boot time", 17847c478bd9Sstevel@tonic-gate * put the LEDs in a sane state 17857c478bd9Sstevel@tonic-gate */ 17867c478bd9Sstevel@tonic-gate if (slot_type == HPC3130_SLOT_TYPE_PCI) { 17877c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, offset, 17887c478bd9Sstevel@tonic-gate HPC3130_LED_FAULT, HPC3130_ATTN_OFF); 17897c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, offset, 17907c478bd9Sstevel@tonic-gate HPC3130_LED_OK2REM, HPC3130_ATTN_OFF); 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate } 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate result = HPC_SUCCESS; 17957c478bd9Sstevel@tonic-gate out: 17967c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate return (result); 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate static int 18027c478bd9Sstevel@tonic-gate hpc3130_verify_slot_power(hpc3130_unit_t *hpc3130_p, i2c_client_hdl_t handle, 18037c478bd9Sstevel@tonic-gate uint8_t offset, char *phys_slot, boolean_t slot_target_state) 18047c478bd9Sstevel@tonic-gate { 18057c478bd9Sstevel@tonic-gate uint8_t tries = 0; 18067c478bd9Sstevel@tonic-gate uint8_t status; 18077c478bd9Sstevel@tonic-gate int result = HPC_SUCCESS; 1808d3d50737SRafael Vanoni clock_t timeleft; 1809d3d50737SRafael Vanoni clock_t tm = drv_usectohz(300000); 18107c478bd9Sstevel@tonic-gate boolean_t slot_actual_state; 18117c478bd9Sstevel@tonic-gate boolean_t failure = B_FALSE; 18127c478bd9Sstevel@tonic-gate hpc3130_slot_table_entry_t *ste; 18137c478bd9Sstevel@tonic-gate 18147c478bd9Sstevel@tonic-gate /* This function is called while holding the hpc3130 mutex. */ 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate /* 18177c478bd9Sstevel@tonic-gate * For slot_target_state and slot_actual_state: 18187c478bd9Sstevel@tonic-gate * B_TRUE == the slot is powered on 18197c478bd9Sstevel@tonic-gate * B_FALSE == the slot is powered off 18207c478bd9Sstevel@tonic-gate */ 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate ste = &hpc3130_p->hpc3130_slot_table[offset]; 18237c478bd9Sstevel@tonic-gate slot_actual_state = hpc3130_p->power[offset]; 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate while ((slot_actual_state != slot_target_state) && 18267c478bd9Sstevel@tonic-gate (failure != B_TRUE)) { 1827d3d50737SRafael Vanoni timeleft = cv_reltimedwait(&hpc3130_p->hpc3130_cond, 1828d3d50737SRafael Vanoni &hpc3130_p->hpc3130_mutex, tm, TR_CLOCK_TICK); 18297c478bd9Sstevel@tonic-gate if (timeleft == -1) { 18307c478bd9Sstevel@tonic-gate if (tries++ < HPC3130_POWER_TRIES) { 18317c478bd9Sstevel@tonic-gate /* 18327c478bd9Sstevel@tonic-gate * The interrupt was missed - explicitly 18337c478bd9Sstevel@tonic-gate * check the status. 18347c478bd9Sstevel@tonic-gate */ 18357c478bd9Sstevel@tonic-gate if (hpc3130_read(handle, 18367c478bd9Sstevel@tonic-gate HPC3130_STATUS, offset, &status)) { 18377c478bd9Sstevel@tonic-gate failure = B_TRUE; 18387c478bd9Sstevel@tonic-gate continue; 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate if (status & HPC3130_PWRGOOD) { 18417c478bd9Sstevel@tonic-gate slot_actual_state = B_FALSE; 18427c478bd9Sstevel@tonic-gate } else { 18437c478bd9Sstevel@tonic-gate slot_actual_state = B_TRUE; 18447c478bd9Sstevel@tonic-gate } 18457c478bd9Sstevel@tonic-gate hpc3130_p->power[offset] = slot_actual_state; 18467c478bd9Sstevel@tonic-gate } else { 18477c478bd9Sstevel@tonic-gate /* Too many tries. We failed. */ 18487c478bd9Sstevel@tonic-gate failure = B_TRUE; 18497c478bd9Sstevel@tonic-gate } 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate } 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate if (failure == B_TRUE) { 18547c478bd9Sstevel@tonic-gate result = HPC_ERR_FAILED; 18557c478bd9Sstevel@tonic-gate if (slot_target_state == B_TRUE) { 18567c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 18577c478bd9Sstevel@tonic-gate "Could not power on slot %s", phys_slot); 18587c478bd9Sstevel@tonic-gate } else { 18597c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 18607c478bd9Sstevel@tonic-gate "Could not power off slot %s", phys_slot); 18617c478bd9Sstevel@tonic-gate } 18627c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT, 18637c478bd9Sstevel@tonic-gate HPC3130_ATTN_ON); 1864*07d06da5SSurya Prakki (void) hpc_slot_event_notify(ste->hpc3130_slot_handle, 18657c478bd9Sstevel@tonic-gate HPC_EVENT_SLOT_NOT_HEALTHY, 0); 18667c478bd9Sstevel@tonic-gate } 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate return (result); 18697c478bd9Sstevel@tonic-gate } 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate static int 18727c478bd9Sstevel@tonic-gate hpc3130_slot_insert(caddr_t ops_arg, hpc_slot_t slot_hdl, 18737c478bd9Sstevel@tonic-gate void *data, uint_t flags) 18747c478bd9Sstevel@tonic-gate { 18757c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(ops_arg, slot_hdl, data, flags)) 18767c478bd9Sstevel@tonic-gate return (HPC_ERR_NOTSUPPORTED); 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate static int 18807c478bd9Sstevel@tonic-gate hpc3130_slot_remove(caddr_t ops_arg, hpc_slot_t slot_hdl, 18817c478bd9Sstevel@tonic-gate void *data, uint_t flags) 18827c478bd9Sstevel@tonic-gate { 18837c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(ops_arg, slot_hdl, data, flags)) 18847c478bd9Sstevel@tonic-gate return (HPC_ERR_NOTSUPPORTED); 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate static int 18887c478bd9Sstevel@tonic-gate hpc3130_slot_control(caddr_t ops_arg, hpc_slot_t slot_hdl, 18897c478bd9Sstevel@tonic-gate int request, caddr_t arg) 18907c478bd9Sstevel@tonic-gate { 18917c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(slot_hdl)) 18927c478bd9Sstevel@tonic-gate i2c_client_hdl_t handle; 18937c478bd9Sstevel@tonic-gate uint8_t offset; 18947c478bd9Sstevel@tonic-gate uint8_t state; 18957c478bd9Sstevel@tonic-gate hpc_led_info_t *led_info; 18967c478bd9Sstevel@tonic-gate hpc3130_unit_t *hpc3130_p; 18977c478bd9Sstevel@tonic-gate hpc3130_slot_type_t slot_type; 18987c478bd9Sstevel@tonic-gate 18997c478bd9Sstevel@tonic-gate hpc3130_callback_arg_t *info_p = (hpc3130_callback_arg_t *)ops_arg; 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate /* 19027c478bd9Sstevel@tonic-gate * Callback parameter has specific device handle and offset 19037c478bd9Sstevel@tonic-gate * information in it. 19047c478bd9Sstevel@tonic-gate */ 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate hpc3130_p = (hpc3130_unit_t *)info_p->statep; 19077c478bd9Sstevel@tonic-gate ASSERT(hpc3130_p); 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate mutex_enter(&hpc3130_p->hpc3130_mutex); 19107c478bd9Sstevel@tonic-gate 19117c478bd9Sstevel@tonic-gate handle = (i2c_client_hdl_t)info_p->handle; 19127c478bd9Sstevel@tonic-gate offset = info_p->offset; 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate ASSERT(handle == hpc3130_p->hpc3130_hdl); 19157c478bd9Sstevel@tonic-gate 19167c478bd9Sstevel@tonic-gate slot_type = hpc3130_p->slots_are; 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate switch (request) { 19197c478bd9Sstevel@tonic-gate case HPC_CTRL_GET_LED_STATE: { 19207c478bd9Sstevel@tonic-gate int led; 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate led_info = (hpc_led_info_t *)arg; 19237c478bd9Sstevel@tonic-gate if (led_info->led != HPC_FAULT_LED && 19247c478bd9Sstevel@tonic-gate led_info->led != HPC_ATTN_LED) { 19257c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_WARN, 19267c478bd9Sstevel@tonic-gate "Only FAULT and ATTN leds allowed")); 19277c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 19287c478bd9Sstevel@tonic-gate return (HPC_ERR_INVALID); 19297c478bd9Sstevel@tonic-gate } 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate if (led_info->led == HPC_FAULT_LED) 19327c478bd9Sstevel@tonic-gate led = HPC3130_LED_FAULT; 19337c478bd9Sstevel@tonic-gate else 19347c478bd9Sstevel@tonic-gate led = HPC3130_LED_OK2REM; 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate if (hpc3130_get_led(handle, offset, led, &state) != 19377c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 19387c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 19397c478bd9Sstevel@tonic-gate return (HPC_ERR_FAILED); 19407c478bd9Sstevel@tonic-gate } 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate /* Make sure that no one broke the conversion macros */ 19437c478bd9Sstevel@tonic-gate ASSERT(state < sizeof (hpc3130_to_hpc_led_map)); 19447c478bd9Sstevel@tonic-gate ASSERT(state == 19457c478bd9Sstevel@tonic-gate HPC3130_FROM_HPC_LED(HPC3130_TO_HPC_LED(state))); 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate led_info->state = HPC3130_TO_HPC_LED(state); 19487c478bd9Sstevel@tonic-gate } 19497c478bd9Sstevel@tonic-gate break; 19507c478bd9Sstevel@tonic-gate case HPC_CTRL_SET_LED_STATE: { 19517c478bd9Sstevel@tonic-gate int led; 19527c478bd9Sstevel@tonic-gate 19537c478bd9Sstevel@tonic-gate /* 19547c478bd9Sstevel@tonic-gate * The HPC3130 support modifications to the Fault and 19557c478bd9Sstevel@tonic-gate * Ok-to-remove LEDs. 19567c478bd9Sstevel@tonic-gate */ 19577c478bd9Sstevel@tonic-gate led_info = (hpc_led_info_t *)arg; 19587c478bd9Sstevel@tonic-gate if (led_info->led != HPC_FAULT_LED && 19597c478bd9Sstevel@tonic-gate led_info->led != HPC_ATTN_LED) { 19607c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_WARN, 19617c478bd9Sstevel@tonic-gate "Only FAULT and ATTN leds allowed")); 19627c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 19637c478bd9Sstevel@tonic-gate return (HPC_ERR_INVALID); 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate if (led_info->led == HPC_FAULT_LED) 19677c478bd9Sstevel@tonic-gate led = HPC3130_LED_FAULT; 19687c478bd9Sstevel@tonic-gate else 19697c478bd9Sstevel@tonic-gate led = HPC3130_LED_OK2REM; 19707c478bd9Sstevel@tonic-gate 19717c478bd9Sstevel@tonic-gate state = led_info->state; 19727c478bd9Sstevel@tonic-gate if (state >= sizeof (hpc3130_from_hpc_led_map) || 19737c478bd9Sstevel@tonic-gate (state != HPC3130_TO_HPC_LED( 19747c478bd9Sstevel@tonic-gate HPC3130_FROM_HPC_LED(state)))) { 19757c478bd9Sstevel@tonic-gate D1CMN_ERR((CE_WARN, 19767c478bd9Sstevel@tonic-gate "Improper LED value: %d %d", state, 19777c478bd9Sstevel@tonic-gate HPC3130_TO_HPC_LED( 19787c478bd9Sstevel@tonic-gate HPC3130_FROM_HPC_LED(state)))); 19797c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 19807c478bd9Sstevel@tonic-gate return (HPC_ERR_INVALID); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate (void) hpc3130_set_led(hpc3130_p, offset, led, 19847c478bd9Sstevel@tonic-gate HPC3130_FROM_HPC_LED(state)); 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate break; 19877c478bd9Sstevel@tonic-gate case HPC_CTRL_GET_SLOT_STATE: { 19887c478bd9Sstevel@tonic-gate if (hpc3130_p->power[offset] == B_FALSE) { 19897c478bd9Sstevel@tonic-gate if (hpc3130_p->present[offset] == B_FALSE) { 19907c478bd9Sstevel@tonic-gate *(ap_rstate_t *)arg = 19917c478bd9Sstevel@tonic-gate AP_RSTATE_EMPTY; 19927c478bd9Sstevel@tonic-gate } else { 19937c478bd9Sstevel@tonic-gate *(ap_rstate_t *)arg = 19947c478bd9Sstevel@tonic-gate AP_RSTATE_DISCONNECTED; 19957c478bd9Sstevel@tonic-gate } 19967c478bd9Sstevel@tonic-gate } else { 19977c478bd9Sstevel@tonic-gate *(ap_rstate_t *)arg = 19987c478bd9Sstevel@tonic-gate AP_RSTATE_CONNECTED; 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate } 20017c478bd9Sstevel@tonic-gate break; 20027c478bd9Sstevel@tonic-gate case HPC_CTRL_GET_BOARD_TYPE: { 20037c478bd9Sstevel@tonic-gate *(hpc_board_type_t *)arg = 20047c478bd9Sstevel@tonic-gate (slot_type == HPC3130_SLOT_TYPE_SBD ? 20057c478bd9Sstevel@tonic-gate HPC_BOARD_UNKNOWN : HPC_BOARD_PCI_HOTPLUG); 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate break; 20087c478bd9Sstevel@tonic-gate case HPC_CTRL_DEV_CONFIG_START: 20097c478bd9Sstevel@tonic-gate case HPC_CTRL_DEV_UNCONFIG_START: 2010*07d06da5SSurya Prakki (void) hpc3130_set_led(hpc3130_p, offset, 2011*07d06da5SSurya Prakki HPC3130_LED_FAULT, HPC3130_ATTN_SLO); 20127c478bd9Sstevel@tonic-gate break; 20137c478bd9Sstevel@tonic-gate case HPC_CTRL_DEV_CONFIG_FAILURE: 2014*07d06da5SSurya Prakki (void) hpc3130_set_led(hpc3130_p, offset, 2015*07d06da5SSurya Prakki HPC3130_LED_FAULT, HPC3130_ATTN_ON); 20167c478bd9Sstevel@tonic-gate break; 20177c478bd9Sstevel@tonic-gate case HPC_CTRL_DEV_CONFIGURED: 2018*07d06da5SSurya Prakki (void) hpc3130_set_led(hpc3130_p, offset, 2019*07d06da5SSurya Prakki HPC3130_LED_FAULT, HPC3130_ATTN_OFF); 20207c478bd9Sstevel@tonic-gate hpc3130_p->present[offset] = B_TRUE; 20217c478bd9Sstevel@tonic-gate break; 20227c478bd9Sstevel@tonic-gate case HPC_CTRL_DEV_UNCONFIGURED: 20237c478bd9Sstevel@tonic-gate if (hpc3130_p->power[offset] == B_TRUE) { 2024*07d06da5SSurya Prakki (void) hpc3130_set_led(hpc3130_p, offset, 20257c478bd9Sstevel@tonic-gate HPC3130_LED_FAULT, HPC3130_ATTN_SLO); 20267c478bd9Sstevel@tonic-gate } else { 2027*07d06da5SSurya Prakki (void) hpc3130_set_led(hpc3130_p, offset, 20287c478bd9Sstevel@tonic-gate HPC3130_LED_FAULT, HPC3130_ATTN_OFF); 20297c478bd9Sstevel@tonic-gate } 20307c478bd9Sstevel@tonic-gate break; 20317c478bd9Sstevel@tonic-gate case HPC_CTRL_DISABLE_SLOT: { 20327c478bd9Sstevel@tonic-gate hpc3130_p->enabled[offset] = B_FALSE; 20337c478bd9Sstevel@tonic-gate } 20347c478bd9Sstevel@tonic-gate break; 20357c478bd9Sstevel@tonic-gate case HPC_CTRL_ENABLE_SLOT: { 20367c478bd9Sstevel@tonic-gate hpc3130_p->enabled[offset] = B_TRUE; 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate break; 20397c478bd9Sstevel@tonic-gate default: 20407c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 20417c478bd9Sstevel@tonic-gate return (HPC_ERR_FAILED); 20427c478bd9Sstevel@tonic-gate } 20437c478bd9Sstevel@tonic-gate mutex_exit(&hpc3130_p->hpc3130_mutex); 20447c478bd9Sstevel@tonic-gate return (HPC_SUCCESS); 20457c478bd9Sstevel@tonic-gate } 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate int 20487c478bd9Sstevel@tonic-gate hpc3130_lookup_slot(char *nexus, int pcidev) 20497c478bd9Sstevel@tonic-gate { 20507c478bd9Sstevel@tonic-gate int i = 0; 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate while ((slot_translate[i].pcidev != pcidev || 20537c478bd9Sstevel@tonic-gate strcmp(nexus, slot_translate[i].nexus) != 0) && 205419397407SSherry Moore i < HPC3130_LOOKUP_SLOTS) 205519397407SSherry Moore i++; 20567c478bd9Sstevel@tonic-gate ASSERT(i != HPC3130_LOOKUP_SLOTS); 20577c478bd9Sstevel@tonic-gate return (i); 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate /* 20617c478bd9Sstevel@tonic-gate * A routine to convert a number (represented as a string) to 20627c478bd9Sstevel@tonic-gate * the integer value it represents. 20637c478bd9Sstevel@tonic-gate */ 20647c478bd9Sstevel@tonic-gate 20657c478bd9Sstevel@tonic-gate static int 20667c478bd9Sstevel@tonic-gate isdigit(int ch) 20677c478bd9Sstevel@tonic-gate { 20687c478bd9Sstevel@tonic-gate return (ch >= '0' && ch <= '9'); 20697c478bd9Sstevel@tonic-gate } 20707c478bd9Sstevel@tonic-gate 20717c478bd9Sstevel@tonic-gate #define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') 20727c478bd9Sstevel@tonic-gate #define bad(val) (val == NULL || !isdigit(*val)) 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate static int 20757c478bd9Sstevel@tonic-gate hpc3130_atoi(const char *p) 20767c478bd9Sstevel@tonic-gate { 20777c478bd9Sstevel@tonic-gate int n; 20787c478bd9Sstevel@tonic-gate int c, neg = 0; 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate if (!isdigit(c = *p)) { 20817c478bd9Sstevel@tonic-gate while (isspace(c)) 20827c478bd9Sstevel@tonic-gate c = *++p; 20837c478bd9Sstevel@tonic-gate switch (c) { 20847c478bd9Sstevel@tonic-gate case '-': 20857c478bd9Sstevel@tonic-gate neg++; 20867c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 20877c478bd9Sstevel@tonic-gate case '+': 20887c478bd9Sstevel@tonic-gate c = *++p; 20897c478bd9Sstevel@tonic-gate } 20907c478bd9Sstevel@tonic-gate if (!isdigit(c)) 20917c478bd9Sstevel@tonic-gate return (0); 20927c478bd9Sstevel@tonic-gate } 20937c478bd9Sstevel@tonic-gate for (n = '0' - c; isdigit(c = *++p); ) { 20947c478bd9Sstevel@tonic-gate n *= 10; /* two steps to avoid unnecessary overflow */ 20957c478bd9Sstevel@tonic-gate n += '0' - c; /* accum neg to avoid surprises at MAX */ 20967c478bd9Sstevel@tonic-gate } 20977c478bd9Sstevel@tonic-gate return (neg ? n : -n); 20987c478bd9Sstevel@tonic-gate } 2099