diff --git a/share/examples/scsi_target/Makefile b/share/examples/scsi_target/Makefile index 480da7a..bab70b2 100644 --- a/share/examples/scsi_target/Makefile +++ b/share/examples/scsi_target/Makefile @@ -1,10 +1,9 @@ -# $FreeBSD: src/share/examples/scsi_target/Makefile,v 1.2.2.1 2003/02/18 22:07:10 njl Exp $ -# $DragonFly: src/share/examples/scsi_target/Makefile,v 1.2 2003/06/17 04:36:57 dillon Exp $ +# $FreeBSD$ PROG= scsi_target SRCS= scsi_target.h scsi_target.c scsi_cmds.c -DPADD= ${LIBCAM} -LDADD= -lcam +DPADD= ${LIBCAM} ${LIBSBUF} +LDADD= -lcam -lsbuf MAN= scsi_target.8 diff --git a/share/examples/scsi_target/scsi_cmds.c b/share/examples/scsi_target/scsi_cmds.c index a37b71b..c9d135e 100644 --- a/share/examples/scsi_target/scsi_cmds.c +++ b/share/examples/scsi_target/scsi_cmds.c @@ -25,17 +25,18 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/share/examples/scsi_target/scsi_cmds.c,v 1.2.2.1 2003/02/18 22:07:10 njl Exp $ - * $DragonFly: src/share/examples/scsi_target/scsi_cmds.c,v 1.2 2003/06/17 04:36:57 dillon Exp $ */ #include #include #include +#include #include #include #include +#include #include +#include #include #include @@ -47,6 +48,9 @@ typedef int targ_start_func(struct ccb_accept_tio *, struct ccb_scsiio *); typedef void targ_done_func(struct ccb_accept_tio *, struct ccb_scsiio *, io_ops); +#ifndef REPORT_LUNS +#define REPORT_LUNS 0xa0 +#endif struct targ_cdb_handlers { u_int8_t cmd; @@ -58,6 +62,9 @@ struct targ_cdb_handlers { static targ_start_func tcmd_inquiry; static targ_start_func tcmd_req_sense; static targ_start_func tcmd_rd_cap; +#ifdef READ_16 +static targ_start_func tcmd_rd_cap16; +#endif static targ_start_func tcmd_rdwr; static targ_start_func tcmd_rdwr_decode; static targ_done_func tcmd_rdwr_done; @@ -83,13 +90,19 @@ static struct targ_cdb_handlers cdb_handlers[] = { { SYNCHRONIZE_CACHE, tcmd_null_ok, NULL }, { MODE_SENSE_6, tcmd_illegal_req, NULL }, { MODE_SELECT_6, tcmd_illegal_req, NULL }, + { REPORT_LUNS, tcmd_illegal_req, NULL }, +#ifdef READ_16 + { READ_16, tcmd_rdwr, tcmd_rdwr_done }, + { WRITE_16, tcmd_rdwr, tcmd_rdwr_done }, + { SERVICE_ACTION_IN, tcmd_rd_cap16, NULL }, +#endif { ILLEGAL_CDB, NULL, NULL } }; static struct scsi_inquiry_data inq_data; static struct initiator_state istates[MAX_INITIATORS]; extern int debug; -extern u_int32_t volume_size; +extern uint64_t volume_size; extern size_t sector_size; extern size_t buf_size; @@ -142,6 +155,16 @@ tcmd_handle(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, io_ops event) } last_cmd = h; } + + /* call completion and exit */ + if (event != ATIO_WORK) { + if (last_cmd->done != NULL) + last_cmd->done(atio, ctio, event); + else + free_ccb((union ccb *)ctio); + return (1); + } + if (last_cmd->cmd == ILLEGAL_CDB) { if (event != ATIO_WORK) { warnx("no done func for %#x???", a_descr->cdb[0]); @@ -154,15 +177,6 @@ tcmd_handle(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, io_ops event) return (0); } - /* call completion and exit */ - if (event != ATIO_WORK) { - if (last_cmd->done != NULL) - last_cmd->done(atio, ctio, event); - else - free_ccb((union ccb *)ctio); - return (1); - } - istate = tcmd_get_istate(ctio->init_id); if (istate == NULL) { tcmd_illegal_req(atio, ctio); @@ -246,12 +260,10 @@ tcmd_sense(u_int init_id, struct ccb_scsiio *ctio, u_int8_t flags, /* Fill out the supplied CTIO */ if (ctio != NULL) { - /* No autosense yet bcopy(sense, &ctio->sense_data, sizeof(*sense)); - ctio->sense_len = sizeof(*sense); XXX - */ + ctio->sense_len = sizeof(*sense); /* XXX */ ctio->ccb_h.flags &= ~CAM_DIR_MASK; - ctio->ccb_h.flags |= CAM_DIR_NONE | /* CAM_SEND_SENSE | */ + ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_SENSE | CAM_SEND_STATUS; ctio->dxfer_len = 0; ctio->scsi_status = SCSI_STATUS_CHECK_COND; @@ -331,7 +343,11 @@ init_inquiry(u_int16_t req_flags, u_int16_t sim_flags) inq = &inq_data; bzero(inq, sizeof(*inq)); inq->device = T_DIRECT | (SID_QUAL_LU_CONNECTED << 5); +#ifdef SCSI_REV_SPC + inq->version = SCSI_REV_SPC; /* was 2 */ +#else inq->version = SCSI_REV_3; /* was 2 */ +#endif /* * XXX cpi.hba_inquiry doesn't support Addr16 so we give the @@ -344,7 +360,7 @@ init_inquiry(u_int16_t req_flags, u_int16_t sim_flags) /* Advertise only what the SIM can actually support */ req_flags &= sim_flags; - scsi_ulto2b(req_flags, &inq->reserved[1]); + scsi_ulto2b(req_flags, &inq->spc2_flags); inq->response_format = 2; /* SCSI2 Inquiry Format */ inq->additional_length = SHORT_INQUIRY_LENGTH - @@ -396,17 +412,55 @@ tcmd_rd_cap(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) { struct scsi_read_capacity_data *srp; struct atio_descr *a_descr; + uint32_t vsize; a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; srp = (struct scsi_read_capacity_data *)ctio->data_ptr; + if (volume_size > 0xffffffff) + vsize = 0xffffffff; + else + vsize = (uint32_t)(volume_size - 1); + if (debug) { cdb_debug(a_descr->cdb, "READ CAP from %u (%u, %u): ", + atio->init_id, vsize, sector_size); + } + + bzero(srp, sizeof(*srp)); + scsi_ulto4b(vsize, srp->addr); + scsi_ulto4b(sector_size, srp->length); + + ctio->dxfer_len = sizeof(*srp); + ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS; + ctio->scsi_status = SCSI_STATUS_OK; + return (0); +} + +#ifdef READ_16 +static int +tcmd_rd_cap16(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) +{ + struct scsi_read_capacity_16 *scsi_cmd; + struct scsi_read_capacity_data_long *srp; + struct atio_descr *a_descr; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + scsi_cmd = (struct scsi_read_capacity_16 *)a_descr->cdb; + srp = (struct scsi_read_capacity_data_long *)ctio->data_ptr; + + if (scsi_cmd->service_action != SRC16_SERVICE_ACTION) { + tcmd_illegal_req(atio, ctio); + return (0); + } + + if (debug) { + cdb_debug(a_descr->cdb, "READ CAP16 from %u (%u, %u): ", atio->init_id, volume_size - 1, sector_size); } bzero(srp, sizeof(*srp)); - scsi_ulto4b(volume_size - 1, srp->addr); + scsi_u64to8b(volume_size - 1, srp->addr); scsi_ulto4b(sector_size, srp->length); ctio->dxfer_len = sizeof(*srp); @@ -414,6 +468,7 @@ tcmd_rd_cap(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) ctio->scsi_status = SCSI_STATUS_OK; return (0); } +#endif static int tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) @@ -441,13 +496,13 @@ tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) if ((a_descr->flags & CAM_DIR_IN) != 0) { ret = start_io(atio, ctio, CAM_DIR_IN); if (debug) - warnx("Starting DIR_IN @%lld:%u", c_descr->offset, - a_descr->targ_req); + warnx("Starting %p DIR_IN @" OFF_FMT ":%u", + a_descr, c_descr->offset, a_descr->targ_req); } else { ret = start_io(atio, ctio, CAM_DIR_OUT); if (debug) - warnx("Starting DIR_OUT @%lld:%u", c_descr->offset, - a_descr->init_req); + warnx("Starting %p DIR_OUT @" OFF_FMT ":%u", + a_descr, c_descr->offset, a_descr->init_req); } return (ret); @@ -456,7 +511,8 @@ tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) static int tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) { - u_int32_t blkno, count; + uint64_t blkno; + uint32_t count; struct atio_descr *a_descr; u_int8_t *cdb; @@ -465,14 +521,36 @@ tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) if (debug) cdb_debug(cdb, "R/W from %u: ", atio->init_id); - if (cdb[0] == READ_6 || cdb[0] == WRITE_6) { + switch (cdb[0]) { + case READ_6: + case WRITE_6: + { struct scsi_rw_6 *rw_6 = (struct scsi_rw_6 *)cdb; blkno = scsi_3btoul(rw_6->addr); count = rw_6->length; - } else { + break; + } + case READ_10: + case WRITE_10: + { struct scsi_rw_10 *rw_10 = (struct scsi_rw_10 *)cdb; blkno = scsi_4btoul(rw_10->addr); count = scsi_2btoul(rw_10->length); + break; + } +#ifdef READ_16 + case READ_16: + case WRITE_16: + { + struct scsi_rw_16 *rw_16 = (struct scsi_rw_16 *)cdb; + blkno = scsi_8btou64(rw_16->addr); + count = scsi_4btoul(rw_16->length); + break; + } +#endif + default: + tcmd_illegal_req(atio, ctio); + return (0); } if (blkno + count > volume_size) { warnx("Attempt to access past end of volume"); @@ -486,17 +564,17 @@ tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) a_descr->total_len = count * sector_size; if (a_descr->total_len == 0) { if (debug) - warnx("r/w 0 blocks @ blkno %u", blkno); + warnx("r/w 0 blocks @ blkno " OFF_FMT, blkno); tcmd_null_ok(atio, ctio); return (0); } else if (cdb[0] == WRITE_6 || cdb[0] == WRITE_10) { a_descr->flags |= CAM_DIR_OUT; if (debug) - warnx("write %u blocks @ blkno %u", count, blkno); + warnx("write %u blocks @ blkno " OFF_FMT, count, blkno); } else { a_descr->flags |= CAM_DIR_IN; if (debug) - warnx("read %u blocks @ blkno %u", count, blkno); + warnx("read %u blocks @ blkno " OFF_FMT, count, blkno); } return (1); } @@ -528,14 +606,41 @@ start_io(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, int dir) /* If DIR_IN, start read from target, otherwise begin CTIO xfer. */ ret = 1; if (dir == CAM_DIR_IN) { - if (aio_read(&c_descr->aiocb) < 0) - err(1, "aio_read"); /* XXX */ + if (notaio) { + if (debug) + warnx("read sync %lud @ block " OFF_FMT, + (unsigned long) + (ctio->dxfer_len / sector_size), + c_descr->offset / sector_size); + if (lseek(c_descr->aiocb.aio_fildes, + c_descr->aiocb.aio_offset, SEEK_SET) < 0) { + perror("lseek"); + err(1, "lseek"); + } + if (read(c_descr->aiocb.aio_fildes, + (void *)c_descr->aiocb.aio_buf, + ctio->dxfer_len) != ctio->dxfer_len) { + err(1, "read"); + } + } else { + if (debug) + warnx("read async %lud @ block " OFF_FMT, + (unsigned long) + (ctio->dxfer_len / sector_size), + c_descr->offset / sector_size); + if (aio_read(&c_descr->aiocb) < 0) { + err(1, "aio_read"); /* XXX */ + } + } a_descr->targ_req += ctio->dxfer_len; + /* if we're done, we can mark the CCB as to send status */ if (a_descr->targ_req == a_descr->total_len) { ctio->ccb_h.flags |= CAM_SEND_STATUS; ctio->scsi_status = SCSI_STATUS_OK; ret = 0; } + if (notaio) + tcmd_rdwr_done(atio, ctio, AIO_DONE); } else { if (a_descr->targ_ack == a_descr->total_len) tcmd_null_ok(atio, ctio); @@ -567,7 +672,7 @@ tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, switch (event) { case AIO_DONE: - if (aio_return(&c_descr->aiocb) < 0) { + if (!notaio && aio_return(&c_descr->aiocb) < 0) { warn("aio_return error"); /* XXX */ tcmd_sense(ctio->init_id, ctio, @@ -577,8 +682,12 @@ tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, } a_descr->targ_ack += ctio->dxfer_len; if ((a_descr->flags & CAM_DIR_IN) != 0) { - if (debug) - warnx("sending CTIO for AIO read"); + if (debug) { + if (notaio) + warnx("sending CTIO for AIO read"); + else + warnx("sending CTIO for sync read"); + } a_descr->init_req += ctio->dxfer_len; send_ccb((union ccb *)ctio, /*priority*/1); } else { @@ -591,18 +700,55 @@ tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, } break; case CTIO_DONE: - if (ctio->ccb_h.status != CAM_REQ_CMP) { - /* XXX */ + switch (ctio->ccb_h.status & CAM_STATUS_MASK) { + case CAM_REQ_CMP: + break; + case CAM_REQUEUE_REQ: + warnx("requeueing request"); + if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) { + if (aio_write(&c_descr->aiocb) < 0) { + err(1, "aio_write"); /* XXX */ + } + } else { + if (aio_read(&c_descr->aiocb) < 0) { + err(1, "aio_read"); /* XXX */ + } + } + return; + default: errx(1, "CTIO failed, status %#x", ctio->ccb_h.status); } a_descr->init_ack += ctio->dxfer_len; if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT && ctio->dxfer_len > 0) { - if (debug) - warnx("sending AIO for CTIO write"); a_descr->targ_req += ctio->dxfer_len; - if (aio_write(&c_descr->aiocb) < 0) - err(1, "aio_write"); /* XXX */ + if (notaio) { + if (debug) + warnx("write sync %lud @ block " + OFF_FMT, (unsigned long) + (ctio->dxfer_len / sector_size), + c_descr->offset / sector_size); + if (lseek(c_descr->aiocb.aio_fildes, + c_descr->aiocb.aio_offset, SEEK_SET) < 0) { + perror("lseek"); + err(1, "lseek"); + } + if (write(c_descr->aiocb.aio_fildes, + (void *) c_descr->aiocb.aio_buf, + ctio->dxfer_len) != ctio->dxfer_len) { + err(1, "write"); + } + tcmd_rdwr_done(atio, ctio, AIO_DONE); + } else { + if (debug) + warnx("write async %lud @ block " + OFF_FMT, (unsigned long) + (ctio->dxfer_len / sector_size), + c_descr->offset / sector_size); + if (aio_write(&c_descr->aiocb) < 0) { + err(1, "aio_write"); /* XXX */ + } + } } else { if (debug) warnx("CTIO done freeing CTIO"); diff --git a/share/examples/scsi_target/scsi_target.8 b/share/examples/scsi_target/scsi_target.8 index 9c76b2d..677e2b4 100644 --- a/share/examples/scsi_target/scsi_target.8 +++ b/share/examples/scsi_target/scsi_target.8 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/share/examples/scsi_target/scsi_target.8,v 1.2.4.1 2003/02/18 22:07:10 njl Exp $ +.\" $FreeBSD$ .\" .Dd November 15, 2002 .Dt SCSI_TARGET 8 @@ -94,6 +94,17 @@ and its associated control device. Use a different size for the emulated volume. Must be less than or equal to the size of .Ar filename . +If the number ends with a +.Dq Li k , +.Dq Li m , +.Dq Li g , +.Dq Li t , +.Dq Li p , +or +.Dq Li e , +the number is multiplied by 2^10 (1K), 2^20 (1M), 2^30 (1G), 2^40 (1T), +2^50 (1P) and 2^60 (1E) +respectively. .El .Pp Required arguments: @@ -129,7 +140,7 @@ will be used. Debugging information will be output. 16-bit wide transfers will be used if the SIM supports them. .Pp -.Dl "scsi_target -d -v 1000 -W 16 0:1:0 vol" +.Dl "scsi_target -d -s 1000 -W 16 0:1:0 vol" .Sh SEE ALSO .Xr scsi 4 , .Xr targ 4 @@ -144,4 +155,4 @@ and was written by It was rewritten for .Fx 5.0 by -.An Nate Lawson Aq Mt nate@root.org . +.An Nate Lawson Aq nate@root.org . diff --git a/share/examples/scsi_target/scsi_target.c b/share/examples/scsi_target/scsi_target.c index 5867fc0..b57d084 100644 --- a/share/examples/scsi_target/scsi_target.c +++ b/share/examples/scsi_target/scsi_target.c @@ -25,11 +25,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/share/examples/scsi_target/scsi_target.c,v 1.5.2.5 2003/02/18 22:07:10 njl Exp $ - * $DragonFly: src/share/examples/scsi_target/scsi_target.c,v 1.2 2003/06/17 04:36:57 dillon Exp $ + * $FreeBSD$ */ #include +#include #include #include #include @@ -55,14 +55,15 @@ /* Maximum amount to transfer per CTIO */ #define MAX_XFER MAXPHYS /* Maximum number of allocated CTIOs */ -#define MAX_CTIOS 32 +#define MAX_CTIOS 64 /* Maximum sector size for emulated volume */ #define MAX_SECTOR 32768 /* Global variables */ int debug; -u_int32_t volume_size; -size_t sector_size; +int notaio = 0; +off_t volume_size; +u_int sector_size; size_t buf_size; /* Local variables */ @@ -85,7 +86,7 @@ static void request_loop(void); static void handle_read(void); /* static int work_atio(struct ccb_accept_tio *); */ static void queue_io(struct ccb_scsiio *); -static void run_queue(struct ccb_accept_tio *); +static int run_queue(struct ccb_accept_tio *); static int work_inot(struct ccb_immed_notify *); static struct ccb_scsiio * get_ctio(void); @@ -116,7 +117,7 @@ main(int argc, char *argv[]) TAILQ_INIT(&pending_queue); TAILQ_INIT(&work_queue); - while ((ch = getopt(argc, argv, "AdSTb:c:s:W:")) != -1) { + while ((ch = getopt(argc, argv, "AdSTYb:c:s:W:")) != -1) { switch(ch) { case 'A': req_flags |= SID_Addr16; @@ -141,10 +142,39 @@ main(int argc, char *argv[]) errx(1, "Unreasonable sector size: %s", optarg); break; case 's': - user_size = strtoll(optarg, NULL, /*base*/10); + { + int last, shift = 0; + + last = strlen(optarg) - 1; + if (last > 0) { + switch (tolower(optarg[last])) { + case 'e': + shift += 10; + /* FALLTHROUGH */ + case 'p': + shift += 10; + /* FALLTHROUGH */ + case 't': + shift += 10; + /* FALLTHROUGH */ + case 'g': + shift += 10; + /* FALLTHROUGH */ + case 'm': + shift += 10; + /* FALLTHROUGH */ + case 'k': + shift += 10; + optarg[last] = 0; + break; + } + } + user_size = strtoll(optarg, (char **)NULL, /*base*/10); + user_size <<= shift; if (user_size < 0) errx(1, "Unreasonable volume size: %s", optarg); break; + } case 'W': req_flags &= ~(SID_WBus16 | SID_WBus32); switch (atoi(optarg)) { @@ -163,6 +193,9 @@ main(int argc, char *argv[]) /* NOTREACHED */ } break; + case 'Y': + notaio = 1; + break; default: usage(); /* NOTREACHED */ @@ -200,17 +233,32 @@ main(int argc, char *argv[]) if (fstat(file_fd, &st) < 0) err(1, "fstat file"); - volume_size = st.st_size / sector_size; +#if __FreeBSD_version >= 500000 + if ((st.st_mode & S_IFCHR) != 0) { + /* raw device */ + off_t mediasize; + if (ioctl(file_fd, DIOCGMEDIASIZE, &mediasize) < 0) + err(1, "DIOCGMEDIASIZE"); + + /* XXX get sector size by ioctl()?? */ + volume_size = mediasize / sector_size; + } else +#endif + volume_size = st.st_size / sector_size; } else { volume_size = user_size / sector_size; } + if (debug) + warnx("volume_size: %d bytes x " OFF_FMT " sectors", + sector_size, volume_size); + if (volume_size <= 0) errx(1, "volume must be larger than %d", sector_size); - { + if (notaio == 0) { struct aiocb aio, *aiop; - /* Make sure we have working AIO support */ + /* See if we have we have working AIO support */ memset(&aio, 0, sizeof(aio)); aio.aio_buf = malloc(sector_size); if (aio.aio_buf == NULL) @@ -220,16 +268,17 @@ main(int argc, char *argv[]) aio.aio_nbytes = sector_size; signal(SIGSYS, SIG_IGN); if (aio_read(&aio) != 0) { - printf("You must enable VFS_AIO in your kernel " - "or load the aio(4) module.\n"); - err(1, "aio_read"); + printf("AIO support is not available- switchin to" + " single-threaded mode.\n"); + notaio = 1; + } else { + if (aio_waitcomplete(&aiop, NULL) != sector_size) + err(1, "aio_waitcomplete"); + assert(aiop == &aio); + signal(SIGSYS, SIG_DFL); } - if (aio_waitcomplete(&aiop, NULL) != sector_size) - err(1, "aio_waitcomplete"); - assert(aiop == &aio); - signal(SIGSYS, SIG_DFL); free((void *)aio.aio_buf); - if (debug) + if (debug && notaio == 0) warnx("aio support tested ok"); } @@ -262,7 +311,7 @@ main(int argc, char *argv[]) /* Enable debugging if requested */ if (debug) { if (ioctl(targ_fd, TARGIOCDEBUG, &debug) != 0) - err(1, "TARGIOCDEBUG"); + warnx("TARGIOCDEBUG"); } /* Set up inquiry data according to what SIM supports */ @@ -372,7 +421,7 @@ request_loop() /* Loop until user signal */ while (quit == 0) { - int retval, i; + int retval, i, oo; struct ccb_hdr *ccb_h; /* Check for the next signal, read ready, or AIO completion */ @@ -391,7 +440,7 @@ request_loop() } /* Process all received events. */ - for (i = 0; i < retval; i++) { + for (oo = i = 0; i < retval; i++) { if ((events[i].flags & EV_ERROR) != 0) errx(1, "kevent registration failed"); @@ -415,7 +464,7 @@ request_loop() /* Queue on the appropriate ATIO */ queue_io(ctio); /* Process any queued completions. */ - run_queue(c_descr->atio); + oo += run_queue(c_descr->atio); break; } case EVFILT_SIGNAL: @@ -424,12 +473,17 @@ request_loop() quit = 1; break; default: - warnx("unknown event %#x", events[i].filter); + warnx("unknown event %d", events[i].filter); break; } if (debug) - warnx("event done"); + warnx("event %d done", events[i].filter); + } + + if (oo) { + tptr = &ts; + continue; } /* Grab the first CCB and perform one work unit. */ @@ -485,7 +539,7 @@ static void handle_read() { union ccb *ccb_array[MAX_INITIATORS], *ccb; - int ccb_count, i; + int ccb_count, i, oo; ccb_count = read(targ_fd, ccb_array, sizeof(ccb_array)); if (ccb_count <= 0) { @@ -537,7 +591,7 @@ handle_read() /* Queue on the appropriate ATIO */ queue_io(ctio); /* Process any queued completions. */ - run_queue(c_descr->atio); + oo += run_queue(c_descr->atio); break; } case XPT_IMMED_NOTIFY: @@ -570,8 +624,9 @@ work_atio(struct ccb_accept_tio *atio) /* Get a CTIO and initialize it according to our known parameters */ ctio = get_ctio(); - if (ctio == NULL) + if (ctio == NULL) { return (1); + } ret = 0; ctio->ccb_h.flags = a_descr->flags; ctio->tag_id = atio->tag_id; @@ -583,6 +638,8 @@ work_atio(struct ccb_accept_tio *atio) c_descr->offset = a_descr->base_off + a_descr->targ_req; else if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) c_descr->offset = a_descr->base_off + a_descr->init_req; + else + c_descr->offset = a_descr->base_off; /* * Return a check condition if there was an error while @@ -608,6 +665,7 @@ work_atio(struct ccb_accept_tio *atio) ret = tcmd_handle(atio, ctio, ATIO_WORK); break; case CAM_REQ_ABORTED: + warn("ATIO %p aborted", a_descr); /* Requeue on HBA */ TAILQ_REMOVE(&work_queue, &atio->ccb_h, periph_links.tqe); send_ccb((union ccb *)atio, /*priority*/1); @@ -628,35 +686,29 @@ queue_io(struct ccb_scsiio *ctio) { struct ccb_hdr *ccb_h; struct io_queue *ioq; - struct ctio_descr *c_descr, *curr_descr; + struct ctio_descr *c_descr; c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; - /* If the completion is for a specific ATIO, queue in order */ - if (c_descr->atio != NULL) { - struct atio_descr *a_descr; - - a_descr = (struct atio_descr *)c_descr->atio->ccb_h.targ_descr; - ioq = &a_descr->cmplt_io; - } else { + if (c_descr->atio == NULL) { errx(1, "CTIO %p has NULL ATIO", ctio); } + ioq = &((struct atio_descr *)c_descr->atio->ccb_h.targ_descr)->cmplt_io; - /* Insert in order, sorted by offset */ - if (!TAILQ_EMPTY(ioq)) { - TAILQ_FOREACH_REVERSE(ccb_h, ioq, io_queue, periph_links.tqe) { - curr_descr = (struct ctio_descr *)ccb_h->targ_descr; - if (curr_descr->offset <= c_descr->offset) { - TAILQ_INSERT_AFTER(ioq, ccb_h, &ctio->ccb_h, - periph_links.tqe); - break; - } - if (TAILQ_PREV(ccb_h, io_queue, periph_links.tqe) - == NULL) { - TAILQ_INSERT_BEFORE(ccb_h, &ctio->ccb_h, - periph_links.tqe); - break; - } + if (TAILQ_EMPTY(ioq)) { + TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe); + return; + } + + TAILQ_FOREACH_REVERSE(ccb_h, ioq, io_queue, periph_links.tqe) { + struct ctio_descr *curr_descr = + (struct ctio_descr *)ccb_h->targ_descr; + if (curr_descr->offset <= c_descr->offset) { + break; } + } + + if (ccb_h) { + TAILQ_INSERT_AFTER(ioq, ccb_h, &ctio->ccb_h, periph_links.tqe); } else { TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe); } @@ -666,7 +718,7 @@ queue_io(struct ccb_scsiio *ctio) * Go through all completed AIO/CTIOs for a given ATIO and advance data * counts, start continuation IO, etc. */ -static void +static int run_queue(struct ccb_accept_tio *atio) { struct atio_descr *a_descr; @@ -674,7 +726,7 @@ run_queue(struct ccb_accept_tio *atio) int sent_status, event; if (atio == NULL) - return; + return (0); a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; @@ -685,6 +737,14 @@ run_queue(struct ccb_accept_tio *atio) ctio = (struct ccb_scsiio *)ccb_h; c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; + if (ctio->ccb_h.status == CAM_REQ_ABORTED) { + TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h, + periph_links.tqe); + free_ccb((union ccb *)ctio); + send_ccb((union ccb *)atio, /*priority*/1); + continue; + } + /* If completed item is in range, call handler */ if ((c_descr->event == AIO_DONE && c_descr->offset == a_descr->base_off + a_descr->targ_ack) @@ -702,11 +762,14 @@ run_queue(struct ccb_accept_tio *atio) send_ccb((union ccb *)atio, /*priority*/1); } else { /* Gap in offsets so wait until later callback */ - if (debug) - warnx("IO %p out of order", ccb_h); - break; + if (/* debug */ 1) + warnx("IO %p:%p out of order %s", ccb_h, + a_descr, c_descr->event == AIO_DONE? + "aio" : "ctio"); + return (1); } } + return (0); } static int @@ -797,8 +860,10 @@ get_ctio() struct ctio_descr *c_descr; struct sigevent *se; - if (num_ctios == MAX_CTIOS) + if (num_ctios == MAX_CTIOS) { + warnx("at CTIO max"); return (NULL); + } ctio = (struct ccb_scsiio *)malloc(sizeof(*ctio)); if (ctio == NULL) { @@ -928,7 +993,7 @@ static void usage() { fprintf(stderr, - "Usage: scsi_target [-AdST] [-b bufsize] [-c sectorsize]\n" + "Usage: scsi_target [-AdSTY] [-b bufsize] [-c sectorsize]\n" "\t\t[-r numbufs] [-s volsize] [-W 8,16,32]\n" "\t\tbus:target:lun filename\n"); exit(1); diff --git a/share/examples/scsi_target/scsi_target.h b/share/examples/scsi_target/scsi_target.h index 36bccb9..5a825ee 100644 --- a/share/examples/scsi_target/scsi_target.h +++ b/share/examples/scsi_target/scsi_target.h @@ -25,18 +25,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/share/examples/scsi_target/scsi_target.h,v 1.1.4.1 2003/02/18 22:07:10 njl Exp $ - * $DragonFly: src/share/examples/scsi_target/scsi_target.h,v 1.2 2003/06/17 04:36:57 dillon Exp $ + * $FreeBSD$ */ #ifndef _SCSI_TARGET_H #define _SCSI_TARGET_H /* - * Maximum number of parallel commands to accept - * Set to 256 for Fibre Channel (SPI is 16) + * Maximum number of parallel commands to accept, + * 1024 for Fibre Channel (SPI is 16). */ -#define MAX_INITIATORS 16 +#define MAX_INITIATORS 1024 #define SECTOR_SIZE 512 #define MAX_EVENTS (MAX_INITIATORS + 5) /* kqueue for AIO, signals */ @@ -49,14 +48,57 @@ TAILQ_HEAD(io_queue, ccb_hdr); /* Offset into the private CCB area for storing our descriptor */ #define targ_descr periph_priv.entries[1].ptr +struct scsi_read_capacity_data_long +{ + uint8_t addr[8]; + uint8_t length[4]; +#define SRC16_PROT_EN 0x01 +#define SRC16_P_TYPE 0x0e +#define SRC16_PTYPE_1 0x00 +#define SRC16_PTYPE_2 0x02 +#define SRC16_PTYPE_3 0x04 + uint8_t prot; +#define SRC16_LBPPBE 0x0f +#define SRC16_PI_EXPONENT 0xf0 +#define SRC16_PI_EXPONENT_SHIFT 4 + uint8_t prot_lbppbe; +#define SRC16_LALBA 0x3f +#define SRC16_LBPRZ 0x40 +#define SRC16_LBPME 0x80 +/* + * Alternate versions of these macros that are intended for use on a 16-bit + * version of the lalba_lbp field instead of the array of 2 8 bit numbers. + */ +#define SRC16_LALBA_A 0x3fff +#define SRC16_LBPRZ_A 0x4000 +#define SRC16_LBPME_A 0x8000 + uint8_t lalba_lbp[2]; + uint8_t reserved[16]; +}; + +/* +struct scsi_report_luns +{ + uint8_t opcode; + uint8_t reserved1; +#define RPL_REPORT_DEFAULT 0x00 +#define RPL_REPORT_WELLKNOWN 0x01 +#define RPL_REPORT_ALL 0x02 + uint8_t select_report; + uint8_t reserved2[3]; + uint8_t length[4]; + uint8_t reserved3; + uint8_t control; +}; +*/ /* Descriptor attached to each ATIO */ struct atio_descr { off_t base_off; /* Base offset for ATIO */ - size_t total_len; /* Total xfer len for this ATIO */ - size_t init_req; /* Transfer count requested to/from init */ - size_t init_ack; /* Data transferred ok to/from init */ - size_t targ_req; /* Transfer count requested to/from target */ - size_t targ_ack; /* Data transferred ok to/from target */ + uint total_len; /* Total xfer len for this ATIO */ + uint init_req; /* Transfer count requested to/from init */ + uint init_ack; /* Data transferred ok to/from init */ + uint targ_req; /* Transfer count requested to/from target */ + uint targ_ack; /* Data transferred ok to/from target */ int flags; /* Flags for CTIOs */ u_int8_t *cdb; /* Pointer to received CDB */ /* List of completed AIO/CTIOs */ @@ -115,4 +157,16 @@ extern void send_ccb(union ccb *ccb, int priority); extern void free_ccb(union ccb *ccb); static __inline u_int min(u_int a, u_int b) { return (a < b ? a : b); } +/* Global Data */ +extern int notaio; + +/* + * Compat Defines + */ +#if __FreeBSD_version >= 500000 +#define OFF_FMT "%ju" +#else +#define OFF_FMT "%llu" +#endif + #endif /* _SCSI_TARGET_H */