scsi_target.c revision 50476
139215Sgibbs/* 239215Sgibbs * Sample program to attach to the "targ" processor target, target mode 339215Sgibbs * peripheral driver and push or receive data. 439215Sgibbs * 539215Sgibbs * Copyright (c) 1998 Justin T. Gibbs. 639215Sgibbs * All rights reserved. 739215Sgibbs * 839215Sgibbs * Redistribution and use in source and binary forms, with or without 939215Sgibbs * modification, are permitted provided that the following conditions 1039215Sgibbs * are met: 1139215Sgibbs * 1. Redistributions of source code must retain the above copyright 1239215Sgibbs * notice, this list of conditions, and the following disclaimer, 1339215Sgibbs * without modification, immediately at the beginning of the file. 1439215Sgibbs * 2. The name of the author may not be used to endorse or promote products 1539215Sgibbs * derived from this software without specific prior written permission. 1639215Sgibbs * 1739215Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1839215Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1939215Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2039215Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2139215Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2239215Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2339215Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2439215Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2539215Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2639215Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2739215Sgibbs * SUCH DAMAGE. 2839215Sgibbs * 2950476Speter * $FreeBSD: head/share/examples/scsi_target/scsi_target.c 50476 1999-08-28 00:22:10Z peter $ 3039215Sgibbs */ 3139215Sgibbs 3239215Sgibbs#include <sys/types.h> 3339215Sgibbs 3444498Sgibbs#include <errno.h> 3539215Sgibbs#include <fcntl.h> 3639215Sgibbs#include <poll.h> 3744498Sgibbs#include <signal.h> 3839215Sgibbs#include <stddef.h> 3939215Sgibbs#include <stdio.h> 4039215Sgibbs#include <stdlib.h> 4139215Sgibbs#include <sysexits.h> 4239215Sgibbs#include <unistd.h> 4339215Sgibbs 4439215Sgibbs#include <cam/scsi/scsi_all.h> 4539215Sgibbs#include <cam/scsi/scsi_message.h> 4639215Sgibbs#include <cam/scsi/scsi_targetio.h> 4739215Sgibbs 4844498Sgibbschar *appname; 4944498Sgibbsint ifd; 5044498Sgibbschar *ifilename; 5144498Sgibbsint ofd; 5244498Sgibbschar *ofilename; 5344498Sgibbssize_t bufsize = 64 * 1024; 5444498Sgibbsvoid *buf; 5544498Sgibbschar targdevname[80]; 5644498Sgibbsint targctlfd; 5744498Sgibbsint targfd; 5844498Sgibbsint quit; 5944498Sgibbsstruct ioc_alloc_unit alloc_unit = { 6044498Sgibbs CAM_BUS_WILDCARD, 6144498Sgibbs CAM_TARGET_WILDCARD, 6244498Sgibbs CAM_LUN_WILDCARD 6344498Sgibbs}; 6439215Sgibbs 6539215Sgibbsstatic void pump_events(); 6649935Sgibbsstatic void cleanup(); 6739215Sgibbsstatic void handle_exception(); 6844498Sgibbsstatic void quit_handler(); 6939215Sgibbsstatic void usage(); 7039215Sgibbs 7139215Sgibbsint 7239215Sgibbsmain(int argc, char *argv[]) 7339215Sgibbs{ 7439215Sgibbs int ch; 7539215Sgibbs 7639215Sgibbs appname = *argv; 7744498Sgibbs while ((ch = getopt(argc, argv, "i:o:p:t:l:")) != -1) { 7839215Sgibbs switch(ch) { 7939215Sgibbs case 'i': 8039215Sgibbs if ((ifd = open(optarg, O_RDONLY)) == -1) { 8139215Sgibbs perror(optarg); 8239215Sgibbs exit(EX_NOINPUT); 8339215Sgibbs } 8439215Sgibbs ifilename = optarg; 8539215Sgibbs break; 8639215Sgibbs case 'o': 8739215Sgibbs if ((ofd = open(optarg, 8839215Sgibbs O_WRONLY|O_CREAT), 0600) == -1) { 8939215Sgibbs perror(optarg); 9039215Sgibbs exit(EX_CANTCREAT); 9139215Sgibbs } 9239215Sgibbs ofilename = optarg; 9339215Sgibbs break; 9444498Sgibbs case 'p': 9544498Sgibbs alloc_unit.path_id = atoi(optarg); 9644498Sgibbs break; 9744498Sgibbs case 't': 9844498Sgibbs alloc_unit.target_id = atoi(optarg); 9944498Sgibbs break; 10044498Sgibbs case 'l': 10144498Sgibbs alloc_unit.lun_id = atoi(optarg); 10244498Sgibbs break; 10339215Sgibbs case '?': 10439215Sgibbs default: 10539215Sgibbs usage(); 10639215Sgibbs /* NOTREACHED */ 10739215Sgibbs } 10839215Sgibbs } 10939215Sgibbs argc -= optind; 11039215Sgibbs argv += optind; 11139215Sgibbs 11244498Sgibbs if (alloc_unit.path_id == CAM_BUS_WILDCARD 11344498Sgibbs || alloc_unit.target_id == CAM_TARGET_WILDCARD 11444498Sgibbs || alloc_unit.lun_id == CAM_LUN_WILDCARD) { 11544498Sgibbs fprintf(stderr, "%s: Incomplete device path specifiled\n", 11644498Sgibbs appname); 11739215Sgibbs usage(); 11839215Sgibbs /* NOTREACHED */ 11939215Sgibbs } 12039215Sgibbs 12144498Sgibbs if (argc != 0) { 12244498Sgibbs fprintf(stderr, "%s: Too many arguments\n", appname); 12344498Sgibbs usage(); 12444498Sgibbs /* NOTREACHED */ 12544498Sgibbs } 12644498Sgibbs 12744498Sgibbs /* Allocate a new instance */ 12844498Sgibbs if ((targctlfd = open("/dev/targ.ctl", O_RDWR)) == -1) { 12944498Sgibbs perror("/dev/targ.ctl"); 13044498Sgibbs exit(EX_UNAVAILABLE); 13144498Sgibbs } 13244498Sgibbs 13344498Sgibbs if (ioctl(targctlfd, TARGCTLIOALLOCUNIT, &alloc_unit) == -1) { 13444498Sgibbs perror("TARGCTLIOALLOCUNIT"); 13544498Sgibbs exit(EX_SOFTWARE); 13644498Sgibbs } 13744498Sgibbs 13844498Sgibbs snprintf(targdevname, sizeof(targdevname), "/dev/targ%d", 13944498Sgibbs alloc_unit.unit); 14044498Sgibbs 14139215Sgibbs if ((targfd = open(targdevname, O_RDWR)) == -1) { 14239215Sgibbs perror(targdevname); 14344498Sgibbs ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit); 14439215Sgibbs exit(EX_NOINPUT); 14539215Sgibbs } 14639215Sgibbs 14739215Sgibbs buf = malloc(bufsize); 14839215Sgibbs 14939215Sgibbs if (buf == NULL) { 15039215Sgibbs fprintf(stderr, "%s: Could not malloc I/O buffer", appname); 15139215Sgibbs exit(EX_OSERR); 15239215Sgibbs } 15339215Sgibbs 15444498Sgibbs signal(SIGHUP, quit_handler); 15544498Sgibbs signal(SIGINT, quit_handler); 15644498Sgibbs signal(SIGTERM, quit_handler); 15744498Sgibbs 15849935Sgibbs atexit(cleanup); 15949935Sgibbs 16039215Sgibbs pump_events(); 16139215Sgibbs 16249935Sgibbs return (0); 16349935Sgibbs} 16449935Sgibbs 16549935Sgibbsstatic void 16649935Sgibbscleanup() 16749935Sgibbs{ 16844498Sgibbs close(targfd); 16944498Sgibbs 17044498Sgibbs if (ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit) == -1) { 17144498Sgibbs perror("TARGCTLIOFREEUNIT"); 17244498Sgibbs exit(EX_SOFTWARE); 17344498Sgibbs } 17444498Sgibbs 17544498Sgibbs close(targctlfd); 17639215Sgibbs} 17739215Sgibbs 17839215Sgibbsstatic void 17939215Sgibbspump_events() 18039215Sgibbs{ 18139215Sgibbs struct pollfd targpoll; 18239215Sgibbs 18339215Sgibbs targpoll.fd = targfd; 18439215Sgibbs targpoll.events = POLLRDNORM|POLLWRNORM; 18539215Sgibbs 18644498Sgibbs while (quit == 0) { 18739215Sgibbs int retval; 18839215Sgibbs 18939215Sgibbs retval = poll(&targpoll, 1, INFTIM); 19039215Sgibbs 19139215Sgibbs if (retval == -1) { 19244498Sgibbs if (errno == EINTR) 19344498Sgibbs continue; 19439215Sgibbs perror("Poll Failed"); 19539215Sgibbs exit(EX_SOFTWARE); 19639215Sgibbs } 19739215Sgibbs 19839215Sgibbs if (retval == 0) { 19939215Sgibbs perror("Poll returned 0 although timeout infinite???"); 20039215Sgibbs exit(EX_SOFTWARE); 20139215Sgibbs } 20239215Sgibbs 20339215Sgibbs if (retval > 1) { 20439215Sgibbs perror("Poll returned more fds ready than allocated"); 20539215Sgibbs exit(EX_SOFTWARE); 20639215Sgibbs } 20739215Sgibbs 20839215Sgibbs /* Process events */ 20939215Sgibbs if ((targpoll.revents & POLLERR) != 0) { 21039215Sgibbs handle_exception(); 21139215Sgibbs } 21239215Sgibbs 21339215Sgibbs if ((targpoll.revents & POLLRDNORM) != 0) { 21439215Sgibbs retval = read(targfd, buf, bufsize); 21539215Sgibbs 21639215Sgibbs if (retval == -1) { 21739215Sgibbs perror("Read from targ failed"); 21849935Sgibbs /* Go look for exceptions */ 21949935Sgibbs continue; 22039215Sgibbs } else { 22139215Sgibbs retval = write(ofd, buf, retval); 22239215Sgibbs if (retval == -1) { 22339215Sgibbs perror("Write to file failed"); 22439215Sgibbs } 22539215Sgibbs } 22639215Sgibbs } 22739215Sgibbs 22839215Sgibbs if ((targpoll.revents & POLLWRNORM) != 0) { 22939215Sgibbs int amount_read; 23039215Sgibbs 23139215Sgibbs retval = read(ifd, buf, bufsize); 23239215Sgibbs if (retval == -1) { 23339215Sgibbs perror("Read from file failed"); 23439215Sgibbs exit(EX_SOFTWARE); 23539215Sgibbs } 23639215Sgibbs 23739215Sgibbs amount_read = retval; 23839215Sgibbs retval = write(targfd, buf, retval); 23939215Sgibbs if (retval == -1) { 24039215Sgibbs perror("Write to targ failed"); 24139215Sgibbs retval = 0; 24239215Sgibbs } 24339215Sgibbs 24439215Sgibbs /* Backup in our input stream on short writes */ 24539215Sgibbs if (retval != amount_read) 24639215Sgibbs lseek(ifd, retval - amount_read, SEEK_CUR); 24739215Sgibbs } 24839215Sgibbs } 24939215Sgibbs} 25039215Sgibbs 25139215Sgibbsstatic void 25239215Sgibbshandle_exception() 25339215Sgibbs{ 25439215Sgibbs targ_exception exceptions; 25539215Sgibbs 25639215Sgibbs if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) { 25739215Sgibbs perror("TARGIOCFETCHEXCEPTION"); 25839215Sgibbs exit(EX_SOFTWARE); 25939215Sgibbs } 26039215Sgibbs 26149935Sgibbs printf("Saw exceptions %x\n", exceptions); 26239215Sgibbs if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) { 26339215Sgibbs /* Device went away. Nothing more to do. */ 26449935Sgibbs printf("Device went away\n"); 26539215Sgibbs exit(0); 26639215Sgibbs } 26739215Sgibbs 26839215Sgibbs if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) { 26939215Sgibbs struct ccb_accept_tio atio; 27039215Sgibbs struct ioc_initiator_state ioc_istate; 27139215Sgibbs struct scsi_sense_data *sense; 27239215Sgibbs union ccb ccb; 27339215Sgibbs 27439215Sgibbs if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) { 27539215Sgibbs perror("TARGIOCFETCHATIO"); 27639215Sgibbs exit(EX_SOFTWARE); 27739215Sgibbs } 27839215Sgibbs 27939215Sgibbs printf("Ignoring unhandled command 0x%x for Id %d\n", 28039215Sgibbs atio.cdb_io.cdb_bytes[0], atio.init_id); 28139215Sgibbs 28239215Sgibbs ioc_istate.initiator_id = atio.init_id; 28339215Sgibbs if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) { 28439215Sgibbs perror("TARGIOCGETISTATE"); 28539215Sgibbs exit(EX_SOFTWARE); 28639215Sgibbs } 28739215Sgibbs 28839215Sgibbs /* Send back Illegal Command code status */ 28939215Sgibbs ioc_istate.istate.pending_ca |= CA_CMD_SENSE; 29039215Sgibbs sense = &ioc_istate.istate.sense_data; 29139215Sgibbs bzero(sense, sizeof(*sense)); 29239215Sgibbs sense->error_code = SSD_CURRENT_ERROR; 29339215Sgibbs sense->flags = SSD_KEY_ILLEGAL_REQUEST; 29439215Sgibbs sense->add_sense_code = 0x20; 29539215Sgibbs sense->add_sense_code_qual = 0x00; 29639215Sgibbs sense->extra_len = offsetof(struct scsi_sense_data, fru) 29739215Sgibbs - offsetof(struct scsi_sense_data, extra_len); 29839215Sgibbs 29939215Sgibbs if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) { 30039215Sgibbs perror("TARGIOCSETISTATE"); 30139215Sgibbs exit(EX_SOFTWARE); 30239215Sgibbs } 30339215Sgibbs 30439215Sgibbs bzero(&ccb, sizeof(ccb)); 30539215Sgibbs cam_fill_ctio(&ccb.csio, /*retries*/2, 30639215Sgibbs /*cbfcnp*/NULL, 30739215Sgibbs /*flags*/CAM_DIR_NONE 30839215Sgibbs | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID) 30939215Sgibbs | CAM_SEND_STATUS, 31039215Sgibbs /*tag_action*/MSG_SIMPLE_Q_TAG, 31139215Sgibbs atio.tag_id, 31239215Sgibbs atio.init_id, 31339215Sgibbs SCSI_STATUS_CHECK_COND, 31439215Sgibbs /*data_ptr*/NULL, 31539215Sgibbs /*dxfer_len*/0, 31639215Sgibbs /*timeout*/5 * 1000); 31739215Sgibbs if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) { 31839215Sgibbs perror("TARGIOCCOMMAND"); 31939215Sgibbs exit(EX_SOFTWARE); 32039215Sgibbs } 32139215Sgibbs 32239215Sgibbs } 32339215Sgibbs 32439215Sgibbs if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) { 32539215Sgibbs perror("TARGIOCCLEAREXCEPTION"); 32639215Sgibbs exit(EX_SOFTWARE); 32739215Sgibbs } 32839215Sgibbs} 32939215Sgibbs 33039215Sgibbsstatic void 33144498Sgibbsquit_handler(int signum) 33244498Sgibbs{ 33344498Sgibbs quit = 1; 33444498Sgibbs} 33544498Sgibbs 33644498Sgibbsstatic void 33739215Sgibbsusage() 33839215Sgibbs{ 33939215Sgibbs 34039215Sgibbs (void)fprintf(stderr, 34144498Sgibbs"usage: %-16s [-o output_file] [-i input_file] -p path -t target -l lun\n", 34244498Sgibbs appname); 34339215Sgibbs 34439215Sgibbs exit(EX_USAGE); 34539215Sgibbs} 34639215Sgibbs 347