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