Bump MAX_INITIATORS to 1024- the LSI-Logic can go even higher than

this for 'initiator id'- this is a stopgap until a sparse map is
added.

Make compat defines for offset format (FreeBSD 5 or less).

Add no-asyncio flag. There's some breakage with ASYNC I/O that every
now and then drops us into an infinite loop. This also then does
a fallback to no-asyncio if the AIO option isn't loaded/compiled into
the kernel.

A number of other chanes to try and track some breakage.
This commit is contained in:
Matt Jacob 2006-09-27 15:38:13 +00:00
parent e640c42275
commit cd6dedfc61
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=162704
3 changed files with 150 additions and 96 deletions

View File

@ -35,6 +35,7 @@
#include <string.h>
#include <err.h>
#include <aio.h>
#include <unistd.h>
#include <assert.h>
#include <sys/param.h>
#include <sys/types.h>
@ -360,7 +361,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 -
@ -496,21 +497,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)
#if __FreeBSD_version >= 500000
warnx("Starting DIR_IN @%jd:%u",
#else
warnx("Starting DIR_IN @%lld:%u",
#endif
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)
#if __FreeBSD_version >= 500000
warnx("Starting DIR_OUT @%jd:%u",
#else
warnx("Starting DIR_OUT @%lld:%u",
#endif
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);
@ -572,29 +565,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)
#if __FreeBSD_version >= 500000
warnx("r/w 0 blocks @ blkno %ju", blkno);
#else
warnx("r/w 0 blocks @ blkno %llu", blkno);
#endif
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)
#if __FreeBSD_version >= 500000
warnx("write %u blocks @ blkno %ju", count, blkno);
#else
warnx("write %u blocks @ blkno %llu", count, blkno);
#endif
warnx("write %u blocks @ blkno " OFF_FMT, count, blkno);
} else {
a_descr->flags |= CAM_DIR_IN;
if (debug)
#if __FreeBSD_version >= 500000
warnx("read %u blocks @ blkno %ju", count, blkno);
#else
warnx("read %u blocks @ blkno %llu", count, blkno);
#endif
warnx("read %u blocks @ blkno " OFF_FMT, count, blkno);
}
return (1);
}
@ -626,14 +607,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);
@ -665,7 +673,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,
@ -675,8 +683,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 {
@ -710,11 +722,34 @@ tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio,
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");

View File

@ -56,12 +56,13 @@
/* 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;
int notaio = 0;
off_t volume_size;
u_int sector_size;
size_t buf_size;
@ -86,7 +87,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);
@ -117,7 +118,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;
@ -193,6 +194,9 @@ main(int argc, char *argv[])
/* NOTREACHED */
}
break;
case 'Y':
notaio = 1;
break;
default:
usage();
/* NOTREACHED */
@ -246,20 +250,16 @@ main(int argc, char *argv[])
volume_size = user_size / sector_size;
}
if (debug)
#if __FreeBSD_version >= 500000
warnx("volume_size: %d bytes x %jd sectors",
#else
warnx("volume_size: %d bytes x %lld sectors",
#endif
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)
@ -269,16 +269,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");
}
@ -311,7 +312,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 */
@ -421,7 +422,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 */
@ -440,7 +441,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");
@ -464,7 +465,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:
@ -473,12 +474,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. */
@ -534,7 +540,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) {
@ -586,7 +592,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:
@ -619,8 +625,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;
@ -659,6 +666,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);
@ -679,35 +687,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);
}
@ -717,7 +719,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;
@ -725,7 +727,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;
@ -761,11 +763,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
@ -856,8 +861,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) {
@ -987,7 +994,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);

View File

@ -33,9 +33,9 @@
/*
* Maximum number of parallel commands to accept,
* 256 for Fibre Channel (SPI is 16).
* 1024 for Fibre Channel (SPI is 16).
*/
#define MAX_INITIATORS 256
#define MAX_INITIATORS 1024
#define SECTOR_SIZE 512
#define MAX_EVENTS (MAX_INITIATORS + 5)
/* kqueue for AIO, signals */
@ -114,4 +114,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 */