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