scsi_target.c revision 39215
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 * 2939215Sgibbs * $Id$ 3039215Sgibbs */ 3139215Sgibbs 3239215Sgibbs#include <sys/types.h> 3339215Sgibbs 3439215Sgibbs#include <fcntl.h> 3539215Sgibbs#include <poll.h> 3639215Sgibbs#include <stddef.h> 3739215Sgibbs#include <stdio.h> 3839215Sgibbs#include <stdlib.h> 3939215Sgibbs#include <sysexits.h> 4039215Sgibbs#include <unistd.h> 4139215Sgibbs 4239215Sgibbs#include <cam/scsi/scsi_all.h> 4339215Sgibbs#include <cam/scsi/scsi_message.h> 4439215Sgibbs#include <cam/scsi/scsi_targetio.h> 4539215Sgibbs 4639215Sgibbschar *appname; 4739215Sgibbsint ifd; 4839215Sgibbschar *ifilename; 4939215Sgibbsint ofd; 5039215Sgibbschar *ofilename; 5139215Sgibbssize_t bufsize = 64 * 1024; 5239215Sgibbsvoid *buf; 5339215Sgibbschar *targdevname; 5439215Sgibbsint targfd; 5539215Sgibbs 5639215Sgibbsstatic void pump_events(); 5739215Sgibbsstatic void handle_exception(); 5839215Sgibbsstatic void usage(); 5939215Sgibbs 6039215Sgibbsint 6139215Sgibbsmain(int argc, char *argv[]) 6239215Sgibbs{ 6339215Sgibbs int ch; 6439215Sgibbs 6539215Sgibbs appname = *argv; 6639215Sgibbs while ((ch = getopt(argc, argv, "i:o:")) != -1) { 6739215Sgibbs switch(ch) { 6839215Sgibbs case 'i': 6939215Sgibbs if ((ifd = open(optarg, O_RDONLY)) == -1) { 7039215Sgibbs perror(optarg); 7139215Sgibbs exit(EX_NOINPUT); 7239215Sgibbs } 7339215Sgibbs ifilename = optarg; 7439215Sgibbs break; 7539215Sgibbs case 'o': 7639215Sgibbs if ((ofd = open(optarg, 7739215Sgibbs O_WRONLY|O_CREAT), 0600) == -1) { 7839215Sgibbs perror(optarg); 7939215Sgibbs exit(EX_CANTCREAT); 8039215Sgibbs } 8139215Sgibbs ofilename = optarg; 8239215Sgibbs break; 8339215Sgibbs case '?': 8439215Sgibbs default: 8539215Sgibbs usage(); 8639215Sgibbs /* NOTREACHED */ 8739215Sgibbs } 8839215Sgibbs } 8939215Sgibbs argc -= optind; 9039215Sgibbs argv += optind; 9139215Sgibbs 9239215Sgibbs if (argc != 1) { 9339215Sgibbs fprintf(stderr, "%s: No target device specifiled\n", appname); 9439215Sgibbs usage(); 9539215Sgibbs /* NOTREACHED */ 9639215Sgibbs } 9739215Sgibbs 9839215Sgibbs targdevname = *argv; 9939215Sgibbs if ((targfd = open(targdevname, O_RDWR)) == -1) { 10039215Sgibbs perror(targdevname); 10139215Sgibbs exit(EX_NOINPUT); 10239215Sgibbs } 10339215Sgibbs 10439215Sgibbs buf = malloc(bufsize); 10539215Sgibbs 10639215Sgibbs if (buf == NULL) { 10739215Sgibbs fprintf(stderr, "%s: Could not malloc I/O buffer", appname); 10839215Sgibbs exit(EX_OSERR); 10939215Sgibbs } 11039215Sgibbs 11139215Sgibbs pump_events(); 11239215Sgibbs 11339215Sgibbs return (0); 11439215Sgibbs} 11539215Sgibbs 11639215Sgibbsstatic void 11739215Sgibbspump_events() 11839215Sgibbs{ 11939215Sgibbs struct pollfd targpoll; 12039215Sgibbs 12139215Sgibbs targpoll.fd = targfd; 12239215Sgibbs targpoll.events = POLLRDNORM|POLLWRNORM; 12339215Sgibbs 12439215Sgibbs while (1) { 12539215Sgibbs int retval; 12639215Sgibbs 12739215Sgibbs retval = poll(&targpoll, 1, INFTIM); 12839215Sgibbs 12939215Sgibbs if (retval == -1) { 13039215Sgibbs perror("Poll Failed"); 13139215Sgibbs exit(EX_SOFTWARE); 13239215Sgibbs } 13339215Sgibbs 13439215Sgibbs if (retval == 0) { 13539215Sgibbs perror("Poll returned 0 although timeout infinite???"); 13639215Sgibbs exit(EX_SOFTWARE); 13739215Sgibbs } 13839215Sgibbs 13939215Sgibbs if (retval > 1) { 14039215Sgibbs perror("Poll returned more fds ready than allocated"); 14139215Sgibbs exit(EX_SOFTWARE); 14239215Sgibbs } 14339215Sgibbs 14439215Sgibbs /* Process events */ 14539215Sgibbs if ((targpoll.revents & POLLERR) != 0) { 14639215Sgibbs handle_exception(); 14739215Sgibbs } 14839215Sgibbs 14939215Sgibbs if ((targpoll.revents & POLLRDNORM) != 0) { 15039215Sgibbs printf("Read Poll event came true\n"); 15139215Sgibbs retval = read(targfd, buf, bufsize); 15239215Sgibbs 15339215Sgibbs if (retval == -1) { 15439215Sgibbs perror("Read from targ failed"); 15539215Sgibbs } else { 15639215Sgibbs retval = write(ofd, buf, retval); 15739215Sgibbs if (retval == -1) { 15839215Sgibbs perror("Write to file failed"); 15939215Sgibbs } 16039215Sgibbs } 16139215Sgibbs } 16239215Sgibbs 16339215Sgibbs if ((targpoll.revents & POLLWRNORM) != 0) { 16439215Sgibbs int amount_read; 16539215Sgibbs 16639215Sgibbs printf("Write Poll event came true\n"); 16739215Sgibbs retval = read(ifd, buf, bufsize); 16839215Sgibbs if (retval == -1) { 16939215Sgibbs perror("Read from file failed"); 17039215Sgibbs exit(EX_SOFTWARE); 17139215Sgibbs } 17239215Sgibbs 17339215Sgibbs amount_read = retval; 17439215Sgibbs retval = write(targfd, buf, retval); 17539215Sgibbs if (retval == -1) { 17639215Sgibbs perror("Write to targ failed"); 17739215Sgibbs retval = 0; 17839215Sgibbs } 17939215Sgibbs 18039215Sgibbs /* Backup in our input stream on short writes */ 18139215Sgibbs if (retval != amount_read) 18239215Sgibbs lseek(ifd, retval - amount_read, SEEK_CUR); 18339215Sgibbs } 18439215Sgibbs } 18539215Sgibbs} 18639215Sgibbs 18739215Sgibbsstatic void 18839215Sgibbshandle_exception() 18939215Sgibbs{ 19039215Sgibbs targ_exception exceptions; 19139215Sgibbs 19239215Sgibbs if (ioctl(targfd, TARGIOCFETCHEXCEPTION, &exceptions) == -1) { 19339215Sgibbs perror("TARGIOCFETCHEXCEPTION"); 19439215Sgibbs exit(EX_SOFTWARE); 19539215Sgibbs } 19639215Sgibbs 19739215Sgibbs if ((exceptions & TARG_EXCEPT_DEVICE_INVALID) != 0) { 19839215Sgibbs /* Device went away. Nothing more to do. */ 19939215Sgibbs exit(0); 20039215Sgibbs } 20139215Sgibbs 20239215Sgibbs if ((exceptions & TARG_EXCEPT_UNKNOWN_ATIO) != 0) { 20339215Sgibbs struct ccb_accept_tio atio; 20439215Sgibbs struct ioc_initiator_state ioc_istate; 20539215Sgibbs struct scsi_sense_data *sense; 20639215Sgibbs union ccb ccb; 20739215Sgibbs 20839215Sgibbs if (ioctl(targfd, TARGIOCFETCHATIO, &atio) == -1) { 20939215Sgibbs perror("TARGIOCFETCHATIO"); 21039215Sgibbs exit(EX_SOFTWARE); 21139215Sgibbs } 21239215Sgibbs 21339215Sgibbs printf("Ignoring unhandled command 0x%x for Id %d\n", 21439215Sgibbs atio.cdb_io.cdb_bytes[0], atio.init_id); 21539215Sgibbs 21639215Sgibbs ioc_istate.initiator_id = atio.init_id; 21739215Sgibbs if (ioctl(targfd, TARGIOCGETISTATE, &ioc_istate) == -1) { 21839215Sgibbs perror("TARGIOCGETISTATE"); 21939215Sgibbs exit(EX_SOFTWARE); 22039215Sgibbs } 22139215Sgibbs 22239215Sgibbs /* Send back Illegal Command code status */ 22339215Sgibbs ioc_istate.istate.pending_ca |= CA_CMD_SENSE; 22439215Sgibbs sense = &ioc_istate.istate.sense_data; 22539215Sgibbs bzero(sense, sizeof(*sense)); 22639215Sgibbs sense->error_code = SSD_CURRENT_ERROR; 22739215Sgibbs sense->flags = SSD_KEY_ILLEGAL_REQUEST; 22839215Sgibbs sense->add_sense_code = 0x20; 22939215Sgibbs sense->add_sense_code_qual = 0x00; 23039215Sgibbs sense->extra_len = offsetof(struct scsi_sense_data, fru) 23139215Sgibbs - offsetof(struct scsi_sense_data, extra_len); 23239215Sgibbs 23339215Sgibbs if (ioctl(targfd, TARGIOCSETISTATE, &ioc_istate) == -1) { 23439215Sgibbs perror("TARGIOCSETISTATE"); 23539215Sgibbs exit(EX_SOFTWARE); 23639215Sgibbs } 23739215Sgibbs 23839215Sgibbs bzero(&ccb, sizeof(ccb)); 23939215Sgibbs cam_fill_ctio(&ccb.csio, /*retries*/2, 24039215Sgibbs /*cbfcnp*/NULL, 24139215Sgibbs /*flags*/CAM_DIR_NONE 24239215Sgibbs | (atio.ccb_h.flags & CAM_TAG_ACTION_VALID) 24339215Sgibbs | CAM_SEND_STATUS, 24439215Sgibbs /*tag_action*/MSG_SIMPLE_Q_TAG, 24539215Sgibbs atio.tag_id, 24639215Sgibbs atio.init_id, 24739215Sgibbs SCSI_STATUS_CHECK_COND, 24839215Sgibbs /*data_ptr*/NULL, 24939215Sgibbs /*dxfer_len*/0, 25039215Sgibbs /*timeout*/5 * 1000); 25139215Sgibbs if (ioctl(targfd, TARGIOCCOMMAND, &ccb) == -1) { 25239215Sgibbs perror("TARGIOCCOMMAND"); 25339215Sgibbs exit(EX_SOFTWARE); 25439215Sgibbs } 25539215Sgibbs 25639215Sgibbs } 25739215Sgibbs 25839215Sgibbs if (ioctl(targfd, TARGIOCCLEAREXCEPTION, &exceptions) == -1) { 25939215Sgibbs perror("TARGIOCCLEAREXCEPTION"); 26039215Sgibbs exit(EX_SOFTWARE); 26139215Sgibbs } 26239215Sgibbs} 26339215Sgibbs 26439215Sgibbsstatic void 26539215Sgibbsusage() 26639215Sgibbs{ 26739215Sgibbs 26839215Sgibbs (void)fprintf(stderr, 26939215Sgibbs"usage: %-16s [-o output_file] [-i input_file] /dev/targ?\n", appname); 27039215Sgibbs 27139215Sgibbs exit(EX_USAGE); 27239215Sgibbs} 27339215Sgibbs 274