xref: /dragonfly/sys/bus/cam/scsi/scsi_pt.c (revision a563ca70)
1 /*
2  * Implementation of SCSI Processor Target Peripheral driver for CAM.
3  *
4  * Copyright (c) 1998 Justin T. Gibbs.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/cam/scsi/scsi_pt.c,v 1.17 2000/01/17 06:27:37 mjacob Exp $
29  */
30 
31 #include <sys/param.h>
32 #include <sys/queue.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/types.h>
36 #include <sys/buf.h>
37 #include <sys/devicestat.h>
38 #include <sys/malloc.h>
39 #include <sys/conf.h>
40 #include <sys/ptio.h>
41 #include <sys/buf2.h>
42 #include <sys/thread2.h>
43 
44 #include "../cam.h"
45 #include "../cam_ccb.h"
46 #include "../cam_extend.h"
47 #include "../cam_periph.h"
48 #include "../cam_xpt_periph.h"
49 #include "../cam_debug.h"
50 
51 #include "scsi_all.h"
52 #include "scsi_message.h"
53 #include "scsi_pt.h"
54 
55 #include "opt_pt.h"
56 
57 typedef enum {
58 	PT_STATE_PROBE,
59 	PT_STATE_NORMAL
60 } pt_state;
61 
62 typedef enum {
63 	PT_FLAG_NONE		= 0x00,
64 	PT_FLAG_OPEN		= 0x01,
65 	PT_FLAG_DEVICE_INVALID	= 0x02,
66 	PT_FLAG_RETRY_UA	= 0x04
67 } pt_flags;
68 
69 typedef enum {
70 	PT_CCB_BUFFER_IO	= 0x01,
71 	PT_CCB_WAITING		= 0x02,
72 	PT_CCB_RETRY_UA		= 0x04,
73 	PT_CCB_BUFFER_IO_UA	= PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
74 } pt_ccb_state;
75 
76 /* Offsets into our private area for storing information */
77 #define ccb_state	ppriv_field0
78 #define ccb_bio		ppriv_ptr1
79 
80 struct pt_softc {
81 	struct	 bio_queue_head bio_queue;
82 	struct	 devstat device_stats;
83 	LIST_HEAD(, ccb_hdr) pending_ccbs;
84 	pt_state state;
85 	pt_flags flags;
86 	union	 ccb saved_ccb;
87 	int	 io_timeout;
88 	cdev_t	 dev;
89 };
90 
91 static	d_open_t	ptopen;
92 static	d_close_t	ptclose;
93 static	d_strategy_t	ptstrategy;
94 static	periph_init_t	ptinit;
95 static	void		ptasync(void *callback_arg, u_int32_t code,
96 				struct cam_path *path, void *arg);
97 static	periph_ctor_t	ptctor;
98 static	periph_oninv_t	ptoninvalidate;
99 static	periph_dtor_t	ptdtor;
100 static	periph_start_t	ptstart;
101 static	void		ptdone(struct cam_periph *periph,
102 			       union ccb *done_ccb);
103 static	d_ioctl_t	ptioctl;
104 static  int		pterror(union ccb *ccb, u_int32_t cam_flags,
105 				u_int32_t sense_flags);
106 
107 void	scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
108 			  void (*cbfcnp)(struct cam_periph *, union ccb *),
109 			  u_int tag_action, int readop, u_int byte2,
110 			  u_int32_t xfer_len, u_int8_t *data_ptr,
111 			  u_int8_t sense_len, u_int32_t timeout);
112 
113 static struct periph_driver ptdriver =
114 {
115 	ptinit, "pt",
116 	TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
117 };
118 
119 PERIPHDRIVER_DECLARE(pt, ptdriver);
120 
121 static struct dev_ops pt_ops = {
122 	{ "pt", 0, 0 },
123 	.d_open =	ptopen,
124 	.d_close =	ptclose,
125 	.d_read =	physread,
126 	.d_write =	physwrite,
127 	.d_ioctl =	ptioctl,
128 	.d_strategy =	ptstrategy,
129 };
130 
131 static struct extend_array *ptperiphs;
132 
133 #ifndef SCSI_PT_DEFAULT_TIMEOUT
134 #define SCSI_PT_DEFAULT_TIMEOUT		60
135 #endif
136 
137 static int
138 ptopen(struct dev_open_args *ap)
139 {
140 	cdev_t dev = ap->a_head.a_dev;
141 	struct cam_periph *periph;
142 	struct pt_softc *softc;
143 	int unit;
144 	int error = 0;
145 
146 	unit = minor(dev);
147 	periph = cam_extend_get(ptperiphs, unit);
148 	if (cam_periph_acquire(periph) != CAM_REQ_CMP)
149 		return (ENXIO);
150 
151 	softc = (struct pt_softc *)periph->softc;
152 
153 	cam_periph_lock(periph);
154 	if (softc->flags & PT_FLAG_DEVICE_INVALID) {
155 		cam_periph_unlock(periph);
156 		cam_periph_release(periph);
157 		return(ENXIO);
158 	}
159 
160 	if ((softc->flags & PT_FLAG_OPEN) == 0)
161 		softc->flags |= PT_FLAG_OPEN;
162 	else {
163 		error = EBUSY;
164 		cam_periph_release(periph);
165 	}
166 
167 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
168 	    ("ptopen: dev=%s\n", devtoname(dev)));
169 
170 	cam_periph_unlock(periph);
171 	return (error);
172 }
173 
174 static int
175 ptclose(struct dev_close_args *ap)
176 {
177 	cdev_t dev = ap->a_head.a_dev;
178 	struct	cam_periph *periph;
179 	struct	pt_softc *softc;
180 	int	unit;
181 
182 	unit = minor(dev);
183 	periph = cam_extend_get(ptperiphs, unit);
184 	if (periph == NULL)
185 		return (ENXIO);
186 
187 	softc = (struct pt_softc *)periph->softc;
188 
189 	cam_periph_lock(periph);
190 
191 	softc->flags &= ~PT_FLAG_OPEN;
192 	cam_periph_unlock(periph);
193 	cam_periph_release(periph);
194 	return (0);
195 }
196 
197 /*
198  * Actually translate the requested transfer into one the physical driver
199  * can understand.  The transfer is described by a buf and will include
200  * only one physical transfer.
201  */
202 static int
203 ptstrategy(struct dev_strategy_args *ap)
204 {
205 	cdev_t dev = ap->a_head.a_dev;
206 	struct bio *bio = ap->a_bio;
207 	struct buf *bp = bio->bio_buf;
208 	struct cam_periph *periph;
209 	struct pt_softc *softc;
210 	u_int  unit;
211 
212 	unit = minor(dev);
213 	periph = cam_extend_get(ptperiphs, unit);
214 	if (periph == NULL) {
215 		bp->b_error = ENXIO;
216 		goto bad;
217 	}
218 	cam_periph_lock(periph);
219 	softc = (struct pt_softc *)periph->softc;
220 
221 	/*
222 	 * If the device has been made invalid, error out
223 	 */
224 	if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
225 		cam_periph_unlock(periph);
226 		bp->b_error = ENXIO;
227 		goto bad;
228 	}
229 
230 	/*
231 	 * Place it in the queue of disk activities for this disk
232 	 */
233 	bioq_insert_tail(&softc->bio_queue, bio);
234 
235 	/*
236 	 * Schedule ourselves for performing the work.
237 	 */
238 	xpt_schedule(periph, /* XXX priority */1);
239 	cam_periph_unlock(periph);
240 
241 	return(0);
242 bad:
243 	bp->b_flags |= B_ERROR;
244 
245 	/*
246 	 * Correctly set the buf to indicate a completed xfer
247 	 */
248 	bp->b_resid = bp->b_bcount;
249 	biodone(bio);
250 	return(0);
251 }
252 
253 static void
254 ptinit(void)
255 {
256 	cam_status status;
257 
258 	/*
259 	 * Create our extend array for storing the devices we attach to.
260 	 */
261 	ptperiphs = cam_extend_new();
262 	if (ptperiphs == NULL) {
263 		kprintf("pt: Failed to alloc extend array!\n");
264 		return;
265 	}
266 
267 	/*
268 	 * Install a global async callback.  This callback will
269 	 * receive async callbacks like "new device found".
270 	 */
271 	status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL);
272 
273 	if (status != CAM_REQ_CMP) {
274 		kprintf("pt: Failed to attach master async callback "
275 		       "due to status 0x%x!\n", status);
276 	}
277 }
278 
279 static cam_status
280 ptctor(struct cam_periph *periph, void *arg)
281 {
282 	struct pt_softc *softc;
283 	struct ccb_getdev *cgd;
284 
285 	cgd = (struct ccb_getdev *)arg;
286 	if (periph == NULL) {
287 		kprintf("ptregister: periph was NULL!!\n");
288 		return(CAM_REQ_CMP_ERR);
289 	}
290 
291 	if (cgd == NULL) {
292 		kprintf("ptregister: no getdev CCB, can't register device\n");
293 		return(CAM_REQ_CMP_ERR);
294 	}
295 
296 	softc = kmalloc(sizeof(*softc), M_DEVBUF, M_INTWAIT | M_ZERO);
297 	LIST_INIT(&softc->pending_ccbs);
298 	softc->state = PT_STATE_NORMAL;
299 	bioq_init(&softc->bio_queue);
300 
301 	softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
302 
303 	periph->softc = softc;
304 
305 	cam_periph_unlock(periph);
306 	cam_extend_set(ptperiphs, periph->unit_number, periph);
307 
308 	devstat_add_entry(&softc->device_stats, "pt",
309 			  periph->unit_number, 0,
310 			  DEVSTAT_NO_BLOCKSIZE,
311 			  SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
312 			  DEVSTAT_PRIORITY_OTHER);
313 
314 	make_dev(&pt_ops, periph->unit_number, UID_ROOT,
315 		  GID_OPERATOR, 0600, "%s%d", periph->periph_name,
316 		  periph->unit_number);
317 	cam_periph_lock(periph);
318 	/*
319 	 * Add async callbacks for bus reset and
320 	 * bus device reset calls.  I don't bother
321 	 * checking if this fails as, in most cases,
322 	 * the system will function just fine without
323 	 * them and the only alternative would be to
324 	 * not attach the device on failure.
325 	 */
326 	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
327 			   ptasync, periph, periph->path);
328 
329 	/* Tell the user we've attached to the device */
330 	xpt_announce_periph(periph, NULL);
331 
332 	return(CAM_REQ_CMP);
333 }
334 
335 static void
336 ptoninvalidate(struct cam_periph *periph)
337 {
338 	struct pt_softc *softc;
339 	struct bio *q_bio;
340 	struct buf *q_bp;
341 
342 	softc = (struct pt_softc *)periph->softc;
343 
344 	/*
345 	 * De-register any async callbacks.
346 	 */
347 	xpt_register_async(0, ptasync, periph, periph->path);
348 
349 	softc->flags |= PT_FLAG_DEVICE_INVALID;
350 
351 	/*
352 	 * Return all queued I/O with ENXIO.
353 	 * XXX Handle any transactions queued to the card
354 	 *     with XPT_ABORT_CCB.
355 	 */
356 	while ((q_bio = bioq_first(&softc->bio_queue)) != NULL){
357 		bioq_remove(&softc->bio_queue, q_bio);
358 		q_bp = q_bio->bio_buf;
359 		q_bp->b_resid = q_bp->b_bcount;
360 		q_bp->b_error = ENXIO;
361 		q_bp->b_flags |= B_ERROR;
362 		biodone(q_bio);
363 	}
364 
365 	xpt_print(periph->path, "lost device\n");
366 }
367 
368 static void
369 ptdtor(struct cam_periph *periph)
370 {
371 	struct pt_softc *softc;
372 
373 	softc = (struct pt_softc *)periph->softc;
374 
375 	devstat_remove_entry(&softc->device_stats);
376 
377 	cam_extend_release(ptperiphs, periph->unit_number);
378 	xpt_print(periph->path, "removing device entry\n");
379 	dev_ops_remove_minor(&pt_ops, periph->unit_number);
380 	kfree(softc, M_DEVBUF);
381 }
382 
383 static void
384 ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
385 {
386 	struct cam_periph *periph;
387 
388 	periph = (struct cam_periph *)callback_arg;
389 	switch (code) {
390 	case AC_FOUND_DEVICE:
391 	{
392 		struct ccb_getdev *cgd;
393 		cam_status status;
394 
395 		cgd = (struct ccb_getdev *)arg;
396 		if (cgd == NULL)
397 			break;
398 
399 		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
400 			break;
401 
402 		/*
403 		 * Allocate a peripheral instance for
404 		 * this device and start the probe
405 		 * process.
406 		 */
407 		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
408 					  ptstart, "pt", CAM_PERIPH_BIO,
409 					  cgd->ccb_h.path, ptasync,
410 					  AC_FOUND_DEVICE, cgd);
411 
412 		if (status != CAM_REQ_CMP
413 		 && status != CAM_REQ_INPROG)
414 			kprintf("ptasync: Unable to attach to new device "
415 				"due to status 0x%x\n", status);
416 		break;
417 	}
418 	case AC_SENT_BDR:
419 	case AC_BUS_RESET:
420 	{
421 		struct pt_softc *softc;
422 		struct ccb_hdr *ccbh;
423 
424 		softc = (struct pt_softc *)periph->softc;
425 		/*
426 		 * Don't fail on the expected unit attention
427 		 * that will occur.
428 		 */
429 		softc->flags |= PT_FLAG_RETRY_UA;
430 		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
431 			ccbh->ccb_state |= PT_CCB_RETRY_UA;
432 		/* FALLTHROUGH */
433 	}
434 	default:
435 		cam_periph_async(periph, code, path, arg);
436 		break;
437 	}
438 }
439 
440 static void
441 ptstart(struct cam_periph *periph, union ccb *start_ccb)
442 {
443 	struct pt_softc *softc;
444 	struct buf *bp;
445 	struct bio *bio;
446 
447 	softc = (struct pt_softc *)periph->softc;
448 
449 	/*
450 	 * See if there is a buf with work for us to do..
451 	 */
452 	bio = bioq_first(&softc->bio_queue);
453 	if (periph->immediate_priority <= periph->pinfo.priority) {
454 		CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
455 				("queuing for immediate ccb\n"));
456 		start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
457 		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
458 				  periph_links.sle);
459 		periph->immediate_priority = CAM_PRIORITY_NONE;
460 		wakeup(&periph->ccb_list);
461 	} else if (bio == NULL) {
462 		xpt_release_ccb(start_ccb);
463 	} else {
464 		bioq_remove(&softc->bio_queue, bio);
465 		bp = bio->bio_buf;
466 
467 		devstat_start_transaction(&softc->device_stats);
468 
469 		scsi_send_receive(&start_ccb->csio,
470 				  /*retries*/4,
471 				  ptdone,
472 				  MSG_SIMPLE_Q_TAG,
473 				  (bp->b_cmd == BUF_CMD_READ),
474 				  /*byte2*/0,
475 				  bp->b_bcount,
476 				  bp->b_data,
477 				  /*sense_len*/SSD_FULL_SIZE,
478 				  /*timeout*/softc->io_timeout);
479 
480 		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
481 
482 		/*
483 		 * Block out any asyncronous callbacks
484 		 * while we touch the pending ccb list.
485 		 */
486 		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
487 				 periph_links.le);
488 
489 		start_ccb->ccb_h.ccb_bio = bio;
490 		bio = bioq_first(&softc->bio_queue);
491 
492 		xpt_action(start_ccb);
493 
494 		if (bio != NULL) {
495 			/* Have more work to do, so ensure we stay scheduled */
496 			xpt_schedule(periph, /* XXX priority */1);
497 		}
498 	}
499 }
500 
501 static void
502 ptdone(struct cam_periph *periph, union ccb *done_ccb)
503 {
504 	struct pt_softc *softc;
505 	struct ccb_scsiio *csio;
506 
507 	softc = (struct pt_softc *)periph->softc;
508 	csio = &done_ccb->csio;
509 	switch (csio->ccb_h.ccb_state) {
510 	case PT_CCB_BUFFER_IO:
511 	case PT_CCB_BUFFER_IO_UA:
512 	{
513 		struct buf *bp;
514 		struct bio *bio;
515 
516 		bio = (struct bio *)done_ccb->ccb_h.ccb_bio;
517 		bp = bio->bio_buf;
518 
519 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
520 			int error;
521 			int sf;
522 
523 			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
524 				sf = SF_RETRY_UA;
525 			else
526 				sf = 0;
527 
528 			error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
529 			if (error == ERESTART) {
530 				/*
531 				 * A retry was scheuled, so
532 				 * just return.
533 				 */
534 				return;
535 			}
536 			if (error != 0) {
537 				struct buf *q_bp;
538 				struct bio *q_bio;
539 
540 				if (error == ENXIO) {
541 					/*
542 					 * Catastrophic error.  Mark our device
543 					 * as invalid.
544 					 */
545 					xpt_print(periph->path,
546 					    "Invalidating device\n");
547 					softc->flags |= PT_FLAG_DEVICE_INVALID;
548 				}
549 
550 				/*
551 				 * return all queued I/O with EIO, so that
552 				 * the client can retry these I/Os in the
553 				 * proper order should it attempt to recover.
554 				 */
555 				while ((q_bio = bioq_first(&softc->bio_queue))
556 					!= NULL) {
557 					bioq_remove(&softc->bio_queue, q_bio);
558 					q_bp = q_bio->bio_buf;
559 					q_bp->b_resid = q_bp->b_bcount;
560 					q_bp->b_error = EIO;
561 					q_bp->b_flags |= B_ERROR;
562 					biodone(q_bio);
563 				}
564 				bp->b_error = error;
565 				bp->b_resid = bp->b_bcount;
566 				bp->b_flags |= B_ERROR;
567 			} else {
568 				bp->b_resid = csio->resid;
569 				bp->b_error = 0;
570 				if (bp->b_resid != 0) {
571 					/* Short transfer ??? */
572 					bp->b_flags |= B_ERROR;
573 				}
574 			}
575 			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
576 				cam_release_devq(done_ccb->ccb_h.path,
577 						 /*relsim_flags*/0,
578 						 /*reduction*/0,
579 						 /*timeout*/0,
580 						 /*getcount_only*/0);
581 		} else {
582 			bp->b_resid = csio->resid;
583 			if (bp->b_resid != 0)
584 				bp->b_flags |= B_ERROR;
585 		}
586 
587 		/*
588 		 * Block out any asyncronous callbacks
589 		 * while we touch the pending ccb list.
590 		 */
591 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
592 
593 		devstat_end_transaction_buf(&softc->device_stats, bp);
594 		biodone(bio);
595 		break;
596 	}
597 	case PT_CCB_WAITING:
598 		/* Caller will release the CCB */
599 		wakeup(&done_ccb->ccb_h.cbfcnp);
600 		return;
601 	}
602 	xpt_release_ccb(done_ccb);
603 }
604 
605 static int
606 pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
607 {
608 	struct pt_softc	  *softc;
609 	struct cam_periph *periph;
610 
611 	periph = xpt_path_periph(ccb->ccb_h.path);
612 	softc = (struct pt_softc *)periph->softc;
613 
614 	return(cam_periph_error(ccb, cam_flags, sense_flags,
615 				&softc->saved_ccb));
616 }
617 
618 static int
619 ptioctl(struct dev_ioctl_args *ap)
620 {
621 	cdev_t dev = ap->a_head.a_dev;
622 	caddr_t addr = ap->a_data;
623 	struct cam_periph *periph;
624 	struct pt_softc *softc;
625 	int unit;
626 	int error = 0;
627 
628 	unit = minor(dev);
629 	periph = cam_extend_get(ptperiphs, unit);
630 
631 	if (periph == NULL)
632 		return(ENXIO);
633 
634 	softc = (struct pt_softc *)periph->softc;
635 
636 	cam_periph_lock(periph);
637 
638 	switch(ap->a_cmd) {
639 	case PTIOCGETTIMEOUT:
640 		if (softc->io_timeout >= 1000)
641 			*(int *)addr = softc->io_timeout / 1000;
642 		else
643 			*(int *)addr = 0;
644 		break;
645 	case PTIOCSETTIMEOUT:
646 		if (*(int *)addr < 1) {
647 			error = EINVAL;
648 			break;
649 		}
650 
651 		softc->io_timeout = *(int *)addr * 1000;
652 
653 		break;
654 	default:
655 		error = cam_periph_ioctl(periph, ap->a_cmd, addr, pterror);
656 		break;
657 	}
658 
659 	cam_periph_unlock(periph);
660 
661 	return(error);
662 }
663 
664 void
665 scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
666 		  void (*cbfcnp)(struct cam_periph *, union ccb *),
667 		  u_int tag_action, int readop, u_int byte2,
668 		  u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
669 		  u_int32_t timeout)
670 {
671 	struct scsi_send_receive *scsi_cmd;
672 
673 	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
674 	scsi_cmd->opcode = readop ? RECEIVE : SEND;
675 	scsi_cmd->byte2 = byte2;
676 	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
677 	scsi_cmd->control = 0;
678 
679 	cam_fill_csio(csio,
680 		      retries,
681 		      cbfcnp,
682 		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
683 		      tag_action,
684 		      data_ptr,
685 		      xfer_len,
686 		      sense_len,
687 		      sizeof(*scsi_cmd),
688 		      timeout);
689 }
690