1 /* 2 * Sample program to attach to the "targ" processor target, target mode 3 * peripheral driver and push or receive data. 4 * 5 * Copyright (c) 1998 Justin T. Gibbs. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions, and the following disclaimer, 13 * without modification, immediately at the beginning of the file. 14 * 2. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $Id: scsi_target.c,v 1.1 1998/09/15 06:46:32 gibbs Exp $ 30 */ 31 32 #include <sys/types.h> 33 34 #include <fcntl.h> 35 #include <poll.h> 36 #include <stddef.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <sysexits.h> 40 #include <unistd.h> 41 42 #include <cam/scsi/scsi_all.h> 43 #include <cam/scsi/scsi_message.h> 44 #include <cam/scsi/scsi_targetio.h> 45 46 char *appname; 47 int ifd; 48 char *ifilename; 49 int ofd; 50 char *ofilename; 51 size_t bufsize = 64 * 1024; 52 void *buf; 53 char *targdevname; 54 int targfd; 55 56 static void pump_events(); 57 static void handle_exception(); 58 static void usage(); 59 60 int 61 main(int argc, char *argv[]) 62 { 63 int ch; 64 65 appname = *argv; 66 while ((ch = getopt(argc, argv, "i:o:")) != -1) { 67 switch(ch) { 68 case 'i': 69 if ((ifd = open(optarg, O_RDONLY)) == -1) { 70 perror(optarg); 71 exit(EX_NOINPUT); 72 } 73 ifilename = optarg; 74 break; 75 case 'o': 76 if ((ofd = open(optarg, 77 O_WRONLY|O_CREAT), 0600) == -1) { 78 perror(optarg); 79 exit(EX_CANTCREAT); 80 } 81 ofilename = optarg; 82 break; 83 case '?': 84 default: 85 usage(); 86 /* NOTREACHED */ 87 } 88 } 89 argc -= optind; 90 argv += optind; 91 92 if (argc != 1) { 93 fprintf(stderr, "%s: No target device specifiled\n", appname); 94 usage(); 95 /* NOTREACHED */ 96 } 97 98 targdevname = *argv; 99 if ((targfd = open(targdevname, O_RDWR)) == -1) { 100 perror(targdevname); 101 exit(EX_NOINPUT); 102 } 103 104 buf = malloc(bufsize); 105 106 if (buf == NULL) { 107 fprintf(stderr, "%s: Could not malloc I/O buffer", appname); 108 exit(EX_OSERR); 109 } 110 111 pump_events(); 112 113 return (0); 114 } 115 116 static void 117 pump_events() 118 { 119 struct pollfd targpoll; 120 121 targpoll.fd = targfd; 122 targpoll.events = POLLRDNORM|POLLWRNORM; 123 124 while (1) { 125 int retval; 126 127 retval = poll(&targpoll, 1, INFTIM); 128 129 if (retval == -1) { 130 perror("Poll Failed"); 131 exit(EX_SOFTWARE); 132 } 133 134 if (retval == 0) { 135 perror("Poll returned 0 although timeout infinite???"); 136 exit(EX_SOFTWARE); 137 } 138 139 if (retval > 1) { 140 perror("Poll returned more fds ready than allocated"); 141 exit(EX_SOFTWARE); 142 } 143 144 /* Process events */ 145 if ((targpoll.revents & POLLERR) != 0) { 146 handle_exception(); 147 } 148 149 if ((targpoll.revents & POLLRDNORM) != 0) { 150 retval = read(targfd, buf, bufsize); 151 152 if (retval == -1) { 153 perror("Read from targ failed"); 154 } else { 155 retval = write(ofd, buf, retval); 156 if (retval == -1) { 157 perror("Write to file failed"); 158 } 159 } 160 } 161 162 if ((targpoll.revents & POLLWRNORM) != 0) { 163 int amount_read; 164 165 retval = read(ifd, buf, bufsize); 166 if (retval == -1) { 167 perror("Read from file failed"); 168 exit(EX_SOFTWARE); 169 } 170 171 amount_read = retval; 172 retval = write(targfd, buf, retval); 173 if (retval == -1) { 174 perror("Write to targ failed"); 175 retval = 0; 176 } 177 178 /* Backup in our input stream on short writes */ 179 if (retval != amount_read) 180 lseek(ifd, retval - amount_read, SEEK_CUR); 181 } 182 } 183 } 184 185 static void 186 handle_exception() 187 { 188 targ_exception exceptions; 189 190 if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) { 191 perror("TARGIOCFETCHEXCEPTION"); 192 exit(EX_SOFTWARE); 193 } 194 195 if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) { 196 /* Device went away. Nothing more to do. */ 197 exit(0); 198 } 199 200 if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) { 201 struct ccb_accept_tio atio; 202 struct ioc_initiator_state ioc_istate; 203 struct scsi_sense_data *sense; 204 union ccb ccb; 205 206 if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) { 207 perror("TARGIOCFETCHATIO"); 208 exit(EX_SOFTWARE); 209 } 210 211 printf("Ignoring unhandled command 0x%x for Id %d\n", 212 atio.cdb_io.cdb_bytes[0], atio.init_id); 213 214 ioc_istate.initiator_id = atio.init_id; 215 if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) { 216 perror("TARGIOCGETISTATE"); 217 exit(EX_SOFTWARE); 218 } 219 220 /* Send back Illegal Command code status */ 221 ioc_istate.istate.pending_ca |= CA_CMD_SENSE; 222 sense = &ioc_istate.istate.sense_data; 223 bzero(sense, sizeof(*sense)); 224 sense->error_code = SSD_CURRENT_ERROR; 225 sense->flags = SSD_KEY_ILLEGAL_REQUEST; 226 sense->add_sense_code = 0x20; 227 sense->add_sense_code_qual = 0x00; 228 sense->extra_len = offsetof(struct scsi_sense_data, fru) 229 - offsetof(struct scsi_sense_data, extra_len); 230 231 if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) { 232 perror("TARGIOCSETISTATE"); 233 exit(EX_SOFTWARE); 234 } 235 236 bzero(&ccb, sizeof(ccb)); 237 cam_fill_ctio(&ccb.csio, /*retries*/2, 238 /*cbfcnp*/NULL, 239 /*flags*/CAM_DIR_NONE 240 | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID) 241 | CAM_SEND_STATUS, 242 /*tag_action*/MSG_SIMPLE_Q_TAG, 243 atio.tag_id, 244 atio.init_id, 245 SCSI_STATUS_CHECK_COND, 246 /*data_ptr*/NULL, 247 /*dxfer_len*/0, 248 /*timeout*/5 * 1000); 249 if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) { 250 perror("TARGIOCCOMMAND"); 251 exit(EX_SOFTWARE); 252 } 253 254 } 255 256 if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) { 257 perror("TARGIOCCLEAREXCEPTION"); 258 exit(EX_SOFTWARE); 259 } 260 } 261 262 static void 263 usage() 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