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 2005 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 /*
30 * Utility DCD configuration routines.
31 */
32
33 #include <sys/dada/dada.h>
34 #include <sys/modctl.h>
35
36 extern struct mod_ops mod_miscops;
37
38 static struct modlmisc modlmisc = {
39 &mod_miscops, /* Type of module */
40 " ATA Bus Utility Routines"
41 };
42
43 static struct modlinkage modlinkage = {
44 MODREV_1, (void *)&modlmisc, NULL
45 };
46
47
48
49 static int dcd_test(struct dcd_pkt *);
50 void makecommand(struct dcd_pkt *, int, uchar_t, uint32_t,
51 uchar_t, uint32_t, uchar_t, uchar_t);
52
53 int
_init()54 _init()
55 {
56
57 (void) dcd_initialize_hba_interface();
58
59 return (mod_install(&modlinkage));
60 }
61
62
63 /*
64 * There is no _fini() routine because this module is never unloaded.
65 */
66 int
_info(modinfop)67 _info(modinfop)
68 struct modinfo *modinfop;
69 {
70
71 return (mod_info(&modlinkage, modinfop));
72 }
73
74 /*
75 * The implementation of dcd_probe allows a particular HBA to intercept the call
76 * for any post or pre-processing it may need. The default, if the HBA does not
77 * override it, is to call dcd_hba_probe.
78 */
79 int
dcd_probe(struct dcd_device * devp,int (* callback)())80 dcd_probe(struct dcd_device *devp, int (*callback)())
81 {
82 dcd_hba_tran_t *hba_tran = devp->dcd_address->a_hba_tran;
83
84 if (hba_tran->tran_tgt_probe != NULL) {
85 return ((*hba_tran->tran_tgt_probe)(devp, callback));
86 } else {
87 return (dcd_hba_probe(devp, callback));
88 }
89 }
90
91 /*
92 * Undo the dcd_probe
93 */
94 void
dcd_unprobe(struct dcd_device * devp)95 dcd_unprobe(struct dcd_device *devp)
96 {
97 if (devp->dcd_ident) {
98 kmem_free((caddr_t)devp->dcd_ident, SUN_IDENTSIZE);
99 devp->dcd_ident = (struct dcd_identify *)NULL;
100 }
101 }
102
103 #define ROUTE (devp->dcd_address)
104
105 int
dcd_hba_probe(struct dcd_device * devp,int (* callback)())106 dcd_hba_probe(struct dcd_device *devp, int (*callback)())
107 {
108
109 struct dcd_pkt *ident_pkt = NULL;
110 int rval = DCDPROBE_NOMEM;
111 struct buf *ident_bp = NULL;
112 int (*cb_flag)();
113
114 if (devp->dcd_ident == NULL) {
115 #ifdef DEBUG1
116 printf("Dcd_ident is NULL\n");
117 #endif
118
119 devp->dcd_ident = (struct dcd_identify *)
120 kmem_alloc(SUN_IDENTSIZE, ((callback == SLEEP_FUNC)?
121 KM_SLEEP : KM_NOSLEEP));
122 if (devp->dcd_ident == NULL) {
123 goto out;
124 }
125 }
126
127 if (callback != SLEEP_FUNC && callback != NULL_FUNC) {
128 cb_flag = NULL_FUNC;
129 } else {
130 cb_flag = callback;
131 }
132
133 ident_bp = dcd_alloc_consistent_buf(ROUTE, (struct buf *)NULL,
134 (uint_t)SUN_IDENTSIZE, B_READ, cb_flag, NULL);
135 if (ident_bp == NULL) {
136 goto out;
137 }
138
139 ident_pkt = dcd_init_pkt(ROUTE, (struct dcd_pkt *)NULL,
140 ident_bp, sizeof (struct dcd_cmd), 2, 0,
141 PKT_CONSISTENT,
142 callback, NULL);
143
144 if (ident_pkt == NULL) {
145 if (ident_bp->b_error == 0)
146 rval = DCDPROBE_NOMEM_CB;
147 goto out;
148 }
149
150 bp_mapin(ident_bp);
151
152 bzero((caddr_t)devp->dcd_ident, SUN_IDENTSIZE);
153
154 makecommand(ident_pkt, FLAG_NOINTR, IDENTIFY, 0, ADD_LBA_MODE,
155 SUN_IDENTSIZE, DATA_READ, 0);
156
157 /*
158 * The first identify will tell us whether the target responded
159 * or not.
160 */
161
162 if (dcd_test(ident_pkt) < 0) {
163 #ifdef DEBUG1
164 printf("dcd_test: failed\n");
165 #endif
166 if (ident_pkt->pkt_reason == CMD_INCOMPLETE) {
167 rval = DCDPROBE_NORESP;
168 goto out;
169 } else {
170 /*
171 * retry one more time
172 */
173 if (dcd_test(ident_pkt) < 0) {
174 rval = DCDPROBE_FAILURE;
175 goto out;
176 }
177 }
178 }
179
180 #ifdef DEBUG1
181 printf("Pkt reason %x, scsbp %x\n", ident_pkt->pkt_reason,
182 *ident_pkt->pkt_scbp);
183 #endif
184 /*
185 * If we are lucky, this identify succeeded
186 */
187 if ((ident_pkt->pkt_reason == CMD_CMPLT) &&
188 (((*ident_pkt->pkt_scbp) & STATUS_ATA_MASK) == 0)) {
189 goto done;
190 }
191
192 /*
193 * the second inquiry, allows the host adapters to try again.
194 */
195 if (dcd_test(ident_pkt) < 0) {
196 if (ident_pkt->pkt_reason == CMD_INCOMPLETE)
197 rval = DCDPROBE_NORESP;
198 else
199 rval = DCDPROBE_FAILURE;
200 goto out;
201 }
202
203 /*
204 * At this point we are guarenteed that something responded
205 * to this target. We don't know yest what kind of device it is.
206 */
207
208 if (dcd_test(ident_pkt) < 0) {
209 rval = DCDPROBE_FAILURE;
210 goto out;
211 }
212
213 done:
214 /*
215 * If we got no error then receive the indentify data,
216 */
217 if ((ident_pkt->pkt_state & STATE_XFERRED_DATA) == 0 &&
218 ident_pkt->pkt_resid > 0) {
219 rval = DCDPROBE_NONCCS;
220 } else {
221 bcopy((caddr_t)ident_bp->b_un.b_addr,
222 (caddr_t)devp->dcd_ident, SUN_IDENTSIZE);
223 rval = DCDPROBE_EXISTS;
224 }
225
226 out:
227 if (ident_pkt) {
228 dcd_destroy_pkt(ident_pkt);
229 }
230 if (ident_bp) {
231 dcd_free_consistent_buf(ident_bp);
232 }
233 return (rval);
234 }
235
236
237 static int
dcd_test(struct dcd_pkt * pkt)238 dcd_test(struct dcd_pkt *pkt)
239 {
240
241 int rval = -1;
242
243 pkt->pkt_flags |= FLAG_NOINTR;
244 pkt->pkt_time = DCD_POLL_TIMEOUT;
245
246 #ifdef DEBUG1
247 printf("flags %x: timeout %x\n", pkt->pkt_flags, pkt->pkt_time);
248 #endif
249
250 if (dcd_transport(pkt) != TRAN_ACCEPT) {
251 goto error;
252 } else if (pkt->pkt_reason == CMD_INCOMPLETE &&
253 pkt->pkt_state == 0) {
254 goto error;
255 } else if (pkt->pkt_reason != CMD_CMPLT) {
256 goto error;
257 } else if (((*pkt->pkt_scbp) & STATUS_ATA_MASK) == STATUS_ATA_BUSY) {
258 rval = 0;
259 } else {
260 rval = 0;
261 }
262 error:
263 #ifdef DEBUG1
264 printf("dcd_test: rval is %x\n", rval);
265 #endif
266
267 return (rval);
268 }
269
270 void
makecommand(struct dcd_pkt * pkt,int flags,uchar_t command,uint32_t block,uchar_t address_mode,uint32_t size,uchar_t direction,uchar_t features)271 makecommand(struct dcd_pkt *pkt,
272 int flags,
273 uchar_t command,
274 uint32_t block,
275 uchar_t address_mode,
276 uint32_t size,
277 uchar_t direction,
278 uchar_t features)
279 {
280
281 struct dcd_cmd *cdbp = (struct dcd_cmd *)pkt->pkt_cdbp;
282
283 cdbp->cmd = command;
284 cdbp->sector_num.lba_num = block;
285 cdbp->address_mode = address_mode;
286 cdbp->direction = direction;
287 cdbp->size = size; /* Size in bytes */
288 cdbp->features = features;
289
290 pkt->pkt_flags = flags;
291 #ifdef DEBUG1
292 printf("pkt flags set in dada %x\n", pkt->pkt_flags);
293
294 printf("command %x, flags %x, block %x, address_mode %x, size %x\n",
295 command, flags, block, address_mode, size);
296 #endif
297
298
299 }
300