2 * Implementation of SCSI Processor Target Peripheral driver for CAM.
4 * Copyright (c) 1998 Justin T. Gibbs.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
28 * $FreeBSD: src/sys/cam/scsi/scsi_pt.c,v 1.17 2000/01/17 06:27:37 mjacob Exp $
29 * $DragonFly: src/sys/bus/cam/scsi/scsi_pt.c,v 1.23 2008/05/18 20:30:20 pavalos Exp $
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>
38 #include <sys/devicestat.h>
39 #include <sys/malloc.h>
43 #include <sys/thread2.h>
46 #include "../cam_ccb.h"
47 #include "../cam_extend.h"
48 #include "../cam_periph.h"
49 #include "../cam_xpt_periph.h"
50 #include "../cam_debug.h"
53 #include "scsi_message.h"
66 PT_FLAG_DEVICE_INVALID
= 0x02,
67 PT_FLAG_RETRY_UA
= 0x04
71 PT_CCB_BUFFER_IO
= 0x01,
72 PT_CCB_WAITING
= 0x02,
73 PT_CCB_RETRY_UA
= 0x04,
74 PT_CCB_BUFFER_IO_UA
= PT_CCB_BUFFER_IO
|PT_CCB_RETRY_UA
77 /* Offsets into our private area for storing information */
78 #define ccb_state ppriv_field0
79 #define ccb_bio ppriv_ptr1
82 struct bio_queue_head bio_queue
;
83 struct devstat device_stats
;
84 LIST_HEAD(, ccb_hdr
) pending_ccbs
;
92 static d_open_t ptopen
;
93 static d_close_t ptclose
;
94 static d_strategy_t ptstrategy
;
95 static periph_init_t ptinit
;
96 static void ptasync(void *callback_arg
, u_int32_t code
,
97 struct cam_path
*path
, void *arg
);
98 static periph_ctor_t ptctor
;
99 static periph_oninv_t ptoninvalidate
;
100 static periph_dtor_t ptdtor
;
101 static periph_start_t ptstart
;
102 static void ptdone(struct cam_periph
*periph
,
103 union ccb
*done_ccb
);
104 static d_ioctl_t ptioctl
;
105 static int pterror(union ccb
*ccb
, u_int32_t cam_flags
,
106 u_int32_t sense_flags
);
108 void scsi_send_receive(struct ccb_scsiio
*csio
, u_int32_t retries
,
109 void (*cbfcnp
)(struct cam_periph
*, union ccb
*),
110 u_int tag_action
, int readop
, u_int byte2
,
111 u_int32_t xfer_len
, u_int8_t
*data_ptr
,
112 u_int8_t sense_len
, u_int32_t timeout
);
114 static struct periph_driver ptdriver
=
117 TAILQ_HEAD_INITIALIZER(ptdriver
.units
), /* generation */ 0
120 PERIPHDRIVER_DECLARE(pt
, ptdriver
);
122 #define PT_CDEV_MAJOR 61
124 static struct dev_ops pt_ops
= {
125 { "pt", PT_CDEV_MAJOR
, 0 },
129 .d_write
= physwrite
,
131 .d_strategy
= ptstrategy
,
134 static struct extend_array
*ptperiphs
;
136 #ifndef SCSI_PT_DEFAULT_TIMEOUT
137 #define SCSI_PT_DEFAULT_TIMEOUT 60
141 ptopen(struct dev_open_args
*ap
)
143 cdev_t dev
= ap
->a_head
.a_dev
;
144 struct cam_periph
*periph
;
145 struct pt_softc
*softc
;
150 periph
= cam_extend_get(ptperiphs
, unit
);
151 if (cam_periph_acquire(periph
) != CAM_REQ_CMP
)
154 softc
= (struct pt_softc
*)periph
->softc
;
156 cam_periph_lock(periph
);
157 if (softc
->flags
& PT_FLAG_DEVICE_INVALID
) {
158 cam_periph_unlock(periph
);
159 cam_periph_release(periph
);
163 if ((softc
->flags
& PT_FLAG_OPEN
) == 0)
164 softc
->flags
|= PT_FLAG_OPEN
;
167 cam_periph_release(periph
);
170 CAM_DEBUG(periph
->path
, CAM_DEBUG_TRACE
,
171 ("ptopen: dev=%s\n", devtoname(dev
)));
173 cam_periph_unlock(periph
);
178 ptclose(struct dev_close_args
*ap
)
180 cdev_t dev
= ap
->a_head
.a_dev
;
181 struct cam_periph
*periph
;
182 struct pt_softc
*softc
;
186 periph
= cam_extend_get(ptperiphs
, unit
);
190 softc
= (struct pt_softc
*)periph
->softc
;
192 cam_periph_lock(periph
);
194 softc
->flags
&= ~PT_FLAG_OPEN
;
195 cam_periph_unlock(periph
);
196 cam_periph_release(periph
);
201 * Actually translate the requested transfer into one the physical driver
202 * can understand. The transfer is described by a buf and will include
203 * only one physical transfer.
206 ptstrategy(struct dev_strategy_args
*ap
)
208 cdev_t dev
= ap
->a_head
.a_dev
;
209 struct bio
*bio
= ap
->a_bio
;
210 struct buf
*bp
= bio
->bio_buf
;
211 struct cam_periph
*periph
;
212 struct pt_softc
*softc
;
216 periph
= cam_extend_get(ptperiphs
, unit
);
217 if (periph
== NULL
) {
221 cam_periph_lock(periph
);
222 softc
= (struct pt_softc
*)periph
->softc
;
225 * If the device has been made invalid, error out
227 if ((softc
->flags
& PT_FLAG_DEVICE_INVALID
)) {
228 cam_periph_unlock(periph
);
234 * Place it in the queue of disk activities for this disk
236 bioq_insert_tail(&softc
->bio_queue
, bio
);
239 * Schedule ourselves for performing the work.
241 xpt_schedule(periph
, /* XXX priority */1);
242 cam_periph_unlock(periph
);
246 bp
->b_flags
|= B_ERROR
;
249 * Correctly set the buf to indicate a completed xfer
251 bp
->b_resid
= bp
->b_bcount
;
262 * Create our extend array for storing the devices we attach to.
264 ptperiphs
= cam_extend_new();
265 if (ptperiphs
== NULL
) {
266 kprintf("pt: Failed to alloc extend array!\n");
271 * Install a global async callback. This callback will
272 * receive async callbacks like "new device found".
274 status
= xpt_register_async(AC_FOUND_DEVICE
, ptasync
, NULL
, NULL
);
276 if (status
!= CAM_REQ_CMP
) {
277 kprintf("pt: Failed to attach master async callback "
278 "due to status 0x%x!\n", status
);
283 ptctor(struct cam_periph
*periph
, void *arg
)
285 struct pt_softc
*softc
;
286 struct ccb_getdev
*cgd
;
288 cgd
= (struct ccb_getdev
*)arg
;
289 if (periph
== NULL
) {
290 kprintf("ptregister: periph was NULL!!\n");
291 return(CAM_REQ_CMP_ERR
);
295 kprintf("ptregister: no getdev CCB, can't register device\n");
296 return(CAM_REQ_CMP_ERR
);
299 softc
= kmalloc(sizeof(*softc
), M_DEVBUF
, M_INTWAIT
| M_ZERO
);
300 LIST_INIT(&softc
->pending_ccbs
);
301 softc
->state
= PT_STATE_NORMAL
;
302 bioq_init(&softc
->bio_queue
);
304 softc
->io_timeout
= SCSI_PT_DEFAULT_TIMEOUT
* 1000;
306 periph
->softc
= softc
;
308 cam_periph_unlock(periph
);
309 cam_extend_set(ptperiphs
, periph
->unit_number
, periph
);
311 devstat_add_entry(&softc
->device_stats
, "pt",
312 periph
->unit_number
, 0,
313 DEVSTAT_NO_BLOCKSIZE
,
314 SID_TYPE(&cgd
->inq_data
) | DEVSTAT_TYPE_IF_SCSI
,
315 DEVSTAT_PRIORITY_OTHER
);
317 dev_ops_add(&pt_ops
, -1, periph
->unit_number
);
318 make_dev(&pt_ops
, periph
->unit_number
, UID_ROOT
,
319 GID_OPERATOR
, 0600, "%s%d", periph
->periph_name
,
320 periph
->unit_number
);
321 cam_periph_lock(periph
);
323 * Add async callbacks for bus reset and
324 * bus device reset calls. I don't bother
325 * checking if this fails as, in most cases,
326 * the system will function just fine without
327 * them and the only alternative would be to
328 * not attach the device on failure.
330 xpt_register_async(AC_SENT_BDR
| AC_BUS_RESET
| AC_LOST_DEVICE
,
331 ptasync
, periph
, periph
->path
);
333 /* Tell the user we've attached to the device */
334 xpt_announce_periph(periph
, NULL
);
340 ptoninvalidate(struct cam_periph
*periph
)
342 struct pt_softc
*softc
;
346 softc
= (struct pt_softc
*)periph
->softc
;
349 * De-register any async callbacks.
351 xpt_register_async(0, ptasync
, periph
, periph
->path
);
353 softc
->flags
|= PT_FLAG_DEVICE_INVALID
;
356 * Return all queued I/O with ENXIO.
357 * XXX Handle any transactions queued to the card
358 * with XPT_ABORT_CCB.
360 while ((q_bio
= bioq_first(&softc
->bio_queue
)) != NULL
){
361 bioq_remove(&softc
->bio_queue
, q_bio
);
362 q_bp
= q_bio
->bio_buf
;
363 q_bp
->b_resid
= q_bp
->b_bcount
;
364 q_bp
->b_error
= ENXIO
;
365 q_bp
->b_flags
|= B_ERROR
;
369 xpt_print(periph
->path
, "lost device\n");
373 ptdtor(struct cam_periph
*periph
)
375 struct pt_softc
*softc
;
377 softc
= (struct pt_softc
*)periph
->softc
;
379 devstat_remove_entry(&softc
->device_stats
);
381 cam_extend_release(ptperiphs
, periph
->unit_number
);
382 xpt_print(periph
->path
, "removing device entry\n");
383 dev_ops_remove(&pt_ops
, -1, periph
->unit_number
);
384 kfree(softc
, M_DEVBUF
);
388 ptasync(void *callback_arg
, u_int32_t code
, struct cam_path
*path
, void *arg
)
390 struct cam_periph
*periph
;
392 periph
= (struct cam_periph
*)callback_arg
;
394 case AC_FOUND_DEVICE
:
396 struct ccb_getdev
*cgd
;
399 cgd
= (struct ccb_getdev
*)arg
;
403 if (SID_TYPE(&cgd
->inq_data
) != T_PROCESSOR
)
407 * Allocate a peripheral instance for
408 * this device and start the probe
411 status
= cam_periph_alloc(ptctor
, ptoninvalidate
, ptdtor
,
412 ptstart
, "pt", CAM_PERIPH_BIO
,
413 cgd
->ccb_h
.path
, ptasync
,
414 AC_FOUND_DEVICE
, cgd
);
416 if (status
!= CAM_REQ_CMP
417 && status
!= CAM_REQ_INPROG
)
418 kprintf("ptasync: Unable to attach to new device "
419 "due to status 0x%x\n", status
);
425 struct pt_softc
*softc
;
426 struct ccb_hdr
*ccbh
;
428 softc
= (struct pt_softc
*)periph
->softc
;
430 * Don't fail on the expected unit attention
433 softc
->flags
|= PT_FLAG_RETRY_UA
;
434 LIST_FOREACH(ccbh
, &softc
->pending_ccbs
, periph_links
.le
)
435 ccbh
->ccb_state
|= PT_CCB_RETRY_UA
;
439 cam_periph_async(periph
, code
, path
, arg
);
445 ptstart(struct cam_periph
*periph
, union ccb
*start_ccb
)
447 struct pt_softc
*softc
;
451 softc
= (struct pt_softc
*)periph
->softc
;
454 * See if there is a buf with work for us to do..
456 bio
= bioq_first(&softc
->bio_queue
);
457 if (periph
->immediate_priority
<= periph
->pinfo
.priority
) {
458 CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE
,
459 ("queuing for immediate ccb\n"));
460 start_ccb
->ccb_h
.ccb_state
= PT_CCB_WAITING
;
461 SLIST_INSERT_HEAD(&periph
->ccb_list
, &start_ccb
->ccb_h
,
463 periph
->immediate_priority
= CAM_PRIORITY_NONE
;
464 wakeup(&periph
->ccb_list
);
465 } else if (bio
== NULL
) {
466 xpt_release_ccb(start_ccb
);
468 bioq_remove(&softc
->bio_queue
, bio
);
471 devstat_start_transaction(&softc
->device_stats
);
473 scsi_send_receive(&start_ccb
->csio
,
477 (bp
->b_cmd
== BUF_CMD_READ
),
481 /*sense_len*/SSD_FULL_SIZE
,
482 /*timeout*/softc
->io_timeout
);
484 start_ccb
->ccb_h
.ccb_state
= PT_CCB_BUFFER_IO_UA
;
487 * Block out any asyncronous callbacks
488 * while we touch the pending ccb list.
490 LIST_INSERT_HEAD(&softc
->pending_ccbs
, &start_ccb
->ccb_h
,
493 start_ccb
->ccb_h
.ccb_bio
= bio
;
494 bio
= bioq_first(&softc
->bio_queue
);
496 xpt_action(start_ccb
);
499 /* Have more work to do, so ensure we stay scheduled */
500 xpt_schedule(periph
, /* XXX priority */1);
506 ptdone(struct cam_periph
*periph
, union ccb
*done_ccb
)
508 struct pt_softc
*softc
;
509 struct ccb_scsiio
*csio
;
511 softc
= (struct pt_softc
*)periph
->softc
;
512 csio
= &done_ccb
->csio
;
513 switch (csio
->ccb_h
.ccb_state
) {
514 case PT_CCB_BUFFER_IO
:
515 case PT_CCB_BUFFER_IO_UA
:
520 bio
= (struct bio
*)done_ccb
->ccb_h
.ccb_bio
;
523 if ((done_ccb
->ccb_h
.status
& CAM_STATUS_MASK
) != CAM_REQ_CMP
) {
527 if ((csio
->ccb_h
.ccb_state
& PT_CCB_RETRY_UA
) != 0)
532 error
= pterror(done_ccb
, CAM_RETRY_SELTO
, sf
);
533 if (error
== ERESTART
) {
535 * A retry was scheuled, so
544 if (error
== ENXIO
) {
546 * Catastrophic error. Mark our device
549 xpt_print(periph
->path
,
550 "Invalidating device\n");
551 softc
->flags
|= PT_FLAG_DEVICE_INVALID
;
555 * return all queued I/O with EIO, so that
556 * the client can retry these I/Os in the
557 * proper order should it attempt to recover.
559 while ((q_bio
= bioq_first(&softc
->bio_queue
))
561 bioq_remove(&softc
->bio_queue
, q_bio
);
562 q_bp
= q_bio
->bio_buf
;
563 q_bp
->b_resid
= q_bp
->b_bcount
;
565 q_bp
->b_flags
|= B_ERROR
;
569 bp
->b_resid
= bp
->b_bcount
;
570 bp
->b_flags
|= B_ERROR
;
572 bp
->b_resid
= csio
->resid
;
574 if (bp
->b_resid
!= 0) {
575 /* Short transfer ??? */
576 bp
->b_flags
|= B_ERROR
;
579 if ((done_ccb
->ccb_h
.status
& CAM_DEV_QFRZN
) != 0)
580 cam_release_devq(done_ccb
->ccb_h
.path
,
586 bp
->b_resid
= csio
->resid
;
587 if (bp
->b_resid
!= 0)
588 bp
->b_flags
|= B_ERROR
;
592 * Block out any asyncronous callbacks
593 * while we touch the pending ccb list.
595 LIST_REMOVE(&done_ccb
->ccb_h
, periph_links
.le
);
597 devstat_end_transaction_buf(&softc
->device_stats
, bp
);
602 /* Caller will release the CCB */
603 wakeup(&done_ccb
->ccb_h
.cbfcnp
);
606 xpt_release_ccb(done_ccb
);
610 pterror(union ccb
*ccb
, u_int32_t cam_flags
, u_int32_t sense_flags
)
612 struct pt_softc
*softc
;
613 struct cam_periph
*periph
;
615 periph
= xpt_path_periph(ccb
->ccb_h
.path
);
616 softc
= (struct pt_softc
*)periph
->softc
;
618 return(cam_periph_error(ccb
, cam_flags
, sense_flags
,
623 ptioctl(struct dev_ioctl_args
*ap
)
625 cdev_t dev
= ap
->a_head
.a_dev
;
626 caddr_t addr
= ap
->a_data
;
627 struct cam_periph
*periph
;
628 struct pt_softc
*softc
;
633 periph
= cam_extend_get(ptperiphs
, unit
);
638 softc
= (struct pt_softc
*)periph
->softc
;
640 cam_periph_lock(periph
);
643 case PTIOCGETTIMEOUT
:
644 if (softc
->io_timeout
>= 1000)
645 *(int *)addr
= softc
->io_timeout
/ 1000;
649 case PTIOCSETTIMEOUT
:
650 if (*(int *)addr
< 1) {
655 softc
->io_timeout
= *(int *)addr
* 1000;
659 error
= cam_periph_ioctl(periph
, ap
->a_cmd
, addr
, pterror
);
663 cam_periph_unlock(periph
);
669 scsi_send_receive(struct ccb_scsiio
*csio
, u_int32_t retries
,
670 void (*cbfcnp
)(struct cam_periph
*, union ccb
*),
671 u_int tag_action
, int readop
, u_int byte2
,
672 u_int32_t xfer_len
, u_int8_t
*data_ptr
, u_int8_t sense_len
,
675 struct scsi_send_receive
*scsi_cmd
;
677 scsi_cmd
= (struct scsi_send_receive
*)&csio
->cdb_io
.cdb_bytes
;
678 scsi_cmd
->opcode
= readop
? RECEIVE
: SEND
;
679 scsi_cmd
->byte2
= byte2
;
680 scsi_ulto3b(xfer_len
, scsi_cmd
->xfer_len
);
681 scsi_cmd
->control
= 0;
686 /*flags*/readop
? CAM_DIR_IN
: CAM_DIR_OUT
,