139215Sgibbs/* 2107178Snjl * SCSI Disk Emulator 339215Sgibbs * 4107178Snjl * Copyright (c) 2002 Nate Lawson. 539215Sgibbs * All rights reserved. 639215Sgibbs * 739215Sgibbs * Redistribution and use in source and binary forms, with or without 839215Sgibbs * modification, are permitted provided that the following conditions 939215Sgibbs * are met: 1039215Sgibbs * 1. Redistributions of source code must retain the above copyright 1139215Sgibbs * notice, this list of conditions, and the following disclaimer, 1239215Sgibbs * without modification, immediately at the beginning of the file. 1339215Sgibbs * 2. The name of the author may not be used to endorse or promote products 1439215Sgibbs * derived from this software without specific prior written permission. 1539215Sgibbs * 1639215Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739215Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839215Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939215Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2039215Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139215Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239215Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339215Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439215Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539215Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639215Sgibbs * SUCH DAMAGE. 2739215Sgibbs * 2850476Speter * $FreeBSD$ 2939215Sgibbs */ 3039215Sgibbs 3139215Sgibbs#include <sys/types.h> 32121184Ssimokawa#include <ctype.h> 3344498Sgibbs#include <errno.h> 34107178Snjl#include <err.h> 3539215Sgibbs#include <fcntl.h> 3644498Sgibbs#include <signal.h> 3739215Sgibbs#include <stddef.h> 3839215Sgibbs#include <stdio.h> 3939215Sgibbs#include <stdlib.h> 40107178Snjl#include <string.h> 4139215Sgibbs#include <sysexits.h> 4239215Sgibbs#include <unistd.h> 43107178Snjl#include <aio.h> 44109161Snjl#include <assert.h> 45107178Snjl#include <sys/stat.h> 46107178Snjl#include <sys/queue.h> 47107178Snjl#include <sys/event.h> 48107178Snjl#include <sys/param.h> 49120428Ssimokawa#include <sys/disk.h> 50107178Snjl#include <cam/cam_queue.h> 5139215Sgibbs#include <cam/scsi/scsi_all.h> 52107178Snjl#include <cam/scsi/scsi_targetio.h> 5339215Sgibbs#include <cam/scsi/scsi_message.h> 54107178Snjl#include "scsi_target.h" 5539215Sgibbs 56107178Snjl/* Maximum amount to transfer per CTIO */ 57107178Snjl#define MAX_XFER MAXPHYS 58107178Snjl/* Maximum number of allocated CTIOs */ 59162704Smjacob#define MAX_CTIOS 64 60107178Snjl/* Maximum sector size for emulated volume */ 61107178Snjl#define MAX_SECTOR 32768 62107178Snjl 63107178Snjl/* Global variables */ 64107178Snjlint debug; 65162704Smjacobint notaio = 0; 66121184Ssimokawaoff_t volume_size; 67121184Ssimokawau_int sector_size; 68107178Snjlsize_t buf_size; 69107178Snjl 70107178Snjl/* Local variables */ 71107178Snjlstatic int targ_fd; 72107178Snjlstatic int kq_fd; 73107178Snjlstatic int file_fd; 74107178Snjlstatic int num_ctios; 75107178Snjlstatic struct ccb_queue pending_queue; 76107178Snjlstatic struct ccb_queue work_queue; 77107178Snjlstatic struct ioc_enable_lun ioc_enlun = { 7844498Sgibbs CAM_BUS_WILDCARD, 7944498Sgibbs CAM_TARGET_WILDCARD, 8044498Sgibbs CAM_LUN_WILDCARD 8144498Sgibbs}; 8239215Sgibbs 83107178Snjl/* Local functions */ 84107178Snjlstatic void cleanup(void); 85107178Snjlstatic int init_ccbs(void); 86107178Snjlstatic void request_loop(void); 87107178Snjlstatic void handle_read(void); 88107178Snjl/* static int work_atio(struct ccb_accept_tio *); */ 89107178Snjlstatic void queue_io(struct ccb_scsiio *); 90162704Smjacobstatic int run_queue(struct ccb_accept_tio *); 91237601Skenstatic int work_inot(struct ccb_immediate_notify *); 92107178Snjlstatic struct ccb_scsiio * 93107178Snjl get_ctio(void); 94107178Snjl/* static void free_ccb(union ccb *); */ 95107178Snjlstatic cam_status get_sim_flags(u_int16_t *); 96107178Snjlstatic void rel_simq(void); 97107178Snjlstatic void abort_all_pending(void); 98107178Snjlstatic void usage(void); 9939215Sgibbs 10039215Sgibbsint 10139215Sgibbsmain(int argc, char *argv[]) 10239215Sgibbs{ 103228481Sed int ch; 104228481Sed char *file_name; 105107178Snjl u_int16_t req_flags, sim_flags; 106107178Snjl off_t user_size; 10739215Sgibbs 108107178Snjl /* Initialize */ 109107178Snjl debug = 0; 110107178Snjl req_flags = sim_flags = 0; 111107178Snjl user_size = 0; 112107178Snjl targ_fd = file_fd = kq_fd = -1; 113107178Snjl num_ctios = 0; 114107178Snjl sector_size = SECTOR_SIZE; 115107178Snjl buf_size = DFLTPHYS; 116107178Snjl 117107178Snjl /* Prepare resource pools */ 118107178Snjl TAILQ_INIT(&pending_queue); 119107178Snjl TAILQ_INIT(&work_queue); 120107178Snjl 121162704Smjacob while ((ch = getopt(argc, argv, "AdSTYb:c:s:W:")) != -1) { 12239215Sgibbs switch(ch) { 123107178Snjl case 'A': 124107178Snjl req_flags |= SID_Addr16; 12539215Sgibbs break; 126107178Snjl case 'd': 127107178Snjl debug = 1; 12839215Sgibbs break; 129107178Snjl case 'S': 130107178Snjl req_flags |= SID_Sync; 13144498Sgibbs break; 132107178Snjl case 'T': 133107178Snjl req_flags |= SID_CmdQue; 13444498Sgibbs break; 135107178Snjl case 'b': 136107178Snjl buf_size = atoi(optarg); 137107178Snjl if (buf_size < 256 || buf_size > MAX_XFER) 138107178Snjl errx(1, "Unreasonable buf size: %s", optarg); 13944498Sgibbs break; 140107178Snjl case 'c': 141107178Snjl sector_size = atoi(optarg); 142107178Snjl if (sector_size < 512 || sector_size > MAX_SECTOR) 143107178Snjl errx(1, "Unreasonable sector size: %s", optarg); 14463185Smjacob break; 145107178Snjl case 's': 146121184Ssimokawa { 147121184Ssimokawa int last, shift = 0; 148121184Ssimokawa 149121184Ssimokawa last = strlen(optarg) - 1; 150121184Ssimokawa if (last > 0) { 151121184Ssimokawa switch (tolower(optarg[last])) { 152121184Ssimokawa case 'e': 153121184Ssimokawa shift += 10; 154121184Ssimokawa /* FALLTHROUGH */ 155121184Ssimokawa case 'p': 156121184Ssimokawa shift += 10; 157121184Ssimokawa /* FALLTHROUGH */ 158121184Ssimokawa case 't': 159121184Ssimokawa shift += 10; 160121184Ssimokawa /* FALLTHROUGH */ 161121184Ssimokawa case 'g': 162121184Ssimokawa shift += 10; 163121184Ssimokawa /* FALLTHROUGH */ 164121184Ssimokawa case 'm': 165121184Ssimokawa shift += 10; 166121184Ssimokawa /* FALLTHROUGH */ 167121184Ssimokawa case 'k': 168121184Ssimokawa shift += 10; 169121184Ssimokawa optarg[last] = 0; 170121184Ssimokawa break; 171121184Ssimokawa } 172121184Ssimokawa } 173107178Snjl user_size = strtoll(optarg, (char **)NULL, /*base*/10); 174121184Ssimokawa user_size <<= shift; 175107178Snjl if (user_size < 0) 176107178Snjl errx(1, "Unreasonable volume size: %s", optarg); 177107178Snjl break; 178121184Ssimokawa } 179107178Snjl case 'W': 180107178Snjl req_flags &= ~(SID_WBus16 | SID_WBus32); 181107178Snjl switch (atoi(optarg)) { 182107178Snjl case 8: 183107178Snjl /* Leave req_flags zeroed */ 184107178Snjl break; 185107178Snjl case 16: 186107178Snjl req_flags |= SID_WBus16; 187107178Snjl break; 188107178Snjl case 32: 189107178Snjl req_flags |= SID_WBus32; 190107178Snjl break; 191107178Snjl default: 192107178Snjl warnx("Width %s not supported", optarg); 193107178Snjl usage(); 194107178Snjl /* NOTREACHED */ 195107178Snjl } 196107178Snjl break; 197162704Smjacob case 'Y': 198162704Smjacob notaio = 1; 199162704Smjacob break; 20039215Sgibbs default: 20139215Sgibbs usage(); 20239215Sgibbs /* NOTREACHED */ 20339215Sgibbs } 20439215Sgibbs } 20539215Sgibbs argc -= optind; 20639215Sgibbs argv += optind; 207107178Snjl 208107178Snjl if (argc != 2) 20939215Sgibbs usage(); 21039215Sgibbs 211107178Snjl sscanf(argv[0], "%u:%u:%u", &ioc_enlun.path_id, &ioc_enlun.target_id, 212107178Snjl &ioc_enlun.lun_id); 213107178Snjl file_name = argv[1]; 214107178Snjl 215107178Snjl if (ioc_enlun.path_id == CAM_BUS_WILDCARD || 216107178Snjl ioc_enlun.target_id == CAM_TARGET_WILDCARD || 217107178Snjl ioc_enlun.lun_id == CAM_LUN_WILDCARD) { 218107178Snjl warnx("Incomplete target path specified"); 21944498Sgibbs usage(); 22044498Sgibbs /* NOTREACHED */ 22144498Sgibbs } 222107178Snjl /* We don't support any vendor-specific commands */ 223107178Snjl ioc_enlun.grp6_len = 0; 224107178Snjl ioc_enlun.grp7_len = 0; 22544498Sgibbs 226107178Snjl /* Open backing store for IO */ 227107178Snjl file_fd = open(file_name, O_RDWR); 228107178Snjl if (file_fd < 0) 229196955Ssbruno errx(EX_NOINPUT, "open backing store file"); 23044498Sgibbs 231107178Snjl /* Check backing store size or use the size user gave us */ 232107178Snjl if (user_size == 0) { 233107178Snjl struct stat st; 234107178Snjl 235107178Snjl if (fstat(file_fd, &st) < 0) 236107178Snjl err(1, "fstat file"); 237120428Ssimokawa#if __FreeBSD_version >= 500000 238120428Ssimokawa if ((st.st_mode & S_IFCHR) != 0) { 239120428Ssimokawa /* raw device */ 240120428Ssimokawa off_t mediasize; 241120428Ssimokawa if (ioctl(file_fd, DIOCGMEDIASIZE, &mediasize) < 0) 242120428Ssimokawa err(1, "DIOCGMEDIASIZE"); 243120428Ssimokawa 244120428Ssimokawa /* XXX get sector size by ioctl()?? */ 245120428Ssimokawa volume_size = mediasize / sector_size; 246120428Ssimokawa } else 247120428Ssimokawa#endif 248120428Ssimokawa volume_size = st.st_size / sector_size; 249107178Snjl } else { 250107178Snjl volume_size = user_size / sector_size; 25144498Sgibbs } 252121184Ssimokawa if (debug) 253162704Smjacob warnx("volume_size: %d bytes x " OFF_FMT " sectors", 254121184Ssimokawa sector_size, volume_size); 255121184Ssimokawa 256107178Snjl if (volume_size <= 0) 257107178Snjl errx(1, "volume must be larger than %d", sector_size); 25844498Sgibbs 259162704Smjacob if (notaio == 0) { 260109161Snjl struct aiocb aio, *aiop; 261109161Snjl 262162704Smjacob /* See if we have we have working AIO support */ 263109161Snjl memset(&aio, 0, sizeof(aio)); 264109161Snjl aio.aio_buf = malloc(sector_size); 265109161Snjl if (aio.aio_buf == NULL) 266109161Snjl err(1, "malloc"); 267109161Snjl aio.aio_fildes = file_fd; 268109161Snjl aio.aio_offset = 0; 269109161Snjl aio.aio_nbytes = sector_size; 270109161Snjl signal(SIGSYS, SIG_IGN); 271109161Snjl if (aio_read(&aio) != 0) { 272162704Smjacob printf("AIO support is not available- switchin to" 273162704Smjacob " single-threaded mode.\n"); 274162704Smjacob notaio = 1; 275162704Smjacob } else { 276162704Smjacob if (aio_waitcomplete(&aiop, NULL) != sector_size) 277162704Smjacob err(1, "aio_waitcomplete"); 278162704Smjacob assert(aiop == &aio); 279162704Smjacob signal(SIGSYS, SIG_DFL); 280109161Snjl } 281109161Snjl free((void *)aio.aio_buf); 282162704Smjacob if (debug && notaio == 0) 283109161Snjl warnx("aio support tested ok"); 284109161Snjl } 285109161Snjl 286228481Sed targ_fd = open("/dev/targ", O_RDWR); 287107178Snjl if (targ_fd < 0) 288228481Sed err(1, "/dev/targ"); 289196955Ssbruno else 290228481Sed warnx("opened /dev/targ"); 29163185Smjacob 292107178Snjl /* The first three are handled by kevent() later */ 293107178Snjl signal(SIGHUP, SIG_IGN); 294107178Snjl signal(SIGINT, SIG_IGN); 295107178Snjl signal(SIGTERM, SIG_IGN); 296107178Snjl signal(SIGPROF, SIG_IGN); 297107178Snjl signal(SIGALRM, SIG_IGN); 298107178Snjl signal(SIGSTOP, SIG_IGN); 299107178Snjl signal(SIGTSTP, SIG_IGN); 30039215Sgibbs 301107178Snjl /* Register a cleanup handler to run when exiting */ 302107178Snjl atexit(cleanup); 303107178Snjl 304107178Snjl /* Enable listening on the specified LUN */ 305107178Snjl if (ioctl(targ_fd, TARGIOCENABLE, &ioc_enlun) != 0) 306107178Snjl err(1, "TARGIOCENABLE"); 307107178Snjl 308107178Snjl /* Enable debugging if requested */ 309107178Snjl if (debug) { 310107178Snjl if (ioctl(targ_fd, TARGIOCDEBUG, &debug) != 0) 311162704Smjacob warnx("TARGIOCDEBUG"); 31239215Sgibbs } 31339215Sgibbs 314107178Snjl /* Set up inquiry data according to what SIM supports */ 315107178Snjl if (get_sim_flags(&sim_flags) != CAM_REQ_CMP) 316107178Snjl errx(1, "get_sim_flags"); 317196955Ssbruno 318107178Snjl if (tcmd_init(req_flags, sim_flags) != 0) 319107178Snjl errx(1, "Initializing tcmd subsystem failed"); 32044498Sgibbs 321107178Snjl /* Queue ATIOs and INOTs on descriptor */ 322107178Snjl if (init_ccbs() != 0) 323107178Snjl errx(1, "init_ccbs failed"); 32449935Sgibbs 325107178Snjl if (debug) 326107178Snjl warnx("main loop beginning"); 327196955Ssbruno 328107178Snjl request_loop(); 32939215Sgibbs 330107178Snjl exit(0); 33149935Sgibbs} 33249935Sgibbs 33349935Sgibbsstatic void 33449935Sgibbscleanup() 33549935Sgibbs{ 336107178Snjl struct ccb_hdr *ccb_h; 337107178Snjl 33863290Smjacob if (debug) { 339107178Snjl warnx("cleanup called"); 34063290Smjacob debug = 0; 341107178Snjl ioctl(targ_fd, TARGIOCDEBUG, &debug); 34263290Smjacob } 343107178Snjl ioctl(targ_fd, TARGIOCDISABLE, NULL); 344107178Snjl close(targ_fd); 345107178Snjl 346107178Snjl while ((ccb_h = TAILQ_FIRST(&pending_queue)) != NULL) { 347107178Snjl TAILQ_REMOVE(&pending_queue, ccb_h, periph_links.tqe); 348107178Snjl free_ccb((union ccb *)ccb_h); 34944498Sgibbs } 350107178Snjl while ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) { 351107178Snjl TAILQ_REMOVE(&work_queue, ccb_h, periph_links.tqe); 352107178Snjl free_ccb((union ccb *)ccb_h); 353107178Snjl } 354107178Snjl 355107178Snjl if (kq_fd != -1) 356107178Snjl close(kq_fd); 35739215Sgibbs} 35839215Sgibbs 359107178Snjl/* Allocate ATIOs/INOTs and queue on HBA */ 360107178Snjlstatic int 361107178Snjlinit_ccbs() 362107178Snjl{ 363107178Snjl int i; 364107178Snjl 365107178Snjl for (i = 0; i < MAX_INITIATORS; i++) { 366107178Snjl struct ccb_accept_tio *atio; 367107178Snjl struct atio_descr *a_descr; 368255120Smav struct ccb_immediate_notify *inot; 369107178Snjl 370107178Snjl atio = (struct ccb_accept_tio *)malloc(sizeof(*atio)); 371107178Snjl if (atio == NULL) { 372107178Snjl warn("malloc ATIO"); 373107178Snjl return (-1); 374107178Snjl } 375107178Snjl a_descr = (struct atio_descr *)malloc(sizeof(*a_descr)); 376107178Snjl if (a_descr == NULL) { 377107178Snjl free(atio); 378107178Snjl warn("malloc atio_descr"); 379107178Snjl return (-1); 380107178Snjl } 381107178Snjl atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 382107178Snjl atio->ccb_h.targ_descr = a_descr; 383107178Snjl send_ccb((union ccb *)atio, /*priority*/1); 384107178Snjl 385255120Smav inot = (struct ccb_immediate_notify *)malloc(sizeof(*inot)); 386107178Snjl if (inot == NULL) { 387107178Snjl warn("malloc INOT"); 388107178Snjl return (-1); 389107178Snjl } 390237601Sken inot->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; 391107178Snjl send_ccb((union ccb *)inot, /*priority*/1); 392107178Snjl } 393107178Snjl 394107178Snjl return (0); 395107178Snjl} 396107178Snjl 39739215Sgibbsstatic void 398107178Snjlrequest_loop() 39939215Sgibbs{ 400107178Snjl struct kevent events[MAX_EVENTS]; 401107178Snjl struct timespec ts, *tptr; 402107178Snjl int quit; 40339215Sgibbs 404107178Snjl /* Register kqueue for event notification */ 405107178Snjl if ((kq_fd = kqueue()) < 0) 406107178Snjl err(1, "init kqueue"); 40739215Sgibbs 408107178Snjl /* Set up some default events */ 409107178Snjl EV_SET(&events[0], SIGHUP, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); 410107178Snjl EV_SET(&events[1], SIGINT, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); 411107178Snjl EV_SET(&events[2], SIGTERM, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); 412107178Snjl EV_SET(&events[3], targ_fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); 413107178Snjl if (kevent(kq_fd, events, 4, NULL, 0, NULL) < 0) 414107178Snjl err(1, "kevent signal registration"); 415107178Snjl 416107178Snjl ts.tv_sec = 0; 417107178Snjl ts.tv_nsec = 0; 418107178Snjl tptr = NULL; 419107178Snjl quit = 0; 420107178Snjl 421107178Snjl /* Loop until user signal */ 42244498Sgibbs while (quit == 0) { 423162704Smjacob int retval, i, oo; 424107178Snjl struct ccb_hdr *ccb_h; 42539215Sgibbs 426107178Snjl /* Check for the next signal, read ready, or AIO completion */ 427107178Snjl retval = kevent(kq_fd, NULL, 0, events, MAX_EVENTS, tptr); 428107178Snjl if (retval < 0) { 429107178Snjl if (errno == EINTR) { 430107178Snjl if (debug) 431107178Snjl warnx("EINTR, looping"); 43244498Sgibbs continue; 433107178Snjl } 434107178Snjl else { 435107178Snjl err(1, "kevent failed"); 436107178Snjl } 437107178Snjl } else if (retval > MAX_EVENTS) { 438107178Snjl errx(1, "kevent returned more events than allocated?"); 43939215Sgibbs } 44039215Sgibbs 441107178Snjl /* Process all received events. */ 442162704Smjacob for (oo = i = 0; i < retval; i++) { 443107178Snjl if ((events[i].flags & EV_ERROR) != 0) 444107178Snjl errx(1, "kevent registration failed"); 44539215Sgibbs 446107178Snjl switch (events[i].filter) { 447107178Snjl case EVFILT_READ: 448107178Snjl if (debug) 449107178Snjl warnx("read ready"); 450107178Snjl handle_read(); 451107178Snjl break; 452107178Snjl case EVFILT_AIO: 453107178Snjl { 454107178Snjl struct ccb_scsiio *ctio; 455107178Snjl struct ctio_descr *c_descr; 456107178Snjl if (debug) 457107178Snjl warnx("aio ready"); 45839215Sgibbs 459107178Snjl ctio = (struct ccb_scsiio *)events[i].udata; 460107178Snjl c_descr = (struct ctio_descr *) 461107178Snjl ctio->ccb_h.targ_descr; 462107178Snjl c_descr->event = AIO_DONE; 463107178Snjl /* Queue on the appropriate ATIO */ 464107178Snjl queue_io(ctio); 465107178Snjl /* Process any queued completions. */ 466162704Smjacob oo += run_queue(c_descr->atio); 467107178Snjl break; 468107178Snjl } 469107178Snjl case EVFILT_SIGNAL: 470107178Snjl if (debug) 471107178Snjl warnx("signal ready, setting quit"); 472107178Snjl quit = 1; 473107178Snjl break; 474107178Snjl default: 475162704Smjacob warnx("unknown event %d", events[i].filter); 476107178Snjl break; 477107178Snjl } 478107178Snjl 479107178Snjl if (debug) 480162704Smjacob warnx("event %d done", events[i].filter); 48139215Sgibbs } 48239215Sgibbs 483162704Smjacob if (oo) { 484162704Smjacob tptr = &ts; 485162704Smjacob continue; 486162704Smjacob } 487162704Smjacob 488107178Snjl /* Grab the first CCB and perform one work unit. */ 489107178Snjl if ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) { 490107178Snjl union ccb *ccb; 49139215Sgibbs 492107178Snjl ccb = (union ccb *)ccb_h; 493107178Snjl switch (ccb_h->func_code) { 494107178Snjl case XPT_ACCEPT_TARGET_IO: 495107178Snjl /* Start one more transfer. */ 496107178Snjl retval = work_atio(&ccb->atio); 497107178Snjl break; 498237601Sken case XPT_IMMEDIATE_NOTIFY: 499237601Sken retval = work_inot(&ccb->cin1); 500107178Snjl break; 501107178Snjl default: 502107178Snjl warnx("Unhandled ccb type %#x on workq", 503107178Snjl ccb_h->func_code); 504107178Snjl abort(); 505107178Snjl /* NOTREACHED */ 50639215Sgibbs } 50739215Sgibbs 508107178Snjl /* Assume work function handled the exception */ 509107178Snjl if ((ccb_h->status & CAM_DEV_QFRZN) != 0) { 510109345Snjl if (debug) { 511109345Snjl warnx("Queue frozen receiving CCB, " 512109345Snjl "releasing"); 513109345Snjl } 514107178Snjl rel_simq(); 51539215Sgibbs } 51639215Sgibbs 517107178Snjl /* No more work needed for this command. */ 518107178Snjl if (retval == 0) { 519107178Snjl TAILQ_REMOVE(&work_queue, ccb_h, 520107178Snjl periph_links.tqe); 52139215Sgibbs } 522107178Snjl } 52339215Sgibbs 524107178Snjl /* 525107178Snjl * Poll for new events (i.e. completions) while we 526107178Snjl * are processing CCBs on the work_queue. Once it's 527107178Snjl * empty, use an infinite wait. 528107178Snjl */ 529107178Snjl if (!TAILQ_EMPTY(&work_queue)) 530107178Snjl tptr = &ts; 531107178Snjl else 532107178Snjl tptr = NULL; 53339215Sgibbs } 53439215Sgibbs} 53539215Sgibbs 536107178Snjl/* CCBs are ready from the kernel */ 53739215Sgibbsstatic void 538107178Snjlhandle_read() 53939215Sgibbs{ 540107178Snjl union ccb *ccb_array[MAX_INITIATORS], *ccb; 541162704Smjacob int ccb_count, i, oo; 54239215Sgibbs 543107178Snjl ccb_count = read(targ_fd, ccb_array, sizeof(ccb_array)); 544107178Snjl if (ccb_count <= 0) { 545107178Snjl warn("read ccb ptrs"); 546107178Snjl return; 54739215Sgibbs } 548107178Snjl ccb_count /= sizeof(union ccb *); 549107178Snjl if (ccb_count < 1) { 550107178Snjl warnx("truncated read ccb ptr?"); 551107178Snjl return; 552107178Snjl } 55339215Sgibbs 554107178Snjl for (i = 0; i < ccb_count; i++) { 555107178Snjl ccb = ccb_array[i]; 556107178Snjl TAILQ_REMOVE(&pending_queue, &ccb->ccb_h, periph_links.tqe); 557107178Snjl 558107178Snjl switch (ccb->ccb_h.func_code) { 559107178Snjl case XPT_ACCEPT_TARGET_IO: 560107178Snjl { 561107178Snjl struct ccb_accept_tio *atio; 562107178Snjl struct atio_descr *a_descr; 563107178Snjl 564107178Snjl /* Initialize ATIO descr for this transaction */ 565107178Snjl atio = &ccb->atio; 566107178Snjl a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; 567107178Snjl bzero(a_descr, sizeof(*a_descr)); 568107178Snjl TAILQ_INIT(&a_descr->cmplt_io); 569107178Snjl a_descr->flags = atio->ccb_h.flags & 570107178Snjl (CAM_DIS_DISCONNECT | CAM_TAG_ACTION_VALID); 571107178Snjl /* XXX add a_descr->priority */ 572107178Snjl if ((atio->ccb_h.flags & CAM_CDB_POINTER) == 0) 573107178Snjl a_descr->cdb = atio->cdb_io.cdb_bytes; 574107178Snjl else 575107178Snjl a_descr->cdb = atio->cdb_io.cdb_ptr; 576107178Snjl 577107178Snjl /* ATIOs are processed in FIFO order */ 578107178Snjl TAILQ_INSERT_TAIL(&work_queue, &ccb->ccb_h, 579107178Snjl periph_links.tqe); 580107178Snjl break; 581107178Snjl } 582107178Snjl case XPT_CONT_TARGET_IO: 583107178Snjl { 584107178Snjl struct ccb_scsiio *ctio; 585107178Snjl struct ctio_descr *c_descr; 586107178Snjl 587107178Snjl ctio = &ccb->ctio; 588107178Snjl c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; 589107178Snjl c_descr->event = CTIO_DONE; 590107178Snjl /* Queue on the appropriate ATIO */ 591107178Snjl queue_io(ctio); 592107178Snjl /* Process any queued completions. */ 593162704Smjacob oo += run_queue(c_descr->atio); 594107178Snjl break; 595107178Snjl } 596255120Smav case XPT_IMMEDIATE_NOTIFY: 597107178Snjl /* INOTs are handled with priority */ 598107178Snjl TAILQ_INSERT_HEAD(&work_queue, &ccb->ccb_h, 599107178Snjl periph_links.tqe); 600107178Snjl break; 601107178Snjl default: 602107178Snjl warnx("Unhandled ccb type %#x in handle_read", 603107178Snjl ccb->ccb_h.func_code); 604107178Snjl break; 605107178Snjl } 60639215Sgibbs } 607107178Snjl} 60839215Sgibbs 609107178Snjl/* Process an ATIO CCB from the kernel */ 610107178Snjlint 611107178Snjlwork_atio(struct ccb_accept_tio *atio) 612107178Snjl{ 613107178Snjl struct ccb_scsiio *ctio; 614107178Snjl struct atio_descr *a_descr; 615107178Snjl struct ctio_descr *c_descr; 616107178Snjl cam_status status; 617107178Snjl int ret; 618107178Snjl 619107178Snjl if (debug) 620107178Snjl warnx("Working on ATIO %p", atio); 621107178Snjl 622107178Snjl a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; 623107178Snjl 624107178Snjl /* Get a CTIO and initialize it according to our known parameters */ 625107178Snjl ctio = get_ctio(); 626162704Smjacob if (ctio == NULL) { 627107178Snjl return (1); 628162704Smjacob } 629107178Snjl ret = 0; 630107178Snjl ctio->ccb_h.flags = a_descr->flags; 631107178Snjl ctio->tag_id = atio->tag_id; 632107178Snjl ctio->init_id = atio->init_id; 633107178Snjl /* XXX priority needs to be added to a_descr */ 634107178Snjl c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; 635107178Snjl c_descr->atio = atio; 636107178Snjl if ((a_descr->flags & CAM_DIR_IN) != 0) 637107178Snjl c_descr->offset = a_descr->base_off + a_descr->targ_req; 638107178Snjl else if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) 639107178Snjl c_descr->offset = a_descr->base_off + a_descr->init_req; 640120428Ssimokawa else 641120428Ssimokawa c_descr->offset = a_descr->base_off; 642107178Snjl 643107178Snjl /* 644107178Snjl * Return a check condition if there was an error while 645107178Snjl * receiving this ATIO. 646107178Snjl */ 647107178Snjl if (atio->sense_len != 0) { 648225950Sken struct scsi_sense_data_fixed *sense; 64939215Sgibbs 650107178Snjl if (debug) { 651107178Snjl warnx("ATIO with %u bytes sense received", 652107178Snjl atio->sense_len); 65339215Sgibbs } 654237601Sken sense = (struct scsi_sense_data_fixed *)&atio->sense_data; 655107178Snjl tcmd_sense(ctio->init_id, ctio, sense->flags, 656107178Snjl sense->add_sense_code, sense->add_sense_code_qual); 657107178Snjl send_ccb((union ccb *)ctio, /*priority*/1); 658107178Snjl return (0); 659107178Snjl } 66039215Sgibbs 661107178Snjl status = atio->ccb_h.status & CAM_STATUS_MASK; 662107178Snjl switch (status) { 663107178Snjl case CAM_CDB_RECVD: 664107178Snjl ret = tcmd_handle(atio, ctio, ATIO_WORK); 665107178Snjl break; 666107178Snjl case CAM_REQ_ABORTED: 667162704Smjacob warn("ATIO %p aborted", a_descr); 668107178Snjl /* Requeue on HBA */ 669107178Snjl TAILQ_REMOVE(&work_queue, &atio->ccb_h, periph_links.tqe); 670107178Snjl send_ccb((union ccb *)atio, /*priority*/1); 671107178Snjl ret = 1; 672107178Snjl break; 673107178Snjl default: 674107178Snjl warnx("ATIO completed with unhandled status %#x", status); 675107178Snjl abort(); 676107178Snjl /* NOTREACHED */ 677107178Snjl break; 678107178Snjl } 67939215Sgibbs 680107178Snjl return (ret); 681107178Snjl} 68239215Sgibbs 683107178Snjlstatic void 684107178Snjlqueue_io(struct ccb_scsiio *ctio) 685107178Snjl{ 686107178Snjl struct ccb_hdr *ccb_h; 687107178Snjl struct io_queue *ioq; 688162704Smjacob struct ctio_descr *c_descr; 689107178Snjl 690107178Snjl c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; 691162704Smjacob if (c_descr->atio == NULL) { 692107178Snjl errx(1, "CTIO %p has NULL ATIO", ctio); 693107178Snjl } 694162704Smjacob ioq = &((struct atio_descr *)c_descr->atio->ccb_h.targ_descr)->cmplt_io; 695107178Snjl 696162704Smjacob if (TAILQ_EMPTY(ioq)) { 697162704Smjacob TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe); 698162704Smjacob return; 699162704Smjacob } 700162704Smjacob 701162704Smjacob TAILQ_FOREACH_REVERSE(ccb_h, ioq, io_queue, periph_links.tqe) { 702162704Smjacob struct ctio_descr *curr_descr = 703162704Smjacob (struct ctio_descr *)ccb_h->targ_descr; 704162704Smjacob if (curr_descr->offset <= c_descr->offset) { 705162704Smjacob break; 70639215Sgibbs } 707162704Smjacob } 708162704Smjacob 709162704Smjacob if (ccb_h) { 710162704Smjacob TAILQ_INSERT_AFTER(ioq, ccb_h, &ctio->ccb_h, periph_links.tqe); 711107178Snjl } else { 712107178Snjl TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe); 713107178Snjl } 714107178Snjl} 71539215Sgibbs 716107178Snjl/* 717107178Snjl * Go through all completed AIO/CTIOs for a given ATIO and advance data 718107178Snjl * counts, start continuation IO, etc. 719107178Snjl */ 720162704Smjacobstatic int 721107178Snjlrun_queue(struct ccb_accept_tio *atio) 722107178Snjl{ 723107178Snjl struct atio_descr *a_descr; 724107178Snjl struct ccb_hdr *ccb_h; 725107178Snjl int sent_status, event; 726107178Snjl 727107178Snjl if (atio == NULL) 728162704Smjacob return (0); 729107178Snjl 730107178Snjl a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; 731107178Snjl 732107178Snjl while ((ccb_h = TAILQ_FIRST(&a_descr->cmplt_io)) != NULL) { 733107178Snjl struct ccb_scsiio *ctio; 734107178Snjl struct ctio_descr *c_descr; 735107178Snjl 736107178Snjl ctio = (struct ccb_scsiio *)ccb_h; 737107178Snjl c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; 738107178Snjl 739120428Ssimokawa if (ctio->ccb_h.status == CAM_REQ_ABORTED) { 740120428Ssimokawa TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h, 741120428Ssimokawa periph_links.tqe); 742120428Ssimokawa free_ccb((union ccb *)ctio); 743120428Ssimokawa send_ccb((union ccb *)atio, /*priority*/1); 744120428Ssimokawa continue; 745120428Ssimokawa } 746120428Ssimokawa 747107178Snjl /* If completed item is in range, call handler */ 748107178Snjl if ((c_descr->event == AIO_DONE && 749107178Snjl c_descr->offset == a_descr->base_off + a_descr->targ_ack) 750107178Snjl || (c_descr->event == CTIO_DONE && 751107178Snjl c_descr->offset == a_descr->base_off + a_descr->init_ack)) { 752107178Snjl sent_status = (ccb_h->flags & CAM_SEND_STATUS) != 0; 753107178Snjl event = c_descr->event; 754107178Snjl 755107178Snjl TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h, 756107178Snjl periph_links.tqe); 757107178Snjl tcmd_handle(atio, ctio, c_descr->event); 758107178Snjl 759107178Snjl /* If entire transfer complete, send back ATIO */ 760107178Snjl if (sent_status != 0 && event == CTIO_DONE) 761107178Snjl send_ccb((union ccb *)atio, /*priority*/1); 762107178Snjl } else { 763107178Snjl /* Gap in offsets so wait until later callback */ 764162704Smjacob if (/* debug */ 1) 765162704Smjacob warnx("IO %p:%p out of order %s", ccb_h, 766162704Smjacob a_descr, c_descr->event == AIO_DONE? 767162704Smjacob "aio" : "ctio"); 768162704Smjacob return (1); 76963185Smjacob } 770107178Snjl } 771162704Smjacob return (0); 772107178Snjl} 77363185Smjacob 774107178Snjlstatic int 775237601Skenwork_inot(struct ccb_immediate_notify *inot) 776107178Snjl{ 777107178Snjl cam_status status; 77863185Smjacob 779107178Snjl if (debug) 780107178Snjl warnx("Working on INOT %p", inot); 781107178Snjl 782107178Snjl status = inot->ccb_h.status; 783107178Snjl status &= CAM_STATUS_MASK; 784107178Snjl 785107178Snjl switch (status) { 786107178Snjl case CAM_SCSI_BUS_RESET: 787107178Snjl tcmd_ua(CAM_TARGET_WILDCARD, UA_BUS_RESET); 788107178Snjl abort_all_pending(); 789107178Snjl break; 790107178Snjl case CAM_BDR_SENT: 791107178Snjl tcmd_ua(CAM_TARGET_WILDCARD, UA_BDR); 792107178Snjl abort_all_pending(); 793107178Snjl break; 794107178Snjl case CAM_MESSAGE_RECV: 795237601Sken switch (inot->arg) { 796107178Snjl case MSG_TASK_COMPLETE: 797107178Snjl case MSG_INITIATOR_DET_ERR: 798107178Snjl case MSG_ABORT_TASK_SET: 799107178Snjl case MSG_MESSAGE_REJECT: 800107178Snjl case MSG_NOOP: 801107178Snjl case MSG_PARITY_ERROR: 802107178Snjl case MSG_TARGET_RESET: 803107178Snjl case MSG_ABORT_TASK: 804107178Snjl case MSG_CLEAR_TASK_SET: 805107178Snjl default: 806237601Sken warnx("INOT message %#x", inot->arg); 807107178Snjl break; 80839215Sgibbs } 809107178Snjl break; 810107178Snjl case CAM_REQ_ABORTED: 811107178Snjl warnx("INOT %p aborted", inot); 812107178Snjl break; 813107178Snjl default: 814107178Snjl warnx("Unhandled INOT status %#x", status); 815107178Snjl break; 81639215Sgibbs } 81739215Sgibbs 818107178Snjl /* Requeue on SIM */ 819107178Snjl TAILQ_REMOVE(&work_queue, &inot->ccb_h, periph_links.tqe); 820107178Snjl send_ccb((union ccb *)inot, /*priority*/1); 821107178Snjl 822107178Snjl return (1); 82339215Sgibbs} 82439215Sgibbs 825107178Snjlvoid 826107178Snjlsend_ccb(union ccb *ccb, int priority) 827107178Snjl{ 828107178Snjl if (debug) 829107178Snjl warnx("sending ccb (%#x)", ccb->ccb_h.func_code); 830107178Snjl ccb->ccb_h.pinfo.priority = priority; 831107178Snjl if (XPT_FC_IS_QUEUED(ccb)) { 832107178Snjl TAILQ_INSERT_TAIL(&pending_queue, &ccb->ccb_h, 833107178Snjl periph_links.tqe); 834107178Snjl } 835107178Snjl if (write(targ_fd, &ccb, sizeof(ccb)) != sizeof(ccb)) { 836107178Snjl warn("write ccb"); 837107178Snjl ccb->ccb_h.status = CAM_PROVIDE_FAIL; 838107178Snjl } 839107178Snjl} 840107178Snjl 841107178Snjl/* Return a CTIO/descr/buf combo from the freelist or malloc one */ 842107178Snjlstatic struct ccb_scsiio * 843107178Snjlget_ctio() 844107178Snjl{ 845107178Snjl struct ccb_scsiio *ctio; 846107178Snjl struct ctio_descr *c_descr; 847107178Snjl struct sigevent *se; 848107178Snjl 849162704Smjacob if (num_ctios == MAX_CTIOS) { 850162704Smjacob warnx("at CTIO max"); 851107178Snjl return (NULL); 852162704Smjacob } 853107178Snjl 854107178Snjl ctio = (struct ccb_scsiio *)malloc(sizeof(*ctio)); 855107178Snjl if (ctio == NULL) { 856107178Snjl warn("malloc CTIO"); 857107178Snjl return (NULL); 858107178Snjl } 859107178Snjl c_descr = (struct ctio_descr *)malloc(sizeof(*c_descr)); 860107178Snjl if (c_descr == NULL) { 861107178Snjl free(ctio); 862107178Snjl warn("malloc ctio_descr"); 863107178Snjl return (NULL); 864107178Snjl } 865107178Snjl c_descr->buf = malloc(buf_size); 866107178Snjl if (c_descr->buf == NULL) { 867107178Snjl free(c_descr); 868107178Snjl free(ctio); 869107178Snjl warn("malloc backing store"); 870107178Snjl return (NULL); 871107178Snjl } 872107178Snjl num_ctios++; 873107178Snjl 874107178Snjl /* Initialize CTIO, CTIO descr, and AIO */ 875107178Snjl ctio->ccb_h.func_code = XPT_CONT_TARGET_IO; 876107178Snjl ctio->ccb_h.retry_count = 2; 877109345Snjl ctio->ccb_h.timeout = CAM_TIME_INFINITY; 878107178Snjl ctio->data_ptr = c_descr->buf; 879107178Snjl ctio->ccb_h.targ_descr = c_descr; 880107178Snjl c_descr->aiocb.aio_buf = c_descr->buf; 881107178Snjl c_descr->aiocb.aio_fildes = file_fd; 882107178Snjl se = &c_descr->aiocb.aio_sigevent; 883107178Snjl se->sigev_notify = SIGEV_KEVENT; 884107178Snjl se->sigev_notify_kqueue = kq_fd; 885157009Smjacob se->sigev_value.sival_ptr = ctio; 886107178Snjl 887107178Snjl return (ctio); 888107178Snjl} 889107178Snjl 890107178Snjlvoid 891107178Snjlfree_ccb(union ccb *ccb) 892107178Snjl{ 893107178Snjl switch (ccb->ccb_h.func_code) { 894107178Snjl case XPT_CONT_TARGET_IO: 895107178Snjl { 896107178Snjl struct ctio_descr *c_descr; 897107178Snjl 898107178Snjl c_descr = (struct ctio_descr *)ccb->ccb_h.targ_descr; 899107178Snjl free(c_descr->buf); 900107178Snjl num_ctios--; 901107178Snjl /* FALLTHROUGH */ 902107178Snjl } 903107178Snjl case XPT_ACCEPT_TARGET_IO: 904107178Snjl free(ccb->ccb_h.targ_descr); 905107178Snjl /* FALLTHROUGH */ 906255120Smav case XPT_IMMEDIATE_NOTIFY: 907107178Snjl default: 908107178Snjl free(ccb); 909107178Snjl break; 910107178Snjl } 911107178Snjl} 912107178Snjl 913107178Snjlstatic cam_status 914107178Snjlget_sim_flags(u_int16_t *flags) 915107178Snjl{ 916107178Snjl struct ccb_pathinq cpi; 917107178Snjl cam_status status; 918107178Snjl 919107178Snjl /* Find SIM capabilities */ 920107178Snjl bzero(&cpi, sizeof(cpi)); 921107178Snjl cpi.ccb_h.func_code = XPT_PATH_INQ; 922107178Snjl send_ccb((union ccb *)&cpi, /*priority*/1); 923107178Snjl status = cpi.ccb_h.status & CAM_STATUS_MASK; 924107178Snjl if (status != CAM_REQ_CMP) { 925107178Snjl fprintf(stderr, "CPI failed, status %#x\n", status); 926107178Snjl return (status); 927107178Snjl } 928107178Snjl 929107178Snjl /* Can only enable on controllers that support target mode */ 930107178Snjl if ((cpi.target_sprt & PIT_PROCESSOR) == 0) { 931107178Snjl fprintf(stderr, "HBA does not support target mode\n"); 932107178Snjl status = CAM_PATH_INVALID; 933107178Snjl return (status); 934107178Snjl } 935107178Snjl 936107178Snjl *flags = cpi.hba_inquiry; 937107178Snjl return (status); 938107178Snjl} 939107178Snjl 94039215Sgibbsstatic void 941107178Snjlrel_simq() 94244498Sgibbs{ 943107178Snjl struct ccb_relsim crs; 944107178Snjl 945107178Snjl bzero(&crs, sizeof(crs)); 946107178Snjl crs.ccb_h.func_code = XPT_REL_SIMQ; 947107178Snjl crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; 948107178Snjl crs.openings = 0; 949107178Snjl crs.release_timeout = 0; 950107178Snjl crs.qfrozen_cnt = 0; 951107178Snjl send_ccb((union ccb *)&crs, /*priority*/0); 95244498Sgibbs} 95344498Sgibbs 954107178Snjl/* Cancel all pending CCBs. */ 95544498Sgibbsstatic void 956107178Snjlabort_all_pending() 95739215Sgibbs{ 958107178Snjl struct ccb_abort cab; 959107178Snjl struct ccb_hdr *ccb_h; 96039215Sgibbs 961107178Snjl if (debug) 962107178Snjl warnx("abort_all_pending"); 96339215Sgibbs 964107178Snjl bzero(&cab, sizeof(cab)); 965107178Snjl cab.ccb_h.func_code = XPT_ABORT; 966107178Snjl TAILQ_FOREACH(ccb_h, &pending_queue, periph_links.tqe) { 967107178Snjl if (debug) 968107178Snjl warnx("Aborting pending CCB %p\n", ccb_h); 969107178Snjl cab.abort_ccb = (union ccb *)ccb_h; 970107178Snjl send_ccb((union ccb *)&cab, /*priority*/1); 971107178Snjl if (cab.ccb_h.status != CAM_REQ_CMP) { 972107178Snjl warnx("Unable to abort CCB, status %#x\n", 973107178Snjl cab.ccb_h.status); 974107178Snjl } 975107178Snjl } 97639215Sgibbs} 97739215Sgibbs 978107178Snjlstatic void 979107178Snjlusage() 980107178Snjl{ 981107178Snjl fprintf(stderr, 982162704Smjacob "Usage: scsi_target [-AdSTY] [-b bufsize] [-c sectorsize]\n" 983107178Snjl "\t\t[-r numbufs] [-s volsize] [-W 8,16,32]\n" 984107178Snjl "\t\tbus:target:lun filename\n"); 985107178Snjl exit(1); 986107178Snjl} 987