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 /*
28 * 1394 mass storage SBP-2 bus routines
29 */
30
31 #include <sys/param.h>
32 #include <sys/errno.h>
33 #include <sys/cred.h>
34 #include <sys/conf.h>
35 #include <sys/modctl.h>
36 #include <sys/stat.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39
40 #include <sys/sbp2/bus.h>
41 #include <sys/1394/targets/scsa1394/impl.h>
42
43 static ddi_iblock_cookie_t scsa1394_bus_get_iblock_cookie(void *);
44 static uint_t scsa1394_bus_get_node_id(void *);
45 static int scsa1394_bus_alloc_cmd(void *, void **, int);
46 static void scsa1394_bus_free_cmd(void *, void *);
47 static int scsa1394_bus_rq(void *, void *, uint64_t, uint32_t *, int *);
48 static int scsa1394_bus_rb(void *, void *, uint64_t, mblk_t **, int,
49 int *);
50 static int scsa1394_bus_wq(void *, void *, uint64_t, uint32_t, int *);
51 static int scsa1394_bus_wb(void *, void *, uint64_t, mblk_t *, int,
52 int *);
53 static int scsa1394_bus_alloc_buf(void *, sbp2_bus_buf_t *);
54 static int scsa1394_bus_alloc_buf_phys(void *, sbp2_bus_buf_t *);
55 static void scsa1394_bus_free_buf_phys(void *, sbp2_bus_buf_t *);
56 static int scsa1394_bus_alloc_buf_normal(void *, sbp2_bus_buf_t *,
57 boolean_t);
58 static void scsa1394_bus_free_buf_normal(void *, sbp2_bus_buf_t *);
59 static void scsa1394_bus_free_buf(void *, sbp2_bus_buf_t *);
60 static int scsa1394_bus_sync_buf(void *, sbp2_bus_buf_t *, off_t, size_t,
61 int);
62 static void scsa1394_bus_buf_rw_done(void *, sbp2_bus_buf_t *, void *, int);
63
64 /* callbacks */
65 static void scsa1394_bus_recv_read_request(cmd1394_cmd_t *);
66 static void scsa1394_bus_recv_write_request(cmd1394_cmd_t *);
67
68 sbp2_bus_t scsa1394_sbp2_bus = {
69 SBP2_BUS_REV, /* rev */
70 0xFFFFF0000000LL, /* csr_base */
71 IEEE1394_CONFIG_ROM_ADDR, /* cfgrom_addr */
72 scsa1394_bus_get_iblock_cookie, /* get_iblock_cookie */
73 scsa1394_bus_get_node_id, /* get_node_id */
74 scsa1394_bus_alloc_buf, /* alloc_buf */
75 scsa1394_bus_free_buf, /* free_buf */
76 scsa1394_bus_sync_buf, /* sync_buf */
77 scsa1394_bus_buf_rw_done, /* buf_rd_done */
78 scsa1394_bus_buf_rw_done, /* buf_wr_done */
79 scsa1394_bus_alloc_cmd, /* alloc_cmd */
80 scsa1394_bus_free_cmd, /* free_cmd */
81 scsa1394_bus_rq, /* rq */
82 scsa1394_bus_rb, /* rb */
83 scsa1394_bus_wq, /* wq */
84 scsa1394_bus_wb /* wb */
85 };
86
87 /*
88 * fault injector
89 *
90 * global on/off switch
91 */
92 int scsa1394_bus_fi_on = 0;
93
94 /* fault probabilities per operation, in tenths of percent, i.e. 10 is 1% */
95 int scsa1394_bus_fi_prob_alloc_buf = 10;
96 int scsa1394_bus_fi_prob_alloc_cmd = 10;
97 int scsa1394_bus_fi_prob_rq = 10;
98 int scsa1394_bus_fi_prob_rb = 10;
99 int scsa1394_bus_fi_prob_wq = 10;
100 int scsa1394_bus_fi_prob_wb = 10;
101
102 #define SCSA1394_BUS_FI_POSITIVE(p) (scsa1394_bus_fi_on && \
103 ((p) > 0) && ((gethrtime() % (p)) == 0))
104
105 /*
106 * translate command result to SBP2 error code
107 */
108 static int
scsa1394_bus_rw_result2code(int result)109 scsa1394_bus_rw_result2code(int result)
110 {
111 int code;
112
113 switch (result) {
114 case CMD1394_EDEVICE_BUSY:
115 code = SBP2_EBUSY;
116 break;
117 case CMD1394_EADDRESS_ERROR:
118 code = SBP2_EADDR;
119 break;
120 case CMD1394_ETIMEOUT:
121 case CMD1394_ERETRIES_EXCEEDED:
122 code = SBP2_ETIMEOUT;
123 break;
124 case CMD1394_EDEVICE_REMOVED:
125 code = SBP2_ENODEV;
126 break;
127 default:
128 code = SBP2_EIO;
129 break;
130 }
131 return (code);
132 }
133
134 static ddi_iblock_cookie_t
scsa1394_bus_get_iblock_cookie(void * hdl)135 scsa1394_bus_get_iblock_cookie(void *hdl)
136 {
137 scsa1394_state_t *sp = hdl;
138
139 return (sp->s_attachinfo.iblock_cookie);
140 }
141
142 static uint_t
scsa1394_bus_get_node_id(void * hdl)143 scsa1394_bus_get_node_id(void *hdl)
144 {
145 scsa1394_state_t *sp = hdl;
146
147 return (sp->s_attachinfo.localinfo.local_nodeID);
148 }
149
150
151 /*ARGSUSED*/
152 static int
scsa1394_bus_alloc_cmd(void * hdl,void ** cmdp,int flags)153 scsa1394_bus_alloc_cmd(void *hdl, void **cmdp, int flags)
154 {
155 scsa1394_state_t *sp = hdl;
156 cmd1394_cmd_t *cmd;
157
158 if (SCSA1394_BUS_FI_POSITIVE(scsa1394_bus_fi_prob_alloc_cmd)) {
159 return (SBP2_ENOMEM);
160 }
161
162 if (t1394_alloc_cmd(sp->s_t1394_hdl, 0, &cmd) != DDI_SUCCESS) {
163 return (SBP2_ENOMEM);
164 }
165 *cmdp = cmd;
166 return (SBP2_SUCCESS);
167 }
168
169
170 static void
scsa1394_bus_free_cmd(void * hdl,void * argcmd)171 scsa1394_bus_free_cmd(void *hdl, void *argcmd)
172 {
173 scsa1394_state_t *sp = hdl;
174 cmd1394_cmd_t *cmd = argcmd;
175
176 (void) t1394_free_cmd(sp->s_t1394_hdl, 0, &cmd);
177 }
178
179
180 /*ARGSUSED*/
181 static int
scsa1394_bus_rq(void * hdl,void * argcmd,uint64_t addr,uint32_t * q,int * berr)182 scsa1394_bus_rq(void *hdl, void *argcmd, uint64_t addr, uint32_t *q, int *berr)
183 {
184 scsa1394_state_t *sp = hdl;
185 cmd1394_cmd_t *cmd = argcmd;
186
187 if (SCSA1394_BUS_FI_POSITIVE(scsa1394_bus_fi_prob_rq)) {
188 return (SBP2_EIO);
189 }
190
191 cmd->cmd_addr = addr;
192 cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD;
193 cmd->cmd_options = CMD1394_BLOCKING;
194
195 if ((t1394_read(sp->s_t1394_hdl, cmd) != DDI_SUCCESS) ||
196 (cmd->cmd_result != CMD1394_CMDSUCCESS)) {
197 *berr = cmd->cmd_result;
198 return (scsa1394_bus_rw_result2code(cmd->cmd_result));
199 }
200
201 *q = cmd->cmd_u.q.quadlet_data;
202 return (SBP2_SUCCESS);
203 }
204
205
206 /*ARGSUSED*/
207 static int
scsa1394_bus_rb(void * hdl,void * argcmd,uint64_t addr,mblk_t ** bpp,int len,int * berr)208 scsa1394_bus_rb(void *hdl, void *argcmd, uint64_t addr, mblk_t **bpp, int len,
209 int *berr)
210 {
211 scsa1394_state_t *sp = hdl;
212 cmd1394_cmd_t *cmd = argcmd;
213 mblk_t *bp = *bpp;
214
215 /* caller wants us to allocate memory */
216 if ((bp == NULL) && ((bp = allocb(len, BPRI_HI)) == NULL)) {
217 return (SBP2_ENOMEM);
218 }
219
220 cmd->cmd_addr = addr;
221 cmd->cmd_type = CMD1394_ASYNCH_RD_BLOCK;
222 cmd->cmd_u.b.data_block = bp;
223 cmd->cmd_u.b.blk_length = len;
224 cmd->cmd_options = CMD1394_BLOCKING;
225
226 if ((t1394_read(sp->s_t1394_hdl, cmd) != DDI_SUCCESS) ||
227 (cmd->cmd_result != CMD1394_CMDSUCCESS)) {
228 freeb(bp);
229 *berr = cmd->cmd_result;
230 return (scsa1394_bus_rw_result2code(cmd->cmd_result));
231 }
232
233 *bpp = bp;
234 return (SBP2_SUCCESS);
235 }
236
237
238 /*ARGSUSED*/
239 static int
scsa1394_bus_wq(void * hdl,void * argcmd,uint64_t addr,uint32_t q,int * berr)240 scsa1394_bus_wq(void *hdl, void *argcmd, uint64_t addr, uint32_t q, int *berr)
241 {
242 scsa1394_state_t *sp = hdl;
243 cmd1394_cmd_t *cmd = argcmd;
244
245 cmd->cmd_addr = addr;
246 cmd->cmd_type = CMD1394_ASYNCH_WR_QUAD;
247 cmd->cmd_u.q.quadlet_data = q;
248 cmd->cmd_options = CMD1394_BLOCKING;
249
250 if ((t1394_write(sp->s_t1394_hdl, cmd) != DDI_SUCCESS) ||
251 (cmd->cmd_result != CMD1394_CMDSUCCESS)) {
252 *berr = cmd->cmd_result;
253 return (scsa1394_bus_rw_result2code(cmd->cmd_result));
254 }
255
256 return (SBP2_SUCCESS);
257 }
258
259
260 /*ARGSUSED*/
261 static int
scsa1394_bus_wb(void * hdl,void * argcmd,uint64_t addr,mblk_t * bp,int len,int * berr)262 scsa1394_bus_wb(void *hdl, void *argcmd, uint64_t addr, mblk_t *bp, int len,
263 int *berr)
264 {
265 scsa1394_state_t *sp = hdl;
266 cmd1394_cmd_t *cmd = argcmd;
267
268 cmd->cmd_addr = addr;
269 cmd->cmd_type = CMD1394_ASYNCH_WR_BLOCK;
270 cmd->cmd_u.b.data_block = bp;
271 cmd->cmd_u.b.blk_length = len;
272 cmd->cmd_options = CMD1394_BLOCKING;
273
274 if ((t1394_write(sp->s_t1394_hdl, cmd) != DDI_SUCCESS) ||
275 (cmd->cmd_result != CMD1394_CMDSUCCESS)) {
276 *berr = cmd->cmd_result;
277 return (scsa1394_bus_rw_result2code(cmd->cmd_result));
278 }
279
280 return (SBP2_SUCCESS);
281 }
282
283
284 /*ARGSUSED*/
285 static int
scsa1394_bus_alloc_buf(void * hdl,sbp2_bus_buf_t * buf)286 scsa1394_bus_alloc_buf(void *hdl, sbp2_bus_buf_t *buf)
287 {
288 if (SCSA1394_BUS_FI_POSITIVE(scsa1394_bus_fi_prob_alloc_buf)) {
289 return (SBP2_ENOMEM);
290 }
291
292 if (buf->bb_flags & SBP2_BUS_BUF_DMA) {
293 return (scsa1394_bus_alloc_buf_phys(hdl, buf));
294 } else {
295 return (scsa1394_bus_alloc_buf_normal(hdl, buf,
296 ((buf->bb_flags & SBP2_BUS_BUF_POSTED) != 0)));
297 }
298 }
299
300
301 static void
scsa1394_bus_free_buf(void * hdl,sbp2_bus_buf_t * buf)302 scsa1394_bus_free_buf(void *hdl, sbp2_bus_buf_t *buf)
303 {
304 if (buf->bb_flags & SBP2_BUS_BUF_DMA) {
305 scsa1394_bus_free_buf_phys(hdl, buf);
306 } else {
307 scsa1394_bus_free_buf_normal(hdl, buf);
308 }
309 }
310
311
312 static int
scsa1394_bus_alloc_buf_phys(void * hdl,sbp2_bus_buf_t * buf)313 scsa1394_bus_alloc_buf_phys(void *hdl, sbp2_bus_buf_t *buf)
314 {
315 scsa1394_state_t *sp = hdl;
316 scsa1394_bus_buf_t *sbb; /* bus private structure */
317 size_t real_length; /* real allocated length */
318 ddi_dma_cookie_t cookie; /* cookies */
319 uint_t ccount; /* cookie count */
320 t1394_alloc_addr_t aa;
321 int result;
322
323 /* allocate bus private structure */
324 sbb = kmem_zalloc(sizeof (scsa1394_bus_buf_t), KM_SLEEP);
325 sbb->sbb_state = sp;
326
327 /* allocate DMA resources */
328 if (ddi_dma_alloc_handle(sp->s_dip, &sp->s_attachinfo.dma_attr,
329 DDI_DMA_SLEEP, NULL, &sbb->sbb_dma_hdl) != DDI_SUCCESS) {
330 kmem_free(sbb, sizeof (scsa1394_bus_buf_t));
331 return (SBP2_ENOMEM);
332 }
333
334 if (ddi_dma_mem_alloc(sbb->sbb_dma_hdl, buf->bb_len,
335 &sp->s_attachinfo.acc_attr,
336 buf->bb_flags & (DDI_DMA_STREAMING | DDI_DMA_CONSISTENT),
337 DDI_DMA_SLEEP, NULL, &buf->bb_kaddr, &real_length,
338 &sbb->sbb_acc_hdl) != DDI_SUCCESS) {
339 ddi_dma_free_handle(&sbb->sbb_dma_hdl);
340 kmem_free(sbb, sizeof (scsa1394_bus_buf_t));
341 return (SBP2_ENOMEM);
342 }
343
344 buf->bb_flags &= ~DDI_DMA_PARTIAL;
345 if (ddi_dma_addr_bind_handle(sbb->sbb_dma_hdl, NULL, buf->bb_kaddr,
346 buf->bb_len, buf->bb_flags, DDI_DMA_SLEEP, NULL,
347 &cookie, &ccount) != DDI_DMA_MAPPED) {
348 ddi_dma_mem_free(&sbb->sbb_acc_hdl);
349 ddi_dma_free_handle(&sbb->sbb_dma_hdl);
350 kmem_free(sbb, sizeof (scsa1394_bus_buf_t));
351 return (SBP2_ENOMEM);
352 }
353 ASSERT(ccount == 1);
354 buf->bb_paddr = cookie.dmac_address; /* 32-bit address */
355
356 /* allocate 1394 resources */
357 bzero(&aa, sizeof (aa));
358 aa.aa_type = T1394_ADDR_FIXED;
359 aa.aa_length = buf->bb_len;
360 if (buf->bb_flags & SBP2_BUS_BUF_RD) {
361 aa.aa_enable |= T1394_ADDR_RDENBL;
362 }
363 if (buf->bb_flags & SBP2_BUS_BUF_WR) {
364 aa.aa_enable |= T1394_ADDR_WRENBL;
365 }
366 aa.aa_address = buf->bb_paddr; /* PCI-1394 mapping is 1-1 */
367
368 if (t1394_alloc_addr(sp->s_t1394_hdl, &aa, 0, &result) != DDI_SUCCESS) {
369 (void) ddi_dma_unbind_handle(sbb->sbb_dma_hdl);
370 ddi_dma_mem_free(&sbb->sbb_acc_hdl);
371 ddi_dma_free_handle(&sbb->sbb_dma_hdl);
372 kmem_free(sbb, sizeof (scsa1394_bus_buf_t));
373 return (SBP2_ENOMEM);
374 }
375 sbb->sbb_addr_hdl = aa.aa_hdl;
376 buf->bb_baddr = aa.aa_address;
377
378 buf->bb_hdl = sbb;
379 return (SBP2_SUCCESS);
380 }
381
382
383 static void
scsa1394_bus_free_buf_phys(void * hdl,sbp2_bus_buf_t * buf)384 scsa1394_bus_free_buf_phys(void *hdl, sbp2_bus_buf_t *buf)
385 {
386 scsa1394_state_t *sp = hdl;
387 scsa1394_bus_buf_t *sbb = buf->bb_hdl;
388
389 (void) t1394_free_addr(sp->s_t1394_hdl, &sbb->sbb_addr_hdl, 0);
390 (void) ddi_dma_unbind_handle(sbb->sbb_dma_hdl);
391 ddi_dma_mem_free(&sbb->sbb_acc_hdl);
392 ddi_dma_free_handle(&sbb->sbb_dma_hdl);
393 kmem_free(sbb, sizeof (scsa1394_bus_buf_t));
394 buf->bb_hdl = NULL;
395 }
396
397
398 static int
scsa1394_bus_alloc_buf_normal(void * hdl,sbp2_bus_buf_t * buf,boolean_t posted)399 scsa1394_bus_alloc_buf_normal(void *hdl, sbp2_bus_buf_t *buf, boolean_t posted)
400 {
401 scsa1394_state_t *sp = hdl;
402 scsa1394_bus_buf_t *sbb; /* bus private structure */
403 t1394_alloc_addr_t aa;
404 int result;
405
406 /* allocate bus private structure */
407 sbb = kmem_zalloc(sizeof (scsa1394_bus_buf_t), KM_SLEEP);
408 sbb->sbb_state = sp;
409
410 /* allocate 1394 resources */
411 bzero(&aa, sizeof (aa));
412 aa.aa_type = posted ? T1394_ADDR_POSTED_WRITE : T1394_ADDR_NORMAL;
413 aa.aa_length = buf->bb_len;
414 if (buf->bb_flags & SBP2_BUS_BUF_RD) {
415 aa.aa_enable |= T1394_ADDR_RDENBL;
416 aa.aa_evts.recv_read_request = scsa1394_bus_recv_read_request;
417 }
418 if (buf->bb_flags & SBP2_BUS_BUF_WR) {
419 aa.aa_enable |= T1394_ADDR_WRENBL;
420 aa.aa_evts.recv_write_request = scsa1394_bus_recv_write_request;
421 }
422 aa.aa_arg = buf;
423
424 if (t1394_alloc_addr(sp->s_t1394_hdl, &aa, 0, &result) != DDI_SUCCESS) {
425 kmem_free(sbb, sizeof (scsa1394_bus_buf_t));
426 return (SBP2_ENOMEM);
427 }
428 sbb->sbb_addr_hdl = aa.aa_hdl;
429 buf->bb_baddr = aa.aa_address;
430
431 buf->bb_hdl = sbb;
432 return (SBP2_SUCCESS);
433 }
434
435 static void
scsa1394_bus_free_buf_normal(void * hdl,sbp2_bus_buf_t * buf)436 scsa1394_bus_free_buf_normal(void *hdl, sbp2_bus_buf_t *buf)
437 {
438 scsa1394_state_t *sp = hdl;
439 scsa1394_bus_buf_t *sbb = buf->bb_hdl;
440
441 (void) t1394_free_addr(sp->s_t1394_hdl, &sbb->sbb_addr_hdl, 0);
442 kmem_free(sbb, sizeof (scsa1394_bus_buf_t));
443 buf->bb_hdl = NULL;
444 }
445
446 /*ARGSUSED*/
447 static int
scsa1394_bus_sync_buf(void * hdl,sbp2_bus_buf_t * buf,off_t offset,size_t length,int type)448 scsa1394_bus_sync_buf(void *hdl, sbp2_bus_buf_t *buf, off_t offset,
449 size_t length, int type)
450 {
451 scsa1394_bus_buf_t *sbb = buf->bb_hdl;
452
453 if (buf->bb_flags & SBP2_BUS_BUF_DMA) {
454 return (ddi_dma_sync(sbb->sbb_dma_hdl, offset, length, type));
455 } else {
456 return (SBP2_SUCCESS);
457 }
458 }
459
460 /*ARGSUSED*/
461 static void
scsa1394_bus_buf_rw_done(void * hdl,sbp2_bus_buf_t * buf,void * reqh,int error)462 scsa1394_bus_buf_rw_done(void *hdl, sbp2_bus_buf_t *buf, void *reqh, int error)
463 {
464 scsa1394_state_t *sp = hdl;
465 cmd1394_cmd_t *req = reqh;
466
467 /* complete request */
468 switch (error) {
469 case SBP2_BUS_BUF_SUCCESS:
470 req->cmd_result = IEEE1394_RESP_COMPLETE;
471 break;
472 case SBP2_BUS_BUF_ELENGTH:
473 req->cmd_result = IEEE1394_RESP_DATA_ERROR;
474 break;
475 case SBP2_BUS_BUF_EBUSY:
476 req->cmd_result = IEEE1394_RESP_CONFLICT_ERROR;
477 break;
478 default:
479 req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
480 }
481 (void) t1394_recv_request_done(sp->s_t1394_hdl, req, 0);
482 }
483
484
485 /*
486 *
487 * --- callbacks
488 *
489 */
490 static void
scsa1394_bus_recv_read_request(cmd1394_cmd_t * req)491 scsa1394_bus_recv_read_request(cmd1394_cmd_t *req)
492 {
493 sbp2_bus_buf_t *buf = req->cmd_callback_arg;
494 scsa1394_bus_buf_t *sbb = buf->bb_hdl;
495 scsa1394_state_t *sp = sbb->sbb_state;
496
497 /* XXX sanity checks: addr, etc */
498 if (req->cmd_type == CMD1394_ASYNCH_RD_QUAD) {
499 if (buf->bb_rq_cb) {
500 buf->bb_rq_cb(buf, req, &req->cmd_u.q.quadlet_data);
501 return;
502 }
503 } else {
504 if (buf->bb_rb_cb) {
505 buf->bb_rb_cb(buf, req, &req->cmd_u.b.data_block,
506 req->cmd_u.b.blk_length);
507 return;
508 }
509 }
510 scsa1394_bus_buf_rw_done(sp, buf, req, SBP2_BUS_BUF_FAILURE);
511 }
512
513
514 static void
scsa1394_bus_recv_write_request(cmd1394_cmd_t * req)515 scsa1394_bus_recv_write_request(cmd1394_cmd_t *req)
516 {
517 sbp2_bus_buf_t *buf = req->cmd_callback_arg;
518 scsa1394_bus_buf_t *sbb = buf->bb_hdl;
519 scsa1394_state_t *sp = sbb->sbb_state;
520
521 /* XXX sanity checks: addr, etc */
522 if (req->cmd_type == CMD1394_ASYNCH_WR_QUAD) {
523 if (buf->bb_wq_cb) {
524 buf->bb_wq_cb(buf, req, req->cmd_u.q.quadlet_data);
525 return;
526 }
527 } else {
528 if (buf->bb_wb_cb) {
529 buf->bb_wb_cb(buf, req, &req->cmd_u.b.data_block);
530 return;
531 }
532 }
533 scsa1394_bus_buf_rw_done(sp, buf, req, SBP2_BUS_BUF_FAILURE);
534 }
535