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 (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24 /*
25 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
26 */
27
28 /*
29 * PCI-IDE bus nexus driver
30 */
31
32 #include <sys/types.h>
33 #include <sys/cmn_err.h>
34 #include <sys/conf.h>
35 #include <sys/errno.h>
36 #include <sys/debug.h>
37 #include <sys/ddidmareq.h>
38 #include <sys/ddi_impldefs.h>
39 #include <sys/dma_engine.h>
40 #include <sys/modctl.h>
41 #include <sys/ddi.h>
42 #include <sys/sunddi.h>
43 #include <sys/sunndi.h>
44 #include <sys/mach_intr.h>
45 #include <sys/kmem.h>
46 #include <sys/pci.h>
47 #include <sys/promif.h>
48 #include <sys/pci_intr_lib.h>
49 #include <sys/apic.h>
50
51 int pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
52 int pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
53
54 #define PCIIDE_NATIVE_MODE(dip) \
55 (!ddi_prop_exists(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \
56 "compatibility-mode"))
57
58 #define PCIIDE_PRE26(dip) \
59 ddi_prop_exists(DDI_DEV_T_ANY, (dip), 0, "ignore-hardware-nodes")
60
61 #define PCI_IDE_IF_BM_CAP_MASK 0x80
62
63 #define PCIIDE_PDSIZE (sizeof (struct ddi_parent_private_data) + \
64 sizeof (struct intrspec))
65
66 #ifdef DEBUG
67 static int pci_ide_debug = 0;
68 #define PDBG(fmt) \
69 if (pci_ide_debug) { \
70 prom_printf fmt; \
71 }
72 #else
73 #define PDBG(fmt)
74 #endif
75
76 #ifndef TRUE
77 #define TRUE 1
78 #endif
79 #ifndef FALSE
80 #define FALSE 0
81 #endif
82
83 /*
84 * bus_ops functions
85 */
86
87 static int pciide_bus_map(dev_info_t *dip, dev_info_t *rdip,
88 ddi_map_req_t *mp, off_t offset, off_t len,
89 caddr_t *vaddrp);
90
91 static int pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip,
92 ddi_ctl_enum_t ctlop, void *arg,
93 void *result);
94
95 static int pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
96 ddi_intr_handle_impl_t *hdlp, int *pri);
97
98 static int pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip,
99 ddi_intr_op_t intr_op,
100 ddi_intr_handle_impl_t *hdlp, void *result);
101
102 static struct intrspec *pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip,
103 int inum);
104
105 /*
106 * Local Functions
107 */
108 static int pciide_initchild(dev_info_t *mydip, dev_info_t *cdip);
109
110 static void pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip,
111 int dev);
112 static int pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber);
113 static int pciide_map_rnumber(int canonical_rnumber, int pri_native,
114 int sec_native);
115 static int pciide_alloc_intr(dev_info_t *, dev_info_t *,
116 ddi_intr_handle_impl_t *, void *);
117 static int pciide_free_intr(dev_info_t *, dev_info_t *,
118 ddi_intr_handle_impl_t *);
119
120 extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
121 psm_intr_op_t, int *);
122
123 /*
124 * Config information
125 */
126
127 struct bus_ops pciide_bus_ops = {
128 BUSO_REV,
129 pciide_bus_map,
130 0,
131 0,
132 0,
133 i_ddi_map_fault,
134 0,
135 ddi_dma_allochdl,
136 ddi_dma_freehdl,
137 ddi_dma_bindhdl,
138 ddi_dma_unbindhdl,
139 ddi_dma_flush,
140 ddi_dma_win,
141 ddi_dma_mctl,
142 pciide_ddi_ctlops,
143 ddi_bus_prop_op,
144 0, /* (*bus_get_eventcookie)(); */
145 0, /* (*bus_add_eventcall)(); */
146 0, /* (*bus_remove_eventcall)(); */
147 0, /* (*bus_post_event)(); */
148 0,
149 0,
150 0,
151 0,
152 0,
153 0,
154 0,
155 0,
156 pciide_intr_ops
157 };
158
159 struct dev_ops pciide_ops = {
160 DEVO_REV, /* devo_rev, */
161 0, /* refcnt */
162 ddi_no_info, /* info */
163 nulldev, /* identify */
164 nulldev, /* probe */
165 pciide_attach, /* attach */
166 pciide_detach, /* detach */
167 nodev, /* reset */
168 (struct cb_ops *)0, /* driver operations */
169 &pciide_bus_ops, /* bus operations */
170 NULL, /* power */
171 ddi_quiesce_not_needed, /* quiesce */
172 };
173
174 /*
175 * Module linkage information for the kernel.
176 */
177
178 static struct modldrv modldrv = {
179 &mod_driverops, /* Type of module. This is PCI-IDE bus driver */
180 "pciide nexus driver for 'PCI-IDE' 1.26",
181 &pciide_ops, /* driver ops */
182 };
183
184 static struct modlinkage modlinkage = {
185 MODREV_1,
186 { &modldrv, NULL }
187 };
188
189
190 int
191 _init(void)
192 {
193 return (mod_install(&modlinkage));
194 }
195
196 int
197 _fini(void)
198 {
199 return (mod_remove(&modlinkage));
200 }
201
202 int
203 _info(struct modinfo *modinfop)
204 {
205 return (mod_info(&modlinkage, modinfop));
206 }
207
208 int
209 pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
210 {
211 uint16_t cmdreg;
212 ddi_acc_handle_t conf_hdl = NULL;
213 int rc;
214
215 switch (cmd) {
216 case DDI_ATTACH:
217 /*
218 * Make sure bus-mastering is enabled, even if
219 * BIOS didn't.
220 */
221 rc = pci_config_setup(dip, &conf_hdl);
222
223 /*
224 * In case of error, return SUCCESS. This is because
225 * bus-mastering could be already enabled by BIOS.
226 */
227 if (rc != DDI_SUCCESS)
228 return (DDI_SUCCESS);
229
230 cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM);
231 if ((cmdreg & PCI_COMM_ME) == 0) {
232 pci_config_put16(conf_hdl, PCI_CONF_COMM,
233 cmdreg | PCI_COMM_ME);
234 }
235 pci_config_teardown(&conf_hdl);
236 return (DDI_SUCCESS);
237
238 case DDI_RESUME:
239 /* Restore our PCI configuration header */
240 if (pci_restore_config_regs(dip) != DDI_SUCCESS) {
241 /*
242 * XXXX
243 * This is a pretty bad thing. However, for some
244 * reason it always happens. To further complicate
245 * things, it appears if we just ignore this, we
246 * properly resume. For now, all I want to do is
247 * to generate this message so that it doesn't get
248 * forgotten.
249 */
250 cmn_err(CE_WARN,
251 "Couldn't restore PCI config regs for %s(%p)",
252 ddi_node_name(dip), (void *) dip);
253 }
254 #ifdef DEBUG
255 /* Bus mastering should still be enabled */
256 if (pci_config_setup(dip, &conf_hdl) != DDI_SUCCESS)
257 return (DDI_FAILURE);
258 cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM);
259 ASSERT((cmdreg & PCI_COMM_ME) != 0);
260 pci_config_teardown(&conf_hdl);
261 #endif
262 return (DDI_SUCCESS);
263 }
264
265 return (DDI_FAILURE);
266 }
267
268 /*ARGSUSED*/
269 int
270 pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
271 {
272 switch (cmd) {
273 case DDI_DETACH:
274 return (DDI_SUCCESS);
275 case DDI_SUSPEND:
276 /* Save our PCI configuration header */
277 if (pci_save_config_regs(dip) != DDI_SUCCESS) {
278 /* Don't suspend if we cannot save config regs */
279 return (DDI_FAILURE);
280 }
281 return (DDI_SUCCESS);
282 }
283 return (DDI_FAILURE);
284 }
285
286 /*ARGSUSED*/
287 static int
288 pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
289 void *arg, void *result)
290 {
291 dev_info_t *cdip;
292 int controller;
293 void *pdptr;
294 int rnumber;
295 off_t tmp;
296 int rc;
297
298 PDBG(("pciide_bus_ctl\n"));
299
300 switch (ctlop) {
301 case DDI_CTLOPS_INITCHILD:
302 cdip = (dev_info_t *)arg;
303 return (pciide_initchild(dip, cdip));
304
305 case DDI_CTLOPS_UNINITCHILD:
306 cdip = (dev_info_t *)arg;
307 pdptr = ddi_get_parent_data(cdip);
308 ddi_set_parent_data(cdip, NULL);
309 ddi_set_name_addr(cdip, NULL);
310 kmem_free(pdptr, PCIIDE_PDSIZE);
311 return (DDI_SUCCESS);
312
313 case DDI_CTLOPS_NREGS:
314 *(int *)result = 3;
315 return (DDI_SUCCESS);
316
317 case DDI_CTLOPS_REGSIZE:
318 /*
319 * Adjust the rnumbers based on which controller instance
320 * is requested; adjust for the 2 tuples per controller.
321 */
322 if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
323 controller = 0;
324 else
325 controller = 1;
326
327
328 switch (rnumber = *(int *)arg) {
329 case 0:
330 case 1:
331 rnumber += (2 * controller);
332 break;
333 case 2:
334 rnumber = 4;
335 break;
336 default:
337 PDBG(("pciide_ctlops invalid rnumber\n"));
338 return (DDI_FAILURE);
339 }
340
341
342 if (PCIIDE_PRE26(dip)) {
343 int old_rnumber;
344 int new_rnumber;
345
346 old_rnumber = rnumber;
347 new_rnumber
348 = pciide_pre26_rnumber_map(dip, old_rnumber);
349 PDBG(("pciide rnumber old %d new %d\n",
350 old_rnumber, new_rnumber));
351 rnumber = new_rnumber;
352 }
353
354 /*
355 * Add 1 to skip over the PCI config space tuple
356 */
357 rnumber++;
358
359 /*
360 * If it's not tuple #2 pass the adjusted request to my parent
361 */
362 if (*(int *)arg != 2) {
363 return (ddi_ctlops(dip, dip, ctlop, &rnumber, result));
364 }
365
366 /*
367 * Handle my child's reg-tuple #2 here by splitting my 16 byte
368 * reg-tuple #4 into two 8 byte ranges based on the
369 * the child's controller #.
370 */
371
372 tmp = 8;
373 rc = ddi_ctlops(dip, dip, ctlop, &rnumber, &tmp);
374
375 /*
376 * Allow for the possibility of less than 16 bytes by
377 * by checking what's actually returned for my reg-tuple #4.
378 */
379 if (controller == 1) {
380 if (tmp < 8)
381 tmp = 0;
382 else
383 tmp -= 8;
384 }
385 if (tmp > 8)
386 tmp = 8;
387 *(off_t *)result = tmp;
388
389 return (rc);
390
391 case DDI_CTLOPS_ATTACH:
392 case DDI_CTLOPS_DETACH:
393 /*
394 * Don't pass child ide ATTACH/DETACH to parent
395 */
396 return (DDI_SUCCESS);
397
398 default:
399 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
400 }
401 }
402
403 /*
404 * IEEE 1275 Working Group Proposal #414 says that the Primary
405 * controller is "ata@0" and the Secondary controller "ata@1".
406 *
407 * By the time we get here, boot Bootconf (2.6+) has created devinfo
408 * nodes with the appropriate "reg", "assigned-addresses" and "interrupts"
409 * properites on the pci-ide node and both ide child nodes.
410 *
411 * In compatibility mode the "reg" and "assigned-addresses" properties
412 * of the pci-ide node are set up like this:
413 *
414 * 1. PCI-IDE Nexus
415 *
416 * interrupts=0
417 * (addr-hi addr-mid addr-low size-hi size-low)
418 * reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
419 * 81000000.00000000.000001f0.00000000.00000008
420 * 81000000.00000000.000003f4.00000000.00000004
421 * 81000000.00000000,00000170.00000000.00000008
422 * 81000000.00000000,00000374.00000000.00000004
423 * 01000020.00000000,-[BAR4]-.00000000.00000010
424 *
425 * In native PCI mode the "reg" and "assigned-addresses" properties
426 * would be set up like this:
427 *
428 * 2. PCI-IDE Nexus
429 *
430 * interrupts=0
431 * reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
432 * 01000010.00000000.-[BAR0]-.00000000.00000008
433 * 01000014,00000000.-[BAR1]-.00000000.00000004
434 * 01000018.00000000.-[BAR2]-.00000000.00000008
435 * 0100001c.00000000.-[BAR3]-.00000000.00000004
436 * 01000020.00000000.-[BAR4]-.00000000.00000010
437 *
438 *
439 * In both modes the child nodes simply have the following:
440 *
441 * 2. primary controller (compatibility mode)
442 *
443 * interrupts=14
444 * reg=00000000
445 *
446 * 3. secondary controller
447 *
448 * interrupts=15
449 * reg=00000001
450 *
451 * The pciide_bus_map() function is responsible for turning requests
452 * to map primary or secondary controller rnumbers into mapping requests
453 * of the appropriate regspec on the pci-ide node.
454 *
455 */
456
457 static int
458 pciide_initchild(dev_info_t *mydip, dev_info_t *cdip)
459 {
460 struct ddi_parent_private_data *pdptr;
461 struct intrspec *ispecp;
462 int vec;
463 int *rp;
464 uint_t proplen;
465 char name[80];
466 int dev;
467
468 PDBG(("pciide_initchild\n"));
469
470 /*
471 * Set the address portion of the node name based on
472 * the controller number (0 or 1) from the 'reg' property.
473 */
474 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
475 "reg", &rp, (uint_t *)&proplen) != DDI_PROP_SUCCESS) {
476 PDBG(("pciide_intchild prop error\n"));
477 return (DDI_NOT_WELL_FORMED);
478 }
479
480 /*
481 * copy the controller number and
482 * free the memory allocated by ddi_prop_lookup_int_array
483 */
484 dev = *rp;
485 ddi_prop_free(rp);
486
487 /*
488 * I only support two controllers per device, determine
489 * which this one is and set its unit address.
490 */
491 if (dev > 1) {
492 PDBG(("pciide_initchild bad dev\n"));
493 return (DDI_NOT_WELL_FORMED);
494 }
495 (void) sprintf(name, "%d", dev);
496 ddi_set_name_addr(cdip, name);
497
498 /*
499 * determine if this instance is running in native or compat mode
500 */
501 pciide_compat_setup(mydip, cdip, dev);
502
503 /* interrupts property is required */
504 if (PCIIDE_NATIVE_MODE(cdip)) {
505 vec = 1;
506 } else {
507 /*
508 * In compatibility mode, dev 0 should always be
509 * IRQ 14 and dev 1 is IRQ 15. If for some reason
510 * this needs to be changed, do it via the interrupts
511 * property in the ata.conf file.
512 */
513 vec = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
514 "interrupts", -1);
515 if (vec == -1) {
516 /* setup compatibility mode interrupts */
517 if (dev == 0) {
518 vec = 14;
519 } else if (dev == 1) {
520 vec = 15;
521 } else {
522 PDBG(("pciide_initchild bad intr\n"));
523 return (DDI_NOT_WELL_FORMED);
524 }
525 }
526 }
527
528 pdptr = kmem_zalloc(PCIIDE_PDSIZE, KM_SLEEP);
529 ispecp = (struct intrspec *)(pdptr + 1);
530 pdptr->par_nintr = 1;
531 pdptr->par_intr = ispecp;
532 ispecp->intrspec_vec = vec;
533 ddi_set_parent_data(cdip, pdptr);
534
535 PDBG(("pciide_initchild okay\n"));
536 return (DDI_SUCCESS);
537 }
538
539 static int
540 pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
541 off_t offset, off_t len, caddr_t *vaddrp)
542 {
543 dev_info_t *pdip;
544 int rnumber = mp->map_obj.rnumber;
545 int controller;
546 int rc;
547
548 PDBG(("pciide_bus_map\n"));
549
550 if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
551 controller = 0;
552 else
553 controller = 1;
554
555 /*
556 * Adjust the rnumbers based on which controller instance
557 * is being mapped; adjust for the 2 tuples per controller.
558 */
559
560 switch (rnumber) {
561 case 0:
562 case 1:
563 mp->map_obj.rnumber += (controller * 2);
564 break;
565 case 2:
566 /*
567 * split the 16 I/O ports into two 8 port ranges
568 */
569 mp->map_obj.rnumber = 4;
570 if (offset + len > 8) {
571 PDBG(("pciide_bus_map offset\n"));
572 return (DDI_FAILURE);
573 }
574 if (len == 0)
575 len = 8 - offset;
576 offset += 8 * controller;
577 break;
578 default:
579 PDBG(("pciide_bus_map default\n"));
580 return (DDI_FAILURE);
581 }
582
583 if (PCIIDE_PRE26(dip)) {
584 int old_rnumber;
585 int new_rnumber;
586
587 old_rnumber = mp->map_obj.rnumber;
588 new_rnumber = pciide_pre26_rnumber_map(dip, old_rnumber);
589 PDBG(("pciide rnumber old %d new %d\n",
590 old_rnumber, new_rnumber));
591 mp->map_obj.rnumber = new_rnumber;
592 }
593
594 /*
595 * Add 1 to skip over the PCI config space tuple
596 */
597 mp->map_obj.rnumber++;
598
599
600 /*
601 * pass the adjusted request to my parent
602 */
603 pdip = ddi_get_parent(dip);
604 rc = ((*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_map))
605 (pdip, dip, mp, offset, len, vaddrp));
606
607 PDBG(("pciide_bus_map %s\n", rc == DDI_SUCCESS ? "okay" : "!ok"));
608
609 return (rc);
610 }
611
612
613 static struct intrspec *
614 pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inumber)
615 {
616 struct ddi_parent_private_data *ppdptr;
617
618 PDBG(("pciide_get_ispec\n"));
619
620 /*
621 * Native mode PCI-IDE controllers share the parent's
622 * PCI interrupt line.
623 *
624 * Compatibility mode PCI-IDE controllers have their
625 * own intrspec which specifies ISA IRQ 14 or 15.
626 *
627 */
628 if (PCIIDE_NATIVE_MODE(rdip)) {
629 ddi_intrspec_t is;
630
631 is = pci_intx_get_ispec(dip, dip, inumber);
632 PDBG(("pciide_get_ispec okay\n"));
633 return ((struct intrspec *)is);
634 }
635
636 /* Else compatibility mode, use the ISA IRQ */
637 if ((ppdptr = ddi_get_parent_data(rdip)) == NULL) {
638 PDBG(("pciide_get_ispec null\n"));
639 return (NULL);
640 }
641
642 /* validate the interrupt number */
643 if (inumber >= ppdptr->par_nintr) {
644 PDBG(("pciide_get_inum\n"));
645 return (NULL);
646 }
647
648 PDBG(("pciide_get_ispec ok\n"));
649
650 return ((struct intrspec *)&ppdptr->par_intr[inumber]);
651 }
652
653 static int
654 pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
655 ddi_intr_handle_impl_t *hdlp, int *pri)
656 {
657 struct intrspec *ispecp;
658 int *intpriorities;
659 uint_t num_intpriorities;
660
661 PDBG(("pciide_get_pri\n"));
662
663 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL) {
664 PDBG(("pciide_get_pri null\n"));
665 return (DDI_FAILURE);
666 }
667
668 if (PCIIDE_NATIVE_MODE(rdip)) {
669 *pri = ispecp->intrspec_pri;
670 PDBG(("pciide_get_pri ok\n"));
671 return (DDI_SUCCESS);
672 }
673
674 /* check if the intrspec has been initialized */
675 if (ispecp->intrspec_pri != 0) {
676 *pri = ispecp->intrspec_pri;
677 PDBG(("pciide_get_pri ok2\n"));
678 return (DDI_SUCCESS);
679 }
680
681 /* Use a default of level 5 */
682 ispecp->intrspec_pri = 5;
683
684 /*
685 * If there's an interrupt-priorities property, use it to
686 * over-ride the default interrupt priority.
687 */
688 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
689 "interrupt-priorities", &intpriorities, &num_intpriorities) ==
690 DDI_PROP_SUCCESS) {
691 if (hdlp->ih_inum < num_intpriorities)
692 ispecp->intrspec_pri = intpriorities[hdlp->ih_inum];
693 ddi_prop_free(intpriorities);
694 }
695 *pri = ispecp->intrspec_pri;
696
697 PDBG(("pciide_get_pri ok3\n"));
698
699 return (DDI_SUCCESS);
700 }
701
702 static int
703 pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
704 ddi_intr_handle_impl_t *hdlp, void *result)
705 {
706 struct intrspec *ispecp;
707 int rc;
708 int pri = 0;
709
710 PDBG(("pciide_intr_ops: dip %p rdip %p op %x hdlp %p\n",
711 (void *)dip, (void *)rdip, intr_op, (void *)hdlp));
712
713 switch (intr_op) {
714 case DDI_INTROP_SUPPORTED_TYPES:
715 *(int *)result = DDI_INTR_TYPE_FIXED;
716 break;
717 case DDI_INTROP_GETCAP:
718 *(int *)result = DDI_INTR_FLAG_LEVEL;
719 break;
720 case DDI_INTROP_NINTRS:
721 case DDI_INTROP_NAVAIL:
722 *(int *)result = (!PCIIDE_NATIVE_MODE(rdip)) ?
723 i_ddi_get_intx_nintrs(rdip) : 1;
724 break;
725 case DDI_INTROP_ALLOC:
726 return (pciide_alloc_intr(dip, rdip, hdlp, result));
727 case DDI_INTROP_FREE:
728 return (pciide_free_intr(dip, rdip, hdlp));
729 case DDI_INTROP_GETPRI:
730 if (pciide_get_pri(dip, rdip, hdlp, &pri) != DDI_SUCCESS) {
731 *(int *)result = 0;
732 return (DDI_FAILURE);
733 }
734 *(int *)result = pri;
735 break;
736 case DDI_INTROP_ADDISR:
737 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
738 NULL)
739 return (DDI_FAILURE);
740 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
741 ispecp->intrspec_func = hdlp->ih_cb_func;
742 break;
743 case DDI_INTROP_REMISR:
744 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
745 NULL)
746 return (DDI_FAILURE);
747 ispecp->intrspec_func = (uint_t (*)()) 0;
748 break;
749 case DDI_INTROP_ENABLE:
750 /* FALLTHRU */
751 case DDI_INTROP_DISABLE:
752 if (PCIIDE_NATIVE_MODE(rdip)) {
753 rdip = dip;
754 dip = ddi_get_parent(dip);
755 } else { /* get ptr to the root node */
756 dip = ddi_root_node();
757 }
758
759 rc = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_intr_op))(dip,
760 rdip, intr_op, hdlp, result);
761
762 #ifdef DEBUG
763 if (intr_op == DDI_INTROP_ENABLE) {
764 PDBG(("pciide_enable rc=%d", rc));
765 } else
766 PDBG(("pciide_disable rc=%d", rc));
767 #endif /* DEBUG */
768 return (rc);
769 default:
770 return (DDI_FAILURE);
771 }
772
773 return (DDI_SUCCESS);
774 }
775
776 int
777 pciide_alloc_intr(dev_info_t *dip, dev_info_t *rdip,
778 ddi_intr_handle_impl_t *hdlp, void *result)
779 {
780 struct intrspec *ispec;
781 ddi_intr_handle_impl_t info_hdl;
782 int ret;
783 int free_phdl = 0;
784 apic_get_type_t type_info;
785
786 if (psm_intr_ops == NULL)
787 return (DDI_FAILURE);
788
789 if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL)
790 return (DDI_FAILURE);
791
792 /*
793 * If the PSM module is "APIX" then pass the request for it
794 * to allocate the vector now.
795 */
796 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
797 info_hdl.ih_private = &type_info;
798 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
799 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
800 if (hdlp->ih_private == NULL) { /* allocate phdl structure */
801 free_phdl = 1;
802 i_ddi_alloc_intr_phdl(hdlp);
803 }
804 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
805 if (PCIIDE_NATIVE_MODE(rdip)) {
806 rdip = dip;
807 dip = ddi_get_parent(dip);
808 } else { /* get ptr to the root node */
809 dip = ddi_root_node();
810 }
811 ret = (*psm_intr_ops)(rdip, hdlp,
812 PSM_INTR_OP_ALLOC_VECTORS, result);
813 if (free_phdl) { /* free up the phdl structure */
814 free_phdl = 0;
815 i_ddi_free_intr_phdl(hdlp);
816 }
817 } else {
818 /*
819 * No APIX module; fall back to the old scheme where the
820 * interrupt vector is allocated during ddi_enable_intr() call.
821 */
822 *(int *)result = hdlp->ih_scratch1;
823 ret = DDI_SUCCESS;
824 }
825
826 return (ret);
827 }
828
829 int
830 pciide_free_intr(dev_info_t *dip, dev_info_t *rdip,
831 ddi_intr_handle_impl_t *hdlp)
832 {
833 struct intrspec *ispec;
834 ddi_intr_handle_impl_t info_hdl;
835 apic_get_type_t type_info;
836
837 if (psm_intr_ops == NULL)
838 return (DDI_FAILURE);
839
840 /*
841 * If the PSM module is "APIX" then pass the request for it
842 * to free up the vector now.
843 */
844 bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
845 info_hdl.ih_private = &type_info;
846 if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
847 PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
848 if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
849 NULL)
850 return (DDI_FAILURE);
851 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
852 if (PCIIDE_NATIVE_MODE(rdip)) {
853 rdip = dip;
854 dip = ddi_get_parent(dip);
855 } else { /* get ptr to the root node */
856 dip = ddi_root_node();
857 }
858 return ((*psm_intr_ops)(rdip, hdlp,
859 PSM_INTR_OP_FREE_VECTORS, NULL));
860 }
861
862 /*
863 * No APIX module; fall back to the old scheme where
864 * the interrupt vector was already freed during
865 * ddi_disable_intr() call.
866 */
867 return (DDI_SUCCESS);
868 }
869
870 /*
871 * This is one of the places where controller specific setup needs to be
872 * considered.
873 * At this point the controller was already pre-qualified as a known and
874 * supported pciide controller.
875 * Some controllers do not provide PCI_MASS_IDE sub-class code and IDE
876 * programming interface code but rather PCI_MASS_OTHER sub-class code
877 * without any additional data.
878 * For those controllers IDE programming interface cannot be extracted
879 * from PCI class - we assume that they are pci-native type and we fix
880 * the programming interface used by other functions.
881 * The programming interface byte is set to indicate pci-native mode
882 * for both controllers and the Bus Master DMA capabilitiy of the controller.
883 */
884 static void
885 pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, int dev)
886 {
887 int class_code;
888 int rc = DDI_PROP_SUCCESS;
889
890 class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip,
891 DDI_PROP_DONTPASS, "class-code", 0);
892
893 if (((class_code & 0x00FF00) >> 8) == PCI_MASS_IDE) {
894 /*
895 * Controller provides PCI_MASS_IDE sub-class code first
896 * (implied IDE programming interface)
897 */
898 if ((dev == 0 && !(class_code & PCI_IDE_IF_NATIVE_PRI)) ||
899 (dev == 1 && !(class_code & PCI_IDE_IF_NATIVE_SEC))) {
900 rc = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
901 "compatibility-mode", 1);
902 if (rc != DDI_PROP_SUCCESS)
903 cmn_err(CE_WARN,
904 "pciide prop error %d compat-mode", rc);
905 }
906 } else {
907 /*
908 * Pci-ide controllers not providing PCI_MASS_IDE sub-class are
909 * assumed to be of pci-native type and bus master DMA capable.
910 * Programming interface part of the class-code property is
911 * fixed here.
912 */
913 class_code &= 0x00ffff00;
914 class_code |= PCI_IDE_IF_BM_CAP_MASK |
915 PCI_IDE_IF_NATIVE_PRI | PCI_IDE_IF_NATIVE_SEC;
916 rc = ddi_prop_update_int(DDI_DEV_T_NONE, mydip,
917 "class-code", class_code);
918 if (rc != DDI_PROP_SUCCESS)
919 cmn_err(CE_WARN,
920 "pciide prop error %d class-code", rc);
921 }
922 }
923
924
925 static int
926 pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber)
927 {
928 int pri_native;
929 int sec_native;
930 int class_code;
931
932 class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, DDI_PROP_DONTPASS,
933 "class-code", 0);
934
935 pri_native = (class_code & PCI_IDE_IF_NATIVE_PRI) ? TRUE : FALSE;
936 sec_native = (class_code & PCI_IDE_IF_NATIVE_SEC) ? TRUE : FALSE;
937
938 return (pciide_map_rnumber(rnumber, pri_native, sec_native));
939
940 }
941
942 /*
943 * The canonical order of the reg property tuples for the
944 * Base Address Registers is supposed to be:
945 *
946 * primary controller (BAR 0)
947 * primary controller (BAR 1)
948 * secondary controller (BAR 2)
949 * secondary controller (BAR 3)
950 * bus mastering regs (BAR 4)
951 *
952 * For 2.6, bootconf has been fixed to always generate the
953 * reg property (and assigned-addresses property) tuples
954 * in the above order.
955 *
956 * But in releases prior to 2.6 the order varies depending
957 * on whether compatibility or native mode is being used for
958 * each controller. There ends up being four possible
959 * orders:
960 *
961 * BM, P0, P1, S0, S1 primary compatible, secondary compatible
962 * S0, S1, BM, P0, P1 primary compatible, secondary native
963 * P0, P1, BM, S0, S1 primary native, secondary compatible
964 * P0, P1, S0, S1, BM primary native, secondary native
965 *
966 * where: Px is the primary tuples, Sx the secondary tuples, and
967 * B the Bus Master tuple.
968 *
969 * Here's the results for each of the four states:
970 *
971 * 0, 1, 2, 3, 4
972 *
973 * CC 1, 2, 3, 4, 0
974 * CN 3, 4, 0, 1, 2
975 * NC 0, 1, 3, 4, 2
976 * NN 0, 1, 2, 3, 4
977 *
978 * C = compatible(!native) == 0
979 * N = native == 1
980 *
981 * Here's the transformation matrix:
982 */
983
984 static int pciide_transform[2][2][5] = {
985 /* P S */
986 /* [C][C] */ { { +1, +1, +1, +1, -4 },
987 /* [C][N] */ { +3, +3, -2, -2, -2 } },
988 /* [N][C] */ { { +0, +0, +1, +1, -2 },
989 /* [N][N] */ { +0, +0, +0, +0, +0 } }
990 };
991
992
993 static int
994 pciide_map_rnumber(int rnumber, int pri_native, int sec_native)
995 {
996 /* transform flags into indexes */
997 pri_native = pri_native ? 1 : 0;
998 sec_native = sec_native ? 1 : 0;
999
1000 rnumber += pciide_transform[pri_native][sec_native][rnumber];
1001 return (rnumber);
1002 }