scsi_target.c revision 44498
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 * 2944498Sgibbs * $Id: scsi_target.c,v 1.2 1998/12/10 04:00:03 gibbs Exp $ 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(); 6639215Sgibbsstatic void handle_exception(); 6744498Sgibbsstatic void quit_handler(); 6839215Sgibbsstatic void usage(); 6939215Sgibbs 7039215Sgibbsint 7139215Sgibbsmain(int argc, char *argv[]) 7239215Sgibbs{ 7339215Sgibbs int ch; 7439215Sgibbs 7539215Sgibbs appname = *argv; 7644498Sgibbs while ((ch = getopt(argc, argv, "i:o:p:t:l:")) != -1) { 7739215Sgibbs switch(ch) { 7839215Sgibbs case 'i': 7939215Sgibbs if ((ifd = open(optarg, O_RDONLY)) == -1) { 8039215Sgibbs perror(optarg); 8139215Sgibbs exit(EX_NOINPUT); 8239215Sgibbs } 8339215Sgibbs ifilename = optarg; 8439215Sgibbs break; 8539215Sgibbs case 'o': 8639215Sgibbs if ((ofd = open(optarg, 8739215Sgibbs O_WRONLY|O_CREAT), 0600) == -1) { 8839215Sgibbs perror(optarg); 8939215Sgibbs exit(EX_CANTCREAT); 9039215Sgibbs } 9139215Sgibbs ofilename = optarg; 9239215Sgibbs break; 9344498Sgibbs case 'p': 9444498Sgibbs alloc_unit.path_id = atoi(optarg); 9544498Sgibbs break; 9644498Sgibbs case 't': 9744498Sgibbs alloc_unit.target_id = atoi(optarg); 9844498Sgibbs break; 9944498Sgibbs case 'l': 10044498Sgibbs alloc_unit.lun_id = atoi(optarg); 10144498Sgibbs break; 10239215Sgibbs case '?': 10339215Sgibbs default: 10439215Sgibbs usage(); 10539215Sgibbs /* NOTREACHED */ 10639215Sgibbs } 10739215Sgibbs } 10839215Sgibbs argc -= optind; 10939215Sgibbs argv += optind; 11039215Sgibbs 11144498Sgibbs if (alloc_unit.path_id == CAM_BUS_WILDCARD 11244498Sgibbs || alloc_unit.target_id == CAM_TARGET_WILDCARD 11344498Sgibbs || alloc_unit.lun_id == CAM_LUN_WILDCARD) { 11444498Sgibbs fprintf(stderr, "%s: Incomplete device path specifiled\n", 11544498Sgibbs appname); 11639215Sgibbs usage(); 11739215Sgibbs /* NOTREACHED */ 11839215Sgibbs } 11939215Sgibbs 12044498Sgibbs if (argc != 0) { 12144498Sgibbs fprintf(stderr, "%s: Too many arguments\n", appname); 12244498Sgibbs usage(); 12344498Sgibbs /* NOTREACHED */ 12444498Sgibbs } 12544498Sgibbs 12644498Sgibbs /* Allocate a new instance */ 12744498Sgibbs if ((targctlfd = open("/dev/targ.ctl", O_RDWR)) == -1) { 12844498Sgibbs perror("/dev/targ.ctl"); 12944498Sgibbs exit(EX_UNAVAILABLE); 13044498Sgibbs } 13144498Sgibbs 13244498Sgibbs if (ioctl(targctlfd, TARGCTLIOALLOCUNIT, &alloc_unit) == -1) { 13344498Sgibbs perror("TARGCTLIOALLOCUNIT"); 13444498Sgibbs exit(EX_SOFTWARE); 13544498Sgibbs } 13644498Sgibbs 13744498Sgibbs snprintf(targdevname, sizeof(targdevname), "/dev/targ%d", 13844498Sgibbs alloc_unit.unit); 13944498Sgibbs 14039215Sgibbs if ((targfd = open(targdevname, O_RDWR)) == -1) { 14139215Sgibbs perror(targdevname); 14244498Sgibbs ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit); 14339215Sgibbs exit(EX_NOINPUT); 14439215Sgibbs } 14539215Sgibbs 14639215Sgibbs buf = malloc(bufsize); 14739215Sgibbs 14839215Sgibbs if (buf == NULL) { 14939215Sgibbs fprintf(stderr, "%s: Could not malloc I/O buffer", appname); 15039215Sgibbs exit(EX_OSERR); 15139215Sgibbs } 15239215Sgibbs 15344498Sgibbs signal(SIGHUP, quit_handler); 15444498Sgibbs signal(SIGINT, quit_handler); 15544498Sgibbs signal(SIGTERM, quit_handler); 15644498Sgibbs 15739215Sgibbs pump_events(); 15839215Sgibbs 15944498Sgibbs close(targfd); 16044498Sgibbs 16144498Sgibbs if (ioctl(targctlfd, TARGCTLIOFREEUNIT, &alloc_unit) == -1) { 16244498Sgibbs perror("TARGCTLIOFREEUNIT"); 16344498Sgibbs exit(EX_SOFTWARE); 16444498Sgibbs } 16544498Sgibbs 16644498Sgibbs close(targctlfd); 16739215Sgibbs return (0); 16839215Sgibbs} 16939215Sgibbs 17039215Sgibbsstatic void 17139215Sgibbspump_events() 17239215Sgibbs{ 17339215Sgibbs struct pollfd targpoll; 17439215Sgibbs 17539215Sgibbs targpoll.fd = targfd; 17639215Sgibbs targpoll.events = POLLRDNORM|POLLWRNORM; 17739215Sgibbs 17844498Sgibbs while (quit == 0) { 17939215Sgibbs int retval; 18039215Sgibbs 18139215Sgibbs retval = poll(&targpoll, 1, INFTIM); 18239215Sgibbs 18339215Sgibbs if (retval == -1) { 18444498Sgibbs if (errno == EINTR) 18544498Sgibbs continue; 18639215Sgibbs perror("Poll Failed"); 18739215Sgibbs exit(EX_SOFTWARE); 18839215Sgibbs } 18939215Sgibbs 19039215Sgibbs if (retval == 0) { 19139215Sgibbs perror("Poll returned 0 although timeout infinite???"); 19239215Sgibbs exit(EX_SOFTWARE); 19339215Sgibbs } 19439215Sgibbs 19539215Sgibbs if (retval > 1) { 19639215Sgibbs perror("Poll returned more fds ready than allocated"); 19739215Sgibbs exit(EX_SOFTWARE); 19839215Sgibbs } 19939215Sgibbs 20039215Sgibbs /* Process events */ 20139215Sgibbs if ((targpoll.revents & POLLERR) != 0) { 20239215Sgibbs handle_exception(); 20339215Sgibbs } 20439215Sgibbs 20539215Sgibbs if ((targpoll.revents & POLLRDNORM) != 0) { 20639215Sgibbs retval = read(targfd, buf, bufsize); 20739215Sgibbs 20839215Sgibbs if (retval == -1) { 20939215Sgibbs perror("Read from targ failed"); 21039215Sgibbs } else { 21139215Sgibbs retval = write(ofd, buf, retval); 21239215Sgibbs if (retval == -1) { 21339215Sgibbs perror("Write to file failed"); 21439215Sgibbs } 21539215Sgibbs } 21639215Sgibbs } 21739215Sgibbs 21839215Sgibbs if ((targpoll.revents & POLLWRNORM) != 0) { 21939215Sgibbs int amount_read; 22039215Sgibbs 22139215Sgibbs retval = read(ifd, buf, bufsize); 22239215Sgibbs if (retval == -1) { 22339215Sgibbs perror("Read from file failed"); 22439215Sgibbs exit(EX_SOFTWARE); 22539215Sgibbs } 22639215Sgibbs 22739215Sgibbs amount_read = retval; 22839215Sgibbs retval = write(targfd, buf, retval); 22939215Sgibbs if (retval == -1) { 23039215Sgibbs perror("Write to targ failed"); 23139215Sgibbs retval = 0; 23239215Sgibbs } 23339215Sgibbs 23439215Sgibbs /* Backup in our input stream on short writes */ 23539215Sgibbs if (retval != amount_read) 23639215Sgibbs lseek(ifd, retval - amount_read, SEEK_CUR); 23739215Sgibbs } 23839215Sgibbs } 23939215Sgibbs} 24039215Sgibbs 24139215Sgibbsstatic void 24239215Sgibbshandle_exception() 24339215Sgibbs{ 24439215Sgibbs targ_exception exceptions; 24539215Sgibbs 24639215Sgibbs if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) { 24739215Sgibbs perror("TARGIOCFETCHEXCEPTION"); 24839215Sgibbs exit(EX_SOFTWARE); 24939215Sgibbs } 25039215Sgibbs 25139215Sgibbs if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) { 25239215Sgibbs /* Device went away. Nothing more to do. */ 25339215Sgibbs exit(0); 25439215Sgibbs } 25539215Sgibbs 25639215Sgibbs if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) { 25739215Sgibbs struct ccb_accept_tio atio; 25839215Sgibbs struct ioc_initiator_state ioc_istate; 25939215Sgibbs struct scsi_sense_data *sense; 26039215Sgibbs union ccb ccb; 26139215Sgibbs 26239215Sgibbs if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) { 26339215Sgibbs perror("TARGIOCFETCHATIO"); 26439215Sgibbs exit(EX_SOFTWARE); 26539215Sgibbs } 26639215Sgibbs 26739215Sgibbs printf("Ignoring unhandled command 0x%x for Id %d\n", 26839215Sgibbs atio.cdb_io.cdb_bytes[0], atio.init_id); 26939215Sgibbs 27039215Sgibbs ioc_istate.initiator_id = atio.init_id; 27139215Sgibbs if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) { 27239215Sgibbs perror("TARGIOCGETISTATE"); 27339215Sgibbs exit(EX_SOFTWARE); 27439215Sgibbs } 27539215Sgibbs 27639215Sgibbs /* Send back Illegal Command code status */ 27739215Sgibbs ioc_istate.istate.pending_ca |= CA_CMD_SENSE; 27839215Sgibbs sense = &ioc_istate.istate.sense_data; 27939215Sgibbs bzero(sense, sizeof(*sense)); 28039215Sgibbs sense->error_code = SSD_CURRENT_ERROR; 28139215Sgibbs sense->flags = SSD_KEY_ILLEGAL_REQUEST; 28239215Sgibbs sense->add_sense_code = 0x20; 28339215Sgibbs sense->add_sense_code_qual = 0x00; 28439215Sgibbs sense->extra_len = offsetof(struct scsi_sense_data, fru) 28539215Sgibbs - offsetof(struct scsi_sense_data, extra_len); 28639215Sgibbs 28739215Sgibbs if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) { 28839215Sgibbs perror("TARGIOCSETISTATE"); 28939215Sgibbs exit(EX_SOFTWARE); 29039215Sgibbs } 29139215Sgibbs 29239215Sgibbs bzero(&ccb, sizeof(ccb)); 29339215Sgibbs cam_fill_ctio(&ccb.csio, /*retries*/2, 29439215Sgibbs /*cbfcnp*/NULL, 29539215Sgibbs /*flags*/CAM_DIR_NONE 29639215Sgibbs | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID) 29739215Sgibbs | CAM_SEND_STATUS, 29839215Sgibbs /*tag_action*/MSG_SIMPLE_Q_TAG, 29939215Sgibbs atio.tag_id, 30039215Sgibbs atio.init_id, 30139215Sgibbs SCSI_STATUS_CHECK_COND, 30239215Sgibbs /*data_ptr*/NULL, 30339215Sgibbs /*dxfer_len*/0, 30439215Sgibbs /*timeout*/5 * 1000); 30539215Sgibbs if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) { 30639215Sgibbs perror("TARGIOCCOMMAND"); 30739215Sgibbs exit(EX_SOFTWARE); 30839215Sgibbs } 30939215Sgibbs 31039215Sgibbs } 31139215Sgibbs 31239215Sgibbs if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) { 31339215Sgibbs perror("TARGIOCCLEAREXCEPTION"); 31439215Sgibbs exit(EX_SOFTWARE); 31539215Sgibbs } 31639215Sgibbs} 31739215Sgibbs 31839215Sgibbsstatic void 31944498Sgibbsquit_handler(int signum) 32044498Sgibbs{ 32144498Sgibbs quit = 1; 32244498Sgibbs} 32344498Sgibbs 32444498Sgibbsstatic void 32539215Sgibbsusage() 32639215Sgibbs{ 32739215Sgibbs 32839215Sgibbs (void)fprintf(stderr, 32944498Sgibbs"usage: %-16s [-o output_file] [-i input_file] -p path -t target -l lun\n", 33044498Sgibbs appname); 33139215Sgibbs 33239215Sgibbs exit(EX_USAGE); 33339215Sgibbs} 33439215Sgibbs 335