]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/cam/scsi/scsi_pt.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / sys / cam / scsi / scsi_pt.c
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/queue.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/types.h>
37 #include <sys/bio.h>
38 #include <sys/devicestat.h>
39 #include <sys/malloc.h>
40 #include <sys/conf.h>
41 #include <sys/ptio.h>
42
43 #include <cam/cam.h>
44 #include <cam/cam_ccb.h>
45 #include <cam/cam_periph.h>
46 #include <cam/cam_xpt_periph.h>
47 #include <cam/cam_debug.h>
48
49 #include <cam/scsi/scsi_all.h>
50 #include <cam/scsi/scsi_message.h>
51 #include <cam/scsi/scsi_pt.h>
52
53 #include "opt_pt.h"
54
55 typedef enum {
56         PT_STATE_PROBE,
57         PT_STATE_NORMAL
58 } pt_state;
59
60 typedef enum {
61         PT_FLAG_NONE            = 0x00,
62         PT_FLAG_OPEN            = 0x01,
63         PT_FLAG_DEVICE_INVALID  = 0x02,
64         PT_FLAG_RETRY_UA        = 0x04
65 } pt_flags;
66
67 typedef enum {
68         PT_CCB_BUFFER_IO        = 0x01,
69         PT_CCB_WAITING          = 0x02,
70         PT_CCB_RETRY_UA         = 0x04,
71         PT_CCB_BUFFER_IO_UA     = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
72 } pt_ccb_state;
73
74 /* Offsets into our private area for storing information */
75 #define ccb_state       ppriv_field0
76 #define ccb_bp          ppriv_ptr1
77
78 struct pt_softc {
79         struct   bio_queue_head bio_queue;
80         struct   devstat *device_stats;
81         LIST_HEAD(, ccb_hdr) pending_ccbs;
82         pt_state state;
83         pt_flags flags; 
84         union    ccb saved_ccb;
85         int      io_timeout;
86         struct cdev *dev;
87 };
88
89 static  d_open_t        ptopen;
90 static  d_close_t       ptclose;
91 static  d_strategy_t    ptstrategy;
92 static  periph_init_t   ptinit;
93 static  void            ptasync(void *callback_arg, u_int32_t code,
94                                 struct cam_path *path, void *arg);
95 static  periph_ctor_t   ptctor;
96 static  periph_oninv_t  ptoninvalidate;
97 static  periph_dtor_t   ptdtor;
98 static  periph_start_t  ptstart;
99 static  void            ptdone(struct cam_periph *periph,
100                                union ccb *done_ccb);
101 static  d_ioctl_t       ptioctl;
102 static  int             pterror(union ccb *ccb, u_int32_t cam_flags,
103                                 u_int32_t sense_flags);
104
105 void    scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
106                           void (*cbfcnp)(struct cam_periph *, union ccb *),
107                           u_int tag_action, int readop, u_int byte2,
108                           u_int32_t xfer_len, u_int8_t *data_ptr,
109                           u_int8_t sense_len, u_int32_t timeout);
110
111 static struct periph_driver ptdriver =
112 {
113         ptinit, "pt",
114         TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
115 };
116
117 PERIPHDRIVER_DECLARE(pt, ptdriver);
118
119
120 static struct cdevsw pt_cdevsw = {
121         .d_version =    D_VERSION,
122         .d_flags =      D_NEEDGIANT,
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         .d_name =       "pt",
130 };
131
132 #ifndef SCSI_PT_DEFAULT_TIMEOUT
133 #define SCSI_PT_DEFAULT_TIMEOUT         60
134 #endif
135
136 static int
137 ptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
138 {
139         struct cam_periph *periph;
140         struct pt_softc *softc;
141         int unit;
142         int error;
143         int s;
144
145         unit = minor(dev);
146         periph = (struct cam_periph *)dev->si_drv1;
147         if (periph == NULL)
148                 return (ENXIO); 
149
150         softc = (struct pt_softc *)periph->softc;
151
152         s = splsoftcam();
153         if (softc->flags & PT_FLAG_DEVICE_INVALID) {
154                 splx(s);
155                 return(ENXIO);
156         }
157
158         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
159             ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit));
160
161         if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
162                 splx(s);
163                 return (error); /* error code from tsleep */
164         }
165
166         splx(s);
167
168         if ((softc->flags & PT_FLAG_OPEN) == 0) {
169                 if (cam_periph_acquire(periph) != CAM_REQ_CMP)
170                         error = ENXIO;
171                 else
172                         softc->flags |= PT_FLAG_OPEN;
173         } else
174                 error = EBUSY;
175
176         cam_periph_unlock(periph);
177         return (error);
178 }
179
180 static int
181 ptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
182 {
183         struct  cam_periph *periph;
184         struct  pt_softc *softc;
185         int     error;
186
187         periph = (struct cam_periph *)dev->si_drv1;
188         if (periph == NULL)
189                 return (ENXIO); 
190
191         softc = (struct pt_softc *)periph->softc;
192
193         if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
194                 return (error); /* error code from tsleep */
195
196         softc->flags &= ~PT_FLAG_OPEN;
197         cam_periph_unlock(periph);
198         cam_periph_release(periph);
199         return (0);
200 }
201
202 /*
203  * Actually translate the requested transfer into one the physical driver
204  * can understand.  The transfer is described by a buf and will include
205  * only one physical transfer.
206  */
207 static void
208 ptstrategy(struct bio *bp)
209 {
210         struct cam_periph *periph;
211         struct pt_softc *softc;
212         int    s;
213         
214         periph = (struct cam_periph *)bp->bio_dev->si_drv1;
215         bp->bio_resid = bp->bio_bcount;
216         if (periph == NULL) {
217                 biofinish(bp, NULL, ENXIO);
218                 return;
219         }
220         softc = (struct pt_softc *)periph->softc;
221
222         /*
223          * Mask interrupts so that the pack cannot be invalidated until
224          * after we are in the queue.  Otherwise, we might not properly
225          * clean up one of the buffers.
226          */
227         s = splbio();
228         
229         /*
230          * If the device has been made invalid, error out
231          */
232         if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
233                 splx(s);
234                 biofinish(bp, NULL, ENXIO);
235                 return;
236         }
237         
238         /*
239          * Place it in the queue of disk activities for this disk
240          */
241         bioq_insert_tail(&softc->bio_queue, bp);
242
243         splx(s);
244         
245         /*
246          * Schedule ourselves for performing the work.
247          */
248         xpt_schedule(periph, /* XXX priority */1);
249
250         return;
251 }
252
253 static void
254 ptinit(void)
255 {
256         cam_status status;
257         struct cam_path *path;
258
259         /*
260          * Install a global async callback.  This callback will
261          * receive async callbacks like "new device found".
262          */
263         status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
264                                  CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
265
266         if (status == CAM_REQ_CMP) {
267                 struct ccb_setasync csa;
268
269                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
270                 csa.ccb_h.func_code = XPT_SASYNC_CB;
271                 csa.event_enable = AC_FOUND_DEVICE;
272                 csa.callback = ptasync;
273                 csa.callback_arg = NULL;
274                 xpt_action((union ccb *)&csa);
275                 status = csa.ccb_h.status;
276                 xpt_free_path(path);
277         }
278
279         if (status != CAM_REQ_CMP) {
280                 printf("pt: Failed to attach master async callback "
281                        "due to status 0x%x!\n", status);
282         }
283 }
284
285 static cam_status
286 ptctor(struct cam_periph *periph, void *arg)
287 {
288         struct pt_softc *softc;
289         struct ccb_setasync csa;
290         struct ccb_getdev *cgd;
291
292         cgd = (struct ccb_getdev *)arg;
293         if (periph == NULL) {
294                 printf("ptregister: periph was NULL!!\n");
295                 return(CAM_REQ_CMP_ERR);
296         }
297
298         if (cgd == NULL) {
299                 printf("ptregister: no getdev CCB, can't register device\n");
300                 return(CAM_REQ_CMP_ERR);
301         }
302
303         softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
304
305         if (softc == NULL) {
306                 printf("daregister: Unable to probe new device. "
307                        "Unable to allocate softc\n");                           
308                 return(CAM_REQ_CMP_ERR);
309         }
310
311         bzero(softc, sizeof(*softc));
312         LIST_INIT(&softc->pending_ccbs);
313         softc->state = PT_STATE_NORMAL;
314         bioq_init(&softc->bio_queue);
315
316         softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
317
318         periph->softc = softc;
319         
320         softc->device_stats = devstat_new_entry("pt",
321                           periph->unit_number, 0,
322                           DEVSTAT_NO_BLOCKSIZE,
323                           SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
324                           DEVSTAT_PRIORITY_OTHER);
325
326         softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT,
327                               GID_OPERATOR, 0600, "%s%d", periph->periph_name,
328                               periph->unit_number);
329         softc->dev->si_drv1 = periph;
330
331         /*
332          * Add async callbacks for bus reset and
333          * bus device reset calls.  I don't bother
334          * checking if this fails as, in most cases,
335          * the system will function just fine without
336          * them and the only alternative would be to
337          * not attach the device on failure.
338          */
339         xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5);
340         csa.ccb_h.func_code = XPT_SASYNC_CB;
341         csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
342         csa.callback = ptasync;
343         csa.callback_arg = periph;
344         xpt_action((union ccb *)&csa);
345
346         /* Tell the user we've attached to the device */
347         xpt_announce_periph(periph, NULL);
348
349         return(CAM_REQ_CMP);
350 }
351
352 static void
353 ptoninvalidate(struct cam_periph *periph)
354 {
355         int s;
356         struct pt_softc *softc;
357         struct ccb_setasync csa;
358
359         softc = (struct pt_softc *)periph->softc;
360
361         /*
362          * De-register any async callbacks.
363          */
364         xpt_setup_ccb(&csa.ccb_h, periph->path,
365                       /* priority */ 5);
366         csa.ccb_h.func_code = XPT_SASYNC_CB;
367         csa.event_enable = 0;
368         csa.callback = ptasync;
369         csa.callback_arg = periph;
370         xpt_action((union ccb *)&csa);
371
372         softc->flags |= PT_FLAG_DEVICE_INVALID;
373
374         /*
375          * Although the oninvalidate() routines are always called at
376          * splsoftcam, we need to be at splbio() here to keep the buffer
377          * queue from being modified while we traverse it.
378          */
379         s = splbio();
380
381         /*
382          * Return all queued I/O with ENXIO.
383          * XXX Handle any transactions queued to the card
384          *     with XPT_ABORT_CCB.
385          */
386         bioq_flush(&softc->bio_queue, NULL, ENXIO);
387
388         splx(s);
389
390         xpt_print_path(periph->path);
391         printf("lost device\n");
392 }
393
394 static void
395 ptdtor(struct cam_periph *periph)
396 {
397         struct pt_softc *softc;
398
399         softc = (struct pt_softc *)periph->softc;
400
401         devstat_remove_entry(softc->device_stats);
402
403         destroy_dev(softc->dev);
404
405         xpt_print_path(periph->path);
406         printf("removing device entry\n");
407         free(softc, M_DEVBUF);
408 }
409
410 static void
411 ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
412 {
413         struct cam_periph *periph;
414
415         periph = (struct cam_periph *)callback_arg;
416         switch (code) {
417         case AC_FOUND_DEVICE:
418         {
419                 struct ccb_getdev *cgd;
420                 cam_status status;
421  
422                 cgd = (struct ccb_getdev *)arg;
423                 if (cgd == NULL)
424                         break;
425
426                 if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
427                         break;
428
429                 /*
430                  * Allocate a peripheral instance for
431                  * this device and start the probe
432                  * process.
433                  */
434                 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
435                                           ptstart, "pt", CAM_PERIPH_BIO,
436                                           cgd->ccb_h.path, ptasync,
437                                           AC_FOUND_DEVICE, cgd);
438
439                 if (status != CAM_REQ_CMP
440                  && status != CAM_REQ_INPROG)
441                         printf("ptasync: Unable to attach to new device "
442                                 "due to status 0x%x\n", status);
443                 break;
444         }
445         case AC_SENT_BDR:
446         case AC_BUS_RESET:
447         {
448                 struct pt_softc *softc;
449                 struct ccb_hdr *ccbh;
450                 int s;
451
452                 softc = (struct pt_softc *)periph->softc;
453                 s = splsoftcam();
454                 /*
455                  * Don't fail on the expected unit attention
456                  * that will occur.
457                  */
458                 softc->flags |= PT_FLAG_RETRY_UA;
459                 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
460                         ccbh->ccb_state |= PT_CCB_RETRY_UA;
461                 splx(s);
462         }
463         /* FALLTHROUGH */
464         default:
465                 cam_periph_async(periph, code, path, arg);
466                 break;
467         }
468 }
469
470 static void
471 ptstart(struct cam_periph *periph, union ccb *start_ccb)
472 {
473         struct pt_softc *softc;
474         struct bio *bp;
475         int s;
476
477         softc = (struct pt_softc *)periph->softc;
478
479         /*
480          * See if there is a buf with work for us to do..
481          */
482         s = splbio();
483         bp = bioq_first(&softc->bio_queue);
484         if (periph->immediate_priority <= periph->pinfo.priority) {
485                 CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
486                                 ("queuing for immediate ccb\n"));
487                 start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
488                 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
489                                   periph_links.sle);
490                 periph->immediate_priority = CAM_PRIORITY_NONE;
491                 splx(s);
492                 wakeup(&periph->ccb_list);
493         } else if (bp == NULL) {
494                 splx(s);
495                 xpt_release_ccb(start_ccb);
496         } else {
497                 int oldspl;
498
499                 bioq_remove(&softc->bio_queue, bp);
500
501                 devstat_start_transaction_bio(softc->device_stats, bp);
502
503                 scsi_send_receive(&start_ccb->csio,
504                                   /*retries*/4,
505                                   ptdone,
506                                   MSG_SIMPLE_Q_TAG,
507                                   bp->bio_cmd == BIO_READ,
508                                   /*byte2*/0,
509                                   bp->bio_bcount,
510                                   bp->bio_data,
511                                   /*sense_len*/SSD_FULL_SIZE,
512                                   /*timeout*/softc->io_timeout);
513
514                 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
515
516                 /*
517                  * Block out any asyncronous callbacks
518                  * while we touch the pending ccb list.
519                  */
520                 oldspl = splcam();
521                 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
522                                  periph_links.le);
523                 splx(oldspl);
524
525                 start_ccb->ccb_h.ccb_bp = bp;
526                 bp = bioq_first(&softc->bio_queue);
527                 splx(s);
528
529                 xpt_action(start_ccb);
530                 
531                 if (bp != NULL) {
532                         /* Have more work to do, so ensure we stay scheduled */
533                         xpt_schedule(periph, /* XXX priority */1);
534                 }
535         }
536 }
537
538 static void
539 ptdone(struct cam_periph *periph, union ccb *done_ccb)
540 {
541         struct pt_softc *softc;
542         struct ccb_scsiio *csio;
543
544         softc = (struct pt_softc *)periph->softc;
545         csio = &done_ccb->csio;
546         switch (csio->ccb_h.ccb_state) {
547         case PT_CCB_BUFFER_IO:
548         case PT_CCB_BUFFER_IO_UA:
549         {
550                 struct bio *bp;
551                 int    oldspl;
552
553                 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
554                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
555                         int error;
556                         int s;
557                         int sf;
558                         
559                         if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
560                                 sf = SF_RETRY_UA;
561                         else
562                                 sf = 0;
563
564                         error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
565                         if (error == ERESTART) {
566                                 /*
567                                  * A retry was scheuled, so
568                                  * just return.
569                                  */
570                                 return;
571                         }
572                         if (error != 0) {
573                                 s = splbio();
574
575                                 if (error == ENXIO) {
576                                         /*
577                                          * Catastrophic error.  Mark our device
578                                          * as invalid.
579                                          */
580                                         xpt_print_path(periph->path);
581                                         printf("Invalidating device\n");
582                                         softc->flags |= PT_FLAG_DEVICE_INVALID;
583                                 }
584
585                                 /*
586                                  * return all queued I/O with EIO, so that
587                                  * the client can retry these I/Os in the
588                                  * proper order should it attempt to recover.
589                                  */
590                                 bioq_flush(&softc->bio_queue, NULL, EIO);
591                                 splx(s);
592                                 bp->bio_error = error;
593                                 bp->bio_resid = bp->bio_bcount;
594                                 bp->bio_flags |= BIO_ERROR;
595                         } else {
596                                 bp->bio_resid = csio->resid;
597                                 bp->bio_error = 0;
598                                 if (bp->bio_resid != 0) {
599                                         /* Short transfer ??? */
600                                         bp->bio_flags |= BIO_ERROR;
601                                 }
602                         }
603                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
604                                 cam_release_devq(done_ccb->ccb_h.path,
605                                                  /*relsim_flags*/0,
606                                                  /*reduction*/0,
607                                                  /*timeout*/0,
608                                                  /*getcount_only*/0);
609                 } else {
610                         bp->bio_resid = csio->resid;
611                         if (bp->bio_resid != 0)
612                                 bp->bio_flags |= BIO_ERROR;
613                 }
614
615                 /*
616                  * Block out any asyncronous callbacks
617                  * while we touch the pending ccb list.
618                  */
619                 oldspl = splcam();
620                 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
621                 splx(oldspl);
622
623                 biofinish(bp, softc->device_stats, 0);
624                 break;
625         }
626         case PT_CCB_WAITING:
627                 /* Caller will release the CCB */
628                 wakeup(&done_ccb->ccb_h.cbfcnp);
629                 return;
630         }
631         xpt_release_ccb(done_ccb);
632 }
633
634 static int
635 pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
636 {
637         struct pt_softc   *softc;
638         struct cam_periph *periph;
639
640         periph = xpt_path_periph(ccb->ccb_h.path);
641         softc = (struct pt_softc *)periph->softc;
642
643         return(cam_periph_error(ccb, cam_flags, sense_flags,
644                                 &softc->saved_ccb));
645 }
646
647 static int
648 ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
649 {
650         struct cam_periph *periph;
651         struct pt_softc *softc;
652         int error;
653
654         periph = (struct cam_periph *)dev->si_drv1;
655         if (periph == NULL)
656                 return(ENXIO);
657
658         softc = (struct pt_softc *)periph->softc;
659
660         if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) {
661                 return (error); /* error code from tsleep */
662         }       
663
664         switch(cmd) {
665         case PTIOCGETTIMEOUT:
666                 if (softc->io_timeout >= 1000)
667                         *(int *)addr = softc->io_timeout / 1000;
668                 else
669                         *(int *)addr = 0;
670                 break;
671         case PTIOCSETTIMEOUT:
672         {
673                 int s;
674
675                 if (*(int *)addr < 1) {
676                         error = EINVAL;
677                         break;
678                 }
679
680                 s = splsoftcam();
681                 softc->io_timeout = *(int *)addr * 1000;
682                 splx(s);
683
684                 break;
685         }
686         default:
687                 error = cam_periph_ioctl(periph, cmd, addr, pterror);
688                 break;
689         }
690
691         cam_periph_unlock(periph);
692
693         return(error);
694 }
695
696 void
697 scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
698                   void (*cbfcnp)(struct cam_periph *, union ccb *),
699                   u_int tag_action, int readop, u_int byte2,
700                   u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
701                   u_int32_t timeout)
702 {
703         struct scsi_send_receive *scsi_cmd;
704
705         scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
706         scsi_cmd->opcode = readop ? RECEIVE : SEND;
707         scsi_cmd->byte2 = byte2;
708         scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
709         scsi_cmd->control = 0;
710
711         cam_fill_csio(csio,
712                       retries,
713                       cbfcnp,
714                       /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
715                       tag_action,
716                       data_ptr,
717                       xfer_len,
718                       sense_len,
719                       sizeof(*scsi_cmd),
720                       timeout);
721 }