scsi_target.c revision 41643
1132720Skan/* 2132720Skan * Sample program to attach to the "targ" processor target, target mode 3169691Skan * peripheral driver and push or receive data. 4169691Skan * 5132720Skan * Copyright (c) 1998 Justin T. Gibbs. 6132720Skan * All rights reserved. 7132720Skan * 8132720Skan * Redistribution and use in source and binary forms, with or without 9132720Skan * modification, are permitted provided that the following conditions 10132720Skan * are met: 11132720Skan * 1. Redistributions of source code must retain the above copyright 12132720Skan * notice, this list of conditions, and the following disclaimer, 13132720Skan * without modification, immediately at the beginning of the file. 14132720Skan * 2. The name of the author may not be used to endorse or promote products 15132720Skan * derived from this software without specific prior written permission. 16132720Skan * 17132720Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18132720Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19169691Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20132720Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21132720Skan * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22132720Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23132720Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24132720Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25132720Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26132720Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27132720Skan * SUCH DAMAGE. 28132720Skan * 29132720Skan * $Id: scsi_target.c,v 1.1 1998/09/15 06:46:32 gibbs Exp $ 30132720Skan */ 31132720Skan 32132720Skan#include <sys/types.h> 33132720Skan 34132720Skan#include <fcntl.h> 35132720Skan#include <poll.h> 36132720Skan#include <stddef.h> 37132720Skan#include <stdio.h> 38132720Skan#include <stdlib.h> 39132720Skan#include <sysexits.h> 40132720Skan#include <unistd.h> 41132720Skan 42132720Skan#include <cam/scsi/scsi_all.h> 43132720Skan#include <cam/scsi/scsi_message.h> 44132720Skan#include <cam/scsi/scsi_targetio.h> 45132720Skan 46132720Skanchar *appname; 47169691Skanint ifd; 48132720Skanchar *ifilename; 49132720Skanint ofd; 50132720Skanchar *ofilename; 51132720Skansize_t bufsize = 64 * 1024; 52146897Skanvoid *buf; 53132720Skanchar *targdevname; 54132720Skanint targfd; 55169691Skan 56169691Skanstatic void pump_events(); 57132720Skanstatic void handle_exception(); 58169691Skanstatic void usage(); 59169691Skan 60169691Skanint 61169691Skanmain(int argc, char *argv[]) 62169691Skan{ 63132720Skan int ch; 64169691Skan 65169691Skan appname = *argv; 66132720Skan while ((ch = getopt(argc, argv, "i:o:")) != -1) { 67132720Skan switch(ch) { 68132720Skan case 'i': 69132720Skan if ((ifd = open(optarg, O_RDONLY)) == -1) { 70132720Skan perror(optarg); 71132720Skan exit(EX_NOINPUT); 72132720Skan } 73132720Skan ifilename = optarg; 74132720Skan break; 75132720Skan case 'o': 76132720Skan if ((ofd = open(optarg, 77132720Skan O_WRONLY|O_CREAT), 0600) == -1) { 78132720Skan perror(optarg); 79132720Skan exit(EX_CANTCREAT); 80132720Skan } 81146897Skan ofilename = optarg; 82132720Skan break; 83132720Skan case '?': 84132720Skan default: 85132720Skan usage(); 86132720Skan /* NOTREACHED */ 87169691Skan } 88132720Skan } 89132720Skan argc -= optind; 90132720Skan argv += optind; 91132720Skan 92132720Skan if (argc != 1) { 93132720Skan fprintf(stderr, "%s: No target device specifiled\n", appname); 94132720Skan usage(); 95132720Skan /* NOTREACHED */ 96132720Skan } 97132720Skan 98132720Skan targdevname = *argv; 99132720Skan if ((targfd = open(targdevname, O_RDWR)) == -1) { 100132720Skan perror(targdevname); 101132720Skan exit(EX_NOINPUT); 102132720Skan } 103132720Skan 104132720Skan buf = malloc(bufsize); 105132720Skan 106132720Skan if (buf == NULL) { 107132720Skan fprintf(stderr, "%s: Could not malloc I/O buffer", appname); 108132720Skan exit(EX_OSERR); 109169691Skan } 110132720Skan 111132720Skan pump_events(); 112132720Skan 113132720Skan return (0); 114132720Skan} 115132720Skan 116132720Skanstatic void 117132720Skanpump_events() 118132720Skan{ 119132720Skan struct pollfd targpoll; 120132720Skan 121132720Skan targpoll.fd = targfd; 122132720Skan targpoll.events = POLLRDNORM|POLLWRNORM; 123132720Skan 124169691Skan while (1) { 125132720Skan int retval; 126146897Skan 127132720Skan retval = poll(&targpoll, 1, INFTIM); 128132720Skan 129132720Skan if (retval == -1) { 130132720Skan perror("Poll Failed"); 131132720Skan exit(EX_SOFTWARE); 132132720Skan } 133132720Skan 134132720Skan if (retval == 0) { 135132720Skan perror("Poll returned 0 although timeout infinite???"); 136132720Skan exit(EX_SOFTWARE); 137132720Skan } 138132720Skan 139132720Skan if (retval > 1) { 140132720Skan perror("Poll returned more fds ready than allocated"); 141132720Skan exit(EX_SOFTWARE); 142132720Skan } 143132720Skan 144132720Skan /* Process events */ 145132720Skan if ((targpoll.revents & POLLERR) != 0) { 146132720Skan handle_exception(); 147132720Skan } 148132720Skan 149132720Skan if ((targpoll.revents & POLLRDNORM) != 0) { 150132720Skan retval = read(targfd, buf, bufsize); 151132720Skan 152132720Skan if (retval == -1) { 153132720Skan perror("Read from targ failed"); 154132720Skan } else { 155132720Skan retval = write(ofd, buf, retval); 156132720Skan if (retval == -1) { 157132720Skan perror("Write to file failed"); 158132720Skan } 159132720Skan } 160132720Skan } 161132720Skan 162132720Skan if ((targpoll.revents & POLLWRNORM) != 0) { 163132720Skan int amount_read; 164132720Skan 165132720Skan retval = read(ifd, buf, bufsize); 166132720Skan if (retval == -1) { 167132720Skan perror("Read from file failed"); 168132720Skan exit(EX_SOFTWARE); 169132720Skan } 170132720Skan 171132720Skan amount_read = retval; 172132720Skan retval = write(targfd, buf, retval); 173132720Skan if (retval == -1) { 174132720Skan perror("Write to targ failed"); 175132720Skan retval = 0; 176132720Skan } 177132720Skan 178132720Skan /* Backup in our input stream on short writes */ 179132720Skan if (retval != amount_read) 180132720Skan lseek(ifd, retval - amount_read, SEEK_CUR); 181132720Skan } 182132720Skan } 183132720Skan} 184132720Skan 185132720Skanstatic void 186132720Skanhandle_exception() 187132720Skan{ 188132720Skan targ_exception exceptions; 189132720Skan 190132720Skan if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) { 191132720Skan perror("TARGIOCFETCHEXCEPTION"); 192132720Skan exit(EX_SOFTWARE); 193132720Skan } 194132720Skan 195132720Skan if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) { 196132720Skan /* Device went away. Nothing more to do. */ 197132720Skan exit(0); 198169691Skan } 199132720Skan 200169691Skan if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) { 201169691Skan struct ccb_accept_tio atio; 202169691Skan struct ioc_initiator_state ioc_istate; 203169691Skan struct scsi_sense_data *sense; 204169691Skan union ccb ccb; 205169691Skan 206169691Skan if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) { 207132720Skan perror("TARGIOCFETCHATIO"); 208169691Skan exit(EX_SOFTWARE); 209169691Skan } 210169691Skan 211169691Skan printf("Ignoring unhandled command 0x%x for Id %d\n", 212169691Skan atio.cdb_io.cdb_bytes[0], atio.init_id); 213132720Skan 214169691Skan ioc_istate.initiator_id = atio.init_id; 215169691Skan if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) { 216169691Skan perror("TARGIOCGETISTATE"); 217169691Skan exit(EX_SOFTWARE); 218169691Skan } 219169691Skan 220169691Skan /* Send back Illegal Command code status */ 221169691Skan ioc_istate.istate.pending_ca |= CA_CMD_SENSE; 222169691Skan sense = &ioc_istate.istate.sense_data; 223169691Skan bzero(sense, sizeof(*sense)); 224169691Skan sense->error_code = SSD_CURRENT_ERROR; 225132720Skan sense->flags = SSD_KEY_ILLEGAL_REQUEST; 226132720Skan sense->add_sense_code = 0x20; 227169691Skan sense->add_sense_code_qual = 0x00; 228169691Skan sense->extra_len = offsetof(struct scsi_sense_data, fru) 229132720Skan - offsetof(struct scsi_sense_data, extra_len); 230169691Skan 231169691Skan if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) { 232132720Skan perror("TARGIOCSETISTATE"); 233132720Skan exit(EX_SOFTWARE); 234132720Skan } 235132720Skan 236132720Skan bzero(&ccb, sizeof(ccb)); 237132720Skan cam_fill_ctio(&ccb.csio, /*retries*/2, 238132720Skan /*cbfcnp*/NULL, 239132720Skan /*flags*/CAM_DIR_NONE 240132720Skan | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID) 241169691Skan | CAM_SEND_STATUS, 242132720Skan /*tag_action*/MSG_SIMPLE_Q_TAG, 243132720Skan atio.tag_id, 244132720Skan atio.init_id, 245132720Skan SCSI_STATUS_CHECK_COND, 246132720Skan /*data_ptr*/NULL, 247132720Skan /*dxfer_len*/0, 248132720Skan /*timeout*/5 * 1000); 249132720Skan if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) { 250132720Skan perror("TARGIOCCOMMAND"); 251169691Skan exit(EX_SOFTWARE); 252132720Skan } 253132720Skan 254132720Skan } 255132720Skan 256132720Skan if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) { 257132720Skan perror("TARGIOCCLEAREXCEPTION"); 258169691Skan exit(EX_SOFTWARE); 259169691Skan } 260132720Skan} 261 262static void 263usage() 264{ 265 266 (void)fprintf(stderr, 267"usage: %-16s [-o output_file] [-i input_file] /dev/targ?\n", appname); 268 269 exit(EX_USAGE); 270} 271 272