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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 * Generic SCSI Host Bus Adapter interface implementation
32 #include <sys/dada/dada.h>
34 extern int dcd_options
;
36 static kmutex_t dcd_hba_mutex
;
38 kmutex_t dcd_log_mutex
;
42 dcd_hba_tran_t
*inst_hba_tran
;
43 struct dcd_hba_inst
*inst_next
;
44 struct dcd_hba_inst
*inst_prev
;
47 static struct dcd_hba_inst
*dcd_hba_list
= NULL
;
48 static struct dcd_hba_inst
*dcd_hba_list_tail
= NULL
;
51 _NOTE(READ_ONLY_DATA(dev_ops
))
53 kmutex_t dcd_flag_nointr_mutex
;
54 kcondvar_t dcd_flag_nointr_cv
;
58 * Called from _init when loading the dcd module.
61 dcd_initialize_hba_interface()
63 mutex_init(&dcd_hba_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
64 mutex_init(&dcd_flag_nointr_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
65 cv_init(&dcd_flag_nointr_cv
, NULL
, CV_DRIVER
, NULL
);
66 mutex_init(&dcd_log_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
70 * Called from fini() when unloading the dcd module.
74 dcd_uninitialize_hba_interface()
76 mutex_destroy(&dcd_hba_mutex
);
77 cv_destroy(&dcd_flag_nointr_cv
);
78 mutex_destroy(&dcd_flag_nointr_mutex
);
79 mutex_destroy(&dcd_log_mutex
);
84 * Called by an HBA from _init()
88 dcd_hba_init(struct modlinkage
*modlp
)
99 dcd_hba_attach(dev_info_t
*dip
,
100 ddi_dma_lim_t
*hba_lim
,
101 dcd_hba_tran_t
*hba_tran
,
106 ddi_dma_attr_t hba_dma_attr
;
108 bzero(&hba_dma_attr
, sizeof (ddi_dma_attr_t
));
110 hba_dma_attr
.dma_attr_burstsizes
= hba_lim
->dlim_burstsizes
;
111 hba_dma_attr
.dma_attr_minxfer
= hba_lim
->dlim_minxfer
;
113 return (dcd_hba_attach_setup(dip
, &hba_dma_attr
, hba_tran
, flags
));
121 ddi_dma_attr_t
*hba_dma_attr
,
122 dcd_hba_tran_t
*hba_tran
,
126 struct dcd_hba_inst
*elem
;
131 "dcd_hba_attach: cannott create property '%s' for %s%d\n";
134 * Link this instance into the list
136 elem
= kmem_alloc(sizeof (struct dcd_hba_inst
), KM_SLEEP
);
138 elem
->inst_dip
= dip
;
139 elem
->inst_hba_tran
= hba_tran
;
141 mutex_enter(&dcd_hba_mutex
);
142 elem
->inst_next
= NULL
;
143 elem
->inst_prev
= dcd_hba_list_tail
;
145 if (dcd_hba_list
== NULL
) {
148 if (dcd_hba_list_tail
) {
149 dcd_hba_list_tail
->inst_next
= elem
;
151 dcd_hba_list_tail
= elem
;
152 mutex_exit(&dcd_hba_mutex
);
156 * Save all the improtant HBA information that must be accessed
160 hba_tran
->tran_hba_dip
= dip
;
161 hba_tran
->tran_hba_flags
= flags
;
164 * Note: We only need dma_attr_minxfer and dma_attr_burstsize
165 * from the DMA atrributes
168 hba_tran
->tran_min_xfer
= hba_dma_attr
->dma_attr_minxfer
;
169 hba_tran
->tran_min_burst_size
=
170 (1<<(ddi_ffs(hba_dma_attr
->dma_attr_burstsizes
)-1));
171 hba_tran
->tran_max_burst_size
=
172 (1<<(ddi_fls(hba_dma_attr
->dma_attr_burstsizes
)-1));
176 prop_name
= "dcd_options";
178 if (ddi_prop_op(DDI_DEV_T_ANY
, dip
, PROP_LEN
, 0, prop_name
,
179 NULL
, &len
) == DDI_PROP_NOT_FOUND
) {
181 if (ddi_prop_update_int(DDI_MAJOR_T_UNKNOWN
, dip
,
182 prop_name
, value
) != DDI_PROP_SUCCESS
) {
183 cmn_err(CE_CONT
, errmsg
, prop_name
,
184 ddi_get_name(dip
), ddi_get_instance(dip
));
190 * XXX : This needs to be removed when code cleanup
191 * ddi_set_driver_private(dip, (caddr_t)hba_tran);
194 printf("Called Set driver private with dip %x, tran %x\n",
198 return (DDI_SUCCESS
);
203 * called by an HBA to detach an instance of the driver
207 dcd_hba_detach(dev_info_t
*dip
)
211 struct dcd_hba_inst
*elem
;
213 hba
= ddi_get_driver_private(dip
);
214 ddi_set_driver_private(dip
, NULL
);
217 hba
->tran_hba_dip
= (dev_info_t
*)NULL
;
218 hba
->tran_hba_flags
= 0;
219 hba
->tran_min_burst_size
= (uchar_t
)0;
220 hba
->tran_max_burst_size
= (uchar_t
)0;
224 * Remove HBA instance from dcd_hba_list
227 mutex_enter(&dcd_hba_mutex
);
229 for (elem
= dcd_hba_list
; elem
!= (struct dcd_hba_inst
*)NULL
;
230 elem
= elem
->inst_next
) {
231 if (elem
->inst_dip
== dip
)
235 if (elem
== (struct dcd_hba_inst
*)NULL
) {
236 cmn_err(CE_NOTE
, "dcd_hba_attach: Unknown HBA instance\n");
237 mutex_exit(&dcd_hba_mutex
);
240 if (elem
== dcd_hba_list
) {
241 dcd_hba_list
= elem
->inst_next
;
242 dcd_hba_list
->inst_prev
= (struct dcd_hba_inst
*)NULL
;
243 } else if (elem
== dcd_hba_list_tail
) {
244 dcd_hba_list_tail
= elem
->inst_prev
;
245 dcd_hba_list_tail
->inst_next
= (struct dcd_hba_inst
*)NULL
;
247 elem
->inst_prev
->inst_next
= elem
->inst_next
;
248 elem
->inst_next
->inst_prev
= elem
->inst_prev
;
250 mutex_exit(&dcd_hba_mutex
);
252 kmem_free(elem
, sizeof (struct dcd_hba_inst
));
254 return (DDI_SUCCESS
);
270 return (kmem_zalloc(sizeof (dcd_hba_tran_t
),
271 (flags
& DCD_HBA_CANSLEEP
) ? KM_SLEEP
: KM_NOSLEEP
));
276 dcd_hba_tran_free(dcd_hba_tran_t
*hba_tran
)
279 kmem_free(hba_tran
, sizeof (dcd_hba_tran_t
));
284 * XXX: Do we really need the following routines.
288 * private wrapper for dcd_pkt's allocated via scsi_hba_pkt_alloc
291 struct dcd_pkt_wrapper
{
292 struct dcd_pkt dcd_pkt
;
296 _NOTE(SCHEME_PROTECTS_DATA("unique per thread", dcd_pkt_wrapper
))
299 * Round up all allocations so that we can gurentee
300 * long-long alignment. This is the same alignment
301 * provided by kmem_alloc().
304 #define ROUNDUP(x) (((x) + 0x07) & ~0x07)
307 * Called by an HBA to allocate a dcd_pkt
313 struct dcd_address
*ap
,
318 int (*callback
)(caddr_t arg
),
323 struct dcd_pkt_wrapper
*hba_pkt
;
331 if (callback
!= SLEEP_FUNC
&& callback
!= NULL_FUNC
) {
332 cmn_err(CE_PANIC
, " dcd_hba_pkt_alloc: callback must be"
333 " either SLEEP or NULL\n");
338 * Round up so everything gets allocated on long-word boundaries.
341 cmdlen
= ROUNDUP(cmdlen
);
342 tgtlen
= ROUNDUP(tgtlen
);
343 hbalen
= ROUNDUP(hbalen
);
344 statuslen
= ROUNDUP(statuslen
);
345 pktlen
= sizeof (struct dcd_pkt_wrapper
) +
346 cmdlen
+ tgtlen
+hbalen
+ statuslen
;
348 hba_pkt
= kmem_zalloc(pktlen
,
349 (callback
= SLEEP_FUNC
) ? KM_SLEEP
: KM_NOSLEEP
);
351 if (hba_pkt
== NULL
) {
352 ASSERT(callback
== NULL_FUNC
);
357 * Set up or private info on this pkt
359 hba_pkt
->pkt_wrapper_len
= pktlen
;
360 pkt
= &hba_pkt
->dcd_pkt
;
361 p
= (caddr_t
)(hba_pkt
+ 1);
364 * set up pointers to private data areas, cdb and status.
367 pkt
->pkt_ha_private
= (ataopaque_t
)p
;
372 pkt
->pkt_private
= (ataopaque_t
)p
;
377 pkt
->pkt_scbp
= (uchar_t
*)p
;
382 pkt
->pkt_cdbp
= (void *)p
;
386 * Initialize the pkt's dcd_address
388 pkt
->pkt_address
= *ap
;
390 printf("da_target %x, da_lun %x, a_hba_tran %x\n",
391 pkt
->pkt_address
.da_target
, pkt
->pkt_address
.da_lun
,
392 pkt
->pkt_address
.a_hba_tran
);
393 printf("From address : da_target %x, da_lun %x, a_hba_tran %x\n",
394 ap
->da_target
, ap
->da_lun
, ap
->a_hba_tran
);
395 printf("Pkt %x\n", pkt
);
405 struct dcd_address
*ap
,
409 kmem_free((struct dcd_pkt_wrapper
*)pkt
,
410 ((struct dcd_pkt_wrapper
*)pkt
)->pkt_wrapper_len
);
415 * Called by an HBA to map strings to capability indices
419 dcd_hba_lookup_capstr(char *capstr
)
423 * Capability strings, masking the '-' vs '_'.
425 static struct cap_strings
{
429 { "dma-max", DCD_CAP_DMA_MAX
},
430 { "dma_max", DCD_CAP_DMA_MAX
},
431 { "ultraata", DCD_CAP_ULTRA_ATA
},
432 { "busmaster", DCD_CAP_BUS_MASTER
},
433 { "overlap", DCD_CAP_OVERLAP
},
434 { "parity", DCD_CAP_PARITY
},
435 { "sector-size", DCD_CAP_SECTOR_SIZE
},
436 { "total-sectors", DCD_CAP_TOTAL_SECTORS
},
437 { "geometry", DCD_CAP_GEOMETRY
},
438 { "block-mode", DCD_CAP_BLOCKMODE
},
439 { "block-factor", DCD_CAP_BLOCKFACTOR
},
440 { "dma-support", DCD_CAP_DMA_SUPPORT
},
441 { "pio-support", DCD_CAP_PIO_SUPPORT
},
442 { "lba-addressing", DCD_CAP_LBA_ADDRESSING
},
445 struct cap_strings
*cp
;
447 for (cp
= cap_string
; cp
->cap_string
!= NULL
; cp
++) {
448 if (strcmp(cp
->cap_string
, capstr
) == 0) {
449 return (cp
->cap_index
);