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