xref: /illumos-gate/usr/src/uts/sun/io/dada/impl/dcd_hba.c (revision eb0cc229f19c437a6b538d3ac0d0443268290b7e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/note.h>
30 
31 /*
32  * Generic SCSI Host Bus Adapter interface implementation
33  */
34 
35 #include <sys/dada/dada.h>
36 
37 extern int dcd_options;
38 
39 static kmutex_t	dcd_hba_mutex;
40 
41 kmutex_t	dcd_log_mutex;
42 
43 struct dcd_hba_inst {
44 	dev_info_t	*inst_dip;
45 	dcd_hba_tran_t	*inst_hba_tran;
46 	struct dcd_hba_inst	*inst_next;
47 	struct	dcd_hba_inst	*inst_prev;
48 };
49 
50 static struct dcd_hba_inst	*dcd_hba_list	= NULL;
51 static struct dcd_hba_inst	*dcd_hba_list_tail = NULL;
52 
53 
54 _NOTE(READ_ONLY_DATA(dev_ops))
55 
56 kmutex_t	dcd_flag_nointr_mutex;
57 kcondvar_t	dcd_flag_nointr_cv;
58 
59 
60 /*
61  * Called from _init when loading the dcd module.
62  */
63 void
64 dcd_initialize_hba_interface()
65 {
66 	mutex_init(&dcd_hba_mutex, NULL, MUTEX_DRIVER, NULL);
67 	mutex_init(&dcd_flag_nointr_mutex, NULL, MUTEX_DRIVER, NULL);
68 	cv_init(&dcd_flag_nointr_cv, NULL, CV_DRIVER, NULL);
69 	mutex_init(&dcd_log_mutex, NULL, MUTEX_DRIVER, NULL);
70 }
71 
72 /*
73  * Called from fini() when unloading the dcd module.
74  */
75 
76 void
77 dcd_uninitialize_hba_interface()
78 {
79 	mutex_destroy(&dcd_hba_mutex);
80 	cv_destroy(&dcd_flag_nointr_cv);
81 	mutex_destroy(&dcd_flag_nointr_mutex);
82 	mutex_destroy(&dcd_log_mutex);
83 }
84 
85 
86 /*
87  * Called by an HBA from _init()
88  */
89 /* ARGSUSED */
90 int
91 dcd_hba_init(struct modlinkage *modlp)
92 {
93 
94 	return (0);
95 }
96 
97 
98 
99 #ifdef NOTNEEDED
100 /* ARGSUSED */
101 int
102 dcd_hba_attach(dev_info_t *dip,
103 	ddi_dma_lim_t	*hba_lim,
104 	dcd_hba_tran_t	*hba_tran,
105 	int		flags,
106 	void		*hba_options)
107 {
108 
109 	ddi_dma_attr_t		hba_dma_attr;
110 
111 	bzero(&hba_dma_attr, sizeof (ddi_dma_attr_t));
112 
113 	hba_dma_attr.dma_attr_burstsizes = hba_lim->dlim_burstsizes;
114 	hba_dma_attr.dma_attr_minxfer = hba_lim->dlim_minxfer;
115 
116 	return (dcd_hba_attach_setup(dip, &hba_dma_attr, hba_tran, flags));
117 }
118 #endif
119 
120 
121 int
122 dcd_hba_attach(
123 	dev_info_t	*dip,
124 	ddi_dma_attr_t	*hba_dma_attr,
125 	dcd_hba_tran_t	*hba_tran,
126 	int		flags)
127 {
128 
129 	struct dcd_hba_inst	*elem;
130 	int			value;
131 	int			len;
132 	char			*prop_name;
133 	char			*errmsg =
134 		"dcd_hba_attach: cannott create property '%s' for %s%d\n";
135 
136 	/*
137 	 * Link this instance into the list
138 	 */
139 	elem = kmem_alloc(sizeof (struct dcd_hba_inst), KM_SLEEP);
140 
141 	elem->inst_dip = dip;
142 	elem->inst_hba_tran = hba_tran;
143 
144 	mutex_enter(&dcd_hba_mutex);
145 	elem->inst_next = NULL;
146 	elem->inst_prev = dcd_hba_list_tail;
147 
148 	if (dcd_hba_list == NULL) {
149 		dcd_hba_list = elem;
150 	}
151 	if (dcd_hba_list_tail) {
152 		dcd_hba_list_tail->inst_next = elem;
153 	}
154 	dcd_hba_list_tail = elem;
155 	mutex_exit(&dcd_hba_mutex);
156 
157 
158 	/*
159 	 * Save all the improtant HBA information that must be accessed
160 	 * later.
161 	 */
162 
163 	hba_tran->tran_hba_dip = dip;
164 	hba_tran->tran_hba_flags = flags;
165 
166 	/*
167 	 * Note: We only need dma_attr_minxfer and dma_attr_burstsize
168 	 * from the DMA atrributes
169 	 */
170 
171 	hba_tran->tran_min_xfer = hba_dma_attr->dma_attr_minxfer;
172 	hba_tran->tran_min_burst_size =
173 			(1<<(ddi_ffs(hba_dma_attr->dma_attr_burstsizes)-1));
174 	hba_tran->tran_max_burst_size =
175 			(1<<(ddi_fls(hba_dma_attr->dma_attr_burstsizes)-1));
176 
177 
178 
179 	prop_name = "dcd_options";
180 	len = 0;
181 	if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN, 0, prop_name,
182 	    NULL, &len) == DDI_PROP_NOT_FOUND) {
183 		value = dcd_options;
184 		if (ddi_prop_update_int(DDI_MAJOR_T_UNKNOWN, dip,
185 		    prop_name, value) != DDI_PROP_SUCCESS) {
186 			cmn_err(CE_CONT, errmsg, prop_name,
187 				ddi_get_name(dip), ddi_get_instance(dip));
188 		}
189 	}
190 
191 
192 	/*
193 	 * XXX : This needs to be removed when code cleanup
194 	 * ddi_set_driver_private(dip, (caddr_t)hba_tran);
195 	 */
196 #ifdef DEBUG1
197 	printf("Called Set driver private with dip %x, tran %x\n",
198 		dip, hba_tran);
199 #endif
200 
201 	return (DDI_SUCCESS);
202 }
203 
204 
205 /*
206  * called by an HBA to detach an instance of the driver
207  */
208 
209 int
210 dcd_hba_detach(dev_info_t *dip)
211 {
212 
213 	dcd_hba_tran_t	*hba;
214 	struct dcd_hba_inst 	*elem;
215 
216 	hba = ddi_get_driver_private(dip);
217 	ddi_set_driver_private(dip, NULL);
218 	ASSERT(hba != NULL);
219 
220 	hba->tran_hba_dip = (dev_info_t *)NULL;
221 	hba->tran_hba_flags = 0;
222 	hba->tran_min_burst_size = (uchar_t)0;
223 	hba->tran_max_burst_size = (uchar_t)0;
224 
225 
226 	/*
227 	 * Remove HBA instance from dcd_hba_list
228 	 */
229 
230 	mutex_enter(&dcd_hba_mutex);
231 
232 	for (elem = dcd_hba_list; elem != (struct dcd_hba_inst *)NULL;
233 		elem = elem->inst_next) {
234 		if (elem->inst_dip == dip)
235 			break;
236 	}
237 
238 	if (elem == (struct dcd_hba_inst *)NULL) {
239 		cmn_err(CE_NOTE, "dcd_hba_attach: Unknown HBA instance\n");
240 		mutex_exit(&dcd_hba_mutex);
241 	}
242 
243 	if (elem == dcd_hba_list) {
244 		dcd_hba_list = elem->inst_next;
245 		dcd_hba_list->inst_prev = (struct dcd_hba_inst *)NULL;
246 	} else if (elem == dcd_hba_list_tail) {
247 		dcd_hba_list_tail = elem->inst_prev;
248 		dcd_hba_list_tail->inst_next = (struct dcd_hba_inst *)NULL;
249 	} else {
250 		elem->inst_prev->inst_next = elem->inst_next;
251 		elem->inst_next->inst_prev = elem->inst_prev;
252 	}
253 	mutex_exit(&dcd_hba_mutex);
254 
255 	kmem_free(elem, sizeof (struct dcd_hba_inst));
256 
257 	return (DDI_SUCCESS);
258 }
259 
260 void
261 dcd_hba_fini()
262 {
263 
264 }
265 
266 /* ARGSUSED */
267 dcd_hba_tran_t *
268 dcd_hba_tran_alloc(
269 	dev_info_t	*dip,
270 	int		flags)
271 {
272 
273 	return (kmem_zalloc(sizeof (dcd_hba_tran_t),
274 		(flags & DCD_HBA_CANSLEEP) ? KM_SLEEP: KM_NOSLEEP));
275 }
276 
277 
278 void
279 dcd_hba_tran_free(dcd_hba_tran_t	*hba_tran)
280 {
281 
282 	kmem_free(hba_tran, sizeof (dcd_hba_tran_t));
283 }
284 
285 
286 /*
287  * XXX: Do we really need the following routines.
288  */
289 
290 /*
291  * private wrapper for dcd_pkt's allocated via scsi_hba_pkt_alloc
292  */
293 
294 struct dcd_pkt_wrapper {
295 	struct dcd_pkt	dcd_pkt;
296 	int		pkt_wrapper_len;
297 };
298 
299 _NOTE(SCHEME_PROTECTS_DATA("unique per thread", dcd_pkt_wrapper))
300 
301 /*
302  * Round up all allocations so that we can gurentee
303  * long-long alignment. This is the same alignment
304  * provided by kmem_alloc().
305  */
306 
307 #define	ROUNDUP(x)	(((x) + 0x07) & ~0x07)
308 
309 /*
310  * Called by an HBA to allocate a dcd_pkt
311  */
312 
313 /* ARGSUSED */
314 struct dcd_pkt *
315 dcd_hba_pkt_alloc(
316 	struct dcd_address	*ap,
317 	int			cmdlen,
318 	int			statuslen,
319 	int			tgtlen,
320 	int			hbalen,
321 	int			(*callback)(caddr_t arg),
322 	caddr_t			arg)
323 {
324 
325 	struct dcd_pkt	*pkt;
326 	struct dcd_pkt_wrapper	*hba_pkt;
327 	caddr_t		p;
328 	int		pktlen;
329 
330 
331 	/*
332 	 * Sanity check
333 	 */
334 	if (callback != SLEEP_FUNC && callback != NULL_FUNC) {
335 		cmn_err(CE_PANIC, " dcd_hba_pkt_alloc: callback must be"
336 				" either SLEEP or NULL\n");
337 	}
338 
339 
340 	/*
341 	 * Round up so everything gets allocated on long-word boundaries.
342 	 */
343 
344 	cmdlen = ROUNDUP(cmdlen);
345 	tgtlen = ROUNDUP(tgtlen);
346 	hbalen = ROUNDUP(hbalen);
347 	statuslen = ROUNDUP(statuslen);
348 	pktlen = sizeof (struct dcd_pkt_wrapper)
349 		+ cmdlen + tgtlen +hbalen + statuslen;
350 
351 	hba_pkt = kmem_zalloc(pktlen,
352 		(callback = SLEEP_FUNC) ? KM_SLEEP: KM_NOSLEEP);
353 
354 	if (hba_pkt == NULL) {
355 		ASSERT(callback == NULL_FUNC);
356 		return (NULL);
357 	}
358 
359 	/*
360 	 * Set up or private info on this pkt
361 	 */
362 	hba_pkt->pkt_wrapper_len = pktlen;
363 	pkt = &hba_pkt->dcd_pkt;
364 	p = (caddr_t)(hba_pkt + 1);
365 
366 	/*
367 	 * set up pointers to private data areas, cdb and status.
368 	 */
369 	if (hbalen > 0) {
370 		pkt->pkt_ha_private = (ataopaque_t)p;
371 		p += hbalen;
372 	}
373 
374 	if (tgtlen > 0) {
375 		pkt->pkt_private = (ataopaque_t)p;
376 		p += tgtlen;
377 	}
378 
379 	if (statuslen > 0) {
380 		pkt->pkt_scbp = (uchar_t *)p;
381 		p += statuslen;
382 	}
383 
384 	if (cmdlen > 0) {
385 		pkt->pkt_cdbp = (void *)p;
386 	}
387 
388 	/*
389 	 * Initialize the pkt's dcd_address
390 	 */
391 	pkt->pkt_address = *ap;
392 #ifdef DEBUG1
393 	printf("a_target %x, a_lun %x, a_hba_tran %x\n",
394 		pkt->pkt_address.a_target, pkt->pkt_address.a_lun,
395 		pkt->pkt_address.a_hba_tran);
396 	printf("From address : a_target %x, a_lun %x, a_hba_tran %x\n",
397 		ap->a_target, ap->a_lun, ap->a_hba_tran);
398 	printf("Pkt %x\n", pkt);
399 
400 #endif
401 	return (pkt);
402 }
403 
404 
405 /* ARGSUSED */
406 void
407 dcd_hba_pkt_free(
408 	struct dcd_address *ap,
409 	struct dcd_pkt	   *pkt)
410 {
411 
412 	kmem_free((struct dcd_pkt_wrapper *)pkt,
413 		((struct dcd_pkt_wrapper *)pkt)->pkt_wrapper_len);
414 }
415 
416 
417 /*
418  * Called by an HBA to map strings to capability indices
419  */
420 
421 int
422 dcd_hba_lookup_capstr(char		*capstr)
423 {
424 
425 	/*
426 	 * Capability strings, masking the '-' vs '_'.
427 	 */
428 	static struct cap_strings {
429 		char *cap_string;
430 		int   cap_index;
431 	} cap_string[] = {
432 		{ "dma-max",		DCD_CAP_DMA_MAX		},
433 		{ "dma_max",		DCD_CAP_DMA_MAX		},
434 		{ "ultraata",		DCD_CAP_ULTRA_ATA	},
435 		{ "busmaster",		DCD_CAP_BUS_MASTER	},
436 		{ "overlap",		DCD_CAP_OVERLAP		},
437 		{ "parity",		DCD_CAP_PARITY		},
438 		{ "sector-size",	DCD_CAP_SECTOR_SIZE	},
439 		{ "total-sectors",	DCD_CAP_TOTAL_SECTORS	},
440 		{ "geometry",		DCD_CAP_GEOMETRY	},
441 		{ "block-mode",		DCD_CAP_BLOCKMODE	},
442 		{ "block-factor",	DCD_CAP_BLOCKFACTOR	},
443 		{ "dma-support",		DCD_CAP_DMA_SUPPORT	},
444 		{ "pio-support", 	DCD_CAP_PIO_SUPPORT	},
445 		{ "lba-addressing",	DCD_CAP_LBA_ADDRESSING  },
446 		{ NULL, 0					}
447 	};
448 	struct cap_strings *cp;
449 
450 	for (cp = cap_string; cp->cap_string != NULL; cp++) {
451 		if (strcmp(cp->cap_string, capstr) == 0) {
452 			return (cp->cap_index);
453 		}
454 	}
455 
456 	return (-1);
457 }
458