1*57718be8SEnji Cooper /* $NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $ */
2*57718be8SEnji Cooper
3*57718be8SEnji Cooper /*
4*57718be8SEnji Cooper * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
5*57718be8SEnji Cooper *
6*57718be8SEnji Cooper * Redistribution and use in source and binary forms, with or without
7*57718be8SEnji Cooper * modification, are permitted provided that the following conditions
8*57718be8SEnji Cooper * are met:
9*57718be8SEnji Cooper * 1. Redistributions of source code must retain the above copyright
10*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer.
11*57718be8SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright
12*57718be8SEnji Cooper * notice, this list of conditions and the following disclaimer in the
13*57718be8SEnji Cooper * documentation and/or other materials provided with the distribution.
14*57718be8SEnji Cooper *
15*57718be8SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16*57718be8SEnji Cooper * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17*57718be8SEnji Cooper * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18*57718be8SEnji Cooper * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*57718be8SEnji Cooper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*57718be8SEnji Cooper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21*57718be8SEnji Cooper * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*57718be8SEnji Cooper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*57718be8SEnji Cooper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*57718be8SEnji Cooper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*57718be8SEnji Cooper * SUCH DAMAGE.
26*57718be8SEnji Cooper */
27*57718be8SEnji Cooper
28*57718be8SEnji Cooper /*
29*57718be8SEnji Cooper * A SCSI target which is useful for debugging our scsipi driver stack.
30*57718be8SEnji Cooper * Currently it pretends to be a single CD.
31*57718be8SEnji Cooper *
32*57718be8SEnji Cooper * Freely add the necessary features for your tests. Just remember to
33*57718be8SEnji Cooper * run the atf test suite to make sure you didn't cause regressions to
34*57718be8SEnji Cooper * other tests.
35*57718be8SEnji Cooper */
36*57718be8SEnji Cooper
37*57718be8SEnji Cooper #include <sys/cdefs.h>
38*57718be8SEnji Cooper __KERNEL_RCSID(0, "$NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $");
39*57718be8SEnji Cooper
40*57718be8SEnji Cooper #include <sys/param.h>
41*57718be8SEnji Cooper #include <sys/atomic.h>
42*57718be8SEnji Cooper #include <sys/buf.h>
43*57718be8SEnji Cooper #include <sys/device.h>
44*57718be8SEnji Cooper #include <sys/malloc.h>
45*57718be8SEnji Cooper #include <sys/fcntl.h>
46*57718be8SEnji Cooper
47*57718be8SEnji Cooper #include <dev/scsipi/scsiconf.h>
48*57718be8SEnji Cooper #include <dev/scsipi/scsipiconf.h>
49*57718be8SEnji Cooper #include <dev/scsipi/scsi_disk.h>
50*57718be8SEnji Cooper #include <dev/scsipi/scsipi_cd.h>
51*57718be8SEnji Cooper #include <dev/scsipi/scsipi_all.h>
52*57718be8SEnji Cooper
53*57718be8SEnji Cooper #include <rump/rumpuser.h>
54*57718be8SEnji Cooper
55*57718be8SEnji Cooper #include "scsitest.h"
56*57718be8SEnji Cooper
57*57718be8SEnji Cooper int scsitest_match(device_t, cfdata_t, void *);
58*57718be8SEnji Cooper void scsitest_attach(device_t, device_t, void *);
59*57718be8SEnji Cooper
60*57718be8SEnji Cooper struct scsitest {
61*57718be8SEnji Cooper struct scsipi_channel sc_channel;
62*57718be8SEnji Cooper struct scsipi_adapter sc_adapter;
63*57718be8SEnji Cooper };
64*57718be8SEnji Cooper
65*57718be8SEnji Cooper CFATTACH_DECL_NEW(scsitest, sizeof(struct scsitest), scsitest_match,
66*57718be8SEnji Cooper scsitest_attach, NULL, NULL);
67*57718be8SEnji Cooper
68*57718be8SEnji Cooper /*
69*57718be8SEnji Cooper * tosi.iso can be used to deliver CD requests to a host file with the
70*57718be8SEnji Cooper * name in USE_TOSI_ISO (yes, it's extrasimplistic).
71*57718be8SEnji Cooper */
72*57718be8SEnji Cooper //#define USE_TOSI_ISO
73*57718be8SEnji Cooper
74*57718be8SEnji Cooper #define CDBLOCKSIZE 2048
75*57718be8SEnji Cooper static uint32_t mycdsize = 2048;
76*57718be8SEnji Cooper static int isofd;
77*57718be8SEnji Cooper
78*57718be8SEnji Cooper #define MYCDISO "tosi.iso"
79*57718be8SEnji Cooper
80*57718be8SEnji Cooper unsigned rump_scsitest_err[RUMP_SCSITEST_MAXERROR];
81*57718be8SEnji Cooper
82*57718be8SEnji Cooper static void
sense_notready(struct scsipi_xfer * xs)83*57718be8SEnji Cooper sense_notready(struct scsipi_xfer *xs)
84*57718be8SEnji Cooper {
85*57718be8SEnji Cooper struct scsi_sense_data *sense = &xs->sense.scsi_sense;
86*57718be8SEnji Cooper
87*57718be8SEnji Cooper xs->error = XS_SENSE;
88*57718be8SEnji Cooper
89*57718be8SEnji Cooper sense->response_code = 0x70;
90*57718be8SEnji Cooper sense->flags = SKEY_NOT_READY;
91*57718be8SEnji Cooper sense->asc = 0x3A;
92*57718be8SEnji Cooper sense->ascq = 0x00;
93*57718be8SEnji Cooper sense->extra_len = 6;
94*57718be8SEnji Cooper }
95*57718be8SEnji Cooper
96*57718be8SEnji Cooper /*
97*57718be8SEnji Cooper * This is pretty much a CD target for now
98*57718be8SEnji Cooper */
99*57718be8SEnji Cooper static void
scsitest_request(struct scsipi_channel * chan,scsipi_adapter_req_t req,void * arg)100*57718be8SEnji Cooper scsitest_request(struct scsipi_channel *chan,
101*57718be8SEnji Cooper scsipi_adapter_req_t req, void *arg)
102*57718be8SEnji Cooper {
103*57718be8SEnji Cooper struct scsipi_xfer *xs = arg;
104*57718be8SEnji Cooper struct scsipi_generic *cmd = xs->cmd;
105*57718be8SEnji Cooper #ifdef USE_TOSI_ISO
106*57718be8SEnji Cooper int error;
107*57718be8SEnji Cooper #endif
108*57718be8SEnji Cooper
109*57718be8SEnji Cooper if (req != ADAPTER_REQ_RUN_XFER)
110*57718be8SEnji Cooper return;
111*57718be8SEnji Cooper
112*57718be8SEnji Cooper //show_scsipi_xs(xs);
113*57718be8SEnji Cooper
114*57718be8SEnji Cooper switch (cmd->opcode) {
115*57718be8SEnji Cooper case SCSI_TEST_UNIT_READY:
116*57718be8SEnji Cooper if (isofd == -1)
117*57718be8SEnji Cooper sense_notready(xs);
118*57718be8SEnji Cooper
119*57718be8SEnji Cooper break;
120*57718be8SEnji Cooper case INQUIRY: {
121*57718be8SEnji Cooper struct scsipi_inquiry_data *inqbuf = (void *)xs->data;
122*57718be8SEnji Cooper
123*57718be8SEnji Cooper memset(inqbuf, 0, sizeof(*inqbuf));
124*57718be8SEnji Cooper inqbuf->device = T_CDROM;
125*57718be8SEnji Cooper inqbuf->dev_qual2 = SID_REMOVABLE;
126*57718be8SEnji Cooper strcpy(inqbuf->vendor, "RUMPHOBO");
127*57718be8SEnji Cooper strcpy(inqbuf->product, "It's a LIE");
128*57718be8SEnji Cooper strcpy(inqbuf->revision, "0.00");
129*57718be8SEnji Cooper break;
130*57718be8SEnji Cooper }
131*57718be8SEnji Cooper case READ_CD_CAPACITY: {
132*57718be8SEnji Cooper struct scsipi_read_cd_cap_data *ret = (void *)xs->data;
133*57718be8SEnji Cooper
134*57718be8SEnji Cooper _lto4b(CDBLOCKSIZE, ret->length);
135*57718be8SEnji Cooper _lto4b(mycdsize, ret->addr);
136*57718be8SEnji Cooper
137*57718be8SEnji Cooper break;
138*57718be8SEnji Cooper }
139*57718be8SEnji Cooper case READ_DISCINFO: {
140*57718be8SEnji Cooper struct scsipi_read_discinfo_data *ret = (void *)xs->data;
141*57718be8SEnji Cooper
142*57718be8SEnji Cooper memset(ret, 0, sizeof(*ret));
143*57718be8SEnji Cooper break;
144*57718be8SEnji Cooper }
145*57718be8SEnji Cooper case READ_TRACKINFO: {
146*57718be8SEnji Cooper struct scsipi_read_trackinfo_data *ret = (void *)xs->data;
147*57718be8SEnji Cooper
148*57718be8SEnji Cooper _lto4b(mycdsize, ret->track_size);
149*57718be8SEnji Cooper break;
150*57718be8SEnji Cooper }
151*57718be8SEnji Cooper case READ_TOC: {
152*57718be8SEnji Cooper struct scsipi_toc_header *ret = (void *)xs->data;
153*57718be8SEnji Cooper
154*57718be8SEnji Cooper memset(ret, 0, sizeof(*ret));
155*57718be8SEnji Cooper break;
156*57718be8SEnji Cooper }
157*57718be8SEnji Cooper case START_STOP: {
158*57718be8SEnji Cooper struct scsipi_start_stop *param = (void *)cmd;
159*57718be8SEnji Cooper
160*57718be8SEnji Cooper if (param->how & SSS_LOEJ) {
161*57718be8SEnji Cooper #ifdef USE_TOSI_ISO
162*57718be8SEnji Cooper rumpuser_close(isofd, &error);
163*57718be8SEnji Cooper #endif
164*57718be8SEnji Cooper isofd = -1;
165*57718be8SEnji Cooper }
166*57718be8SEnji Cooper break;
167*57718be8SEnji Cooper }
168*57718be8SEnji Cooper case SCSI_SYNCHRONIZE_CACHE_10: {
169*57718be8SEnji Cooper if (isofd == -1) {
170*57718be8SEnji Cooper if ((xs->xs_control & XS_CTL_SILENT) == 0)
171*57718be8SEnji Cooper atomic_inc_uint(&rump_scsitest_err
172*57718be8SEnji Cooper [RUMP_SCSITEST_NOISYSYNC]);
173*57718be8SEnji Cooper
174*57718be8SEnji Cooper sense_notready(xs);
175*57718be8SEnji Cooper }
176*57718be8SEnji Cooper
177*57718be8SEnji Cooper break;
178*57718be8SEnji Cooper }
179*57718be8SEnji Cooper case GET_CONFIGURATION: {
180*57718be8SEnji Cooper memset(xs->data, 0, sizeof(struct scsipi_get_conf_data));
181*57718be8SEnji Cooper break;
182*57718be8SEnji Cooper }
183*57718be8SEnji Cooper case SCSI_READ_6_COMMAND: {
184*57718be8SEnji Cooper #ifdef USE_TOSI_ISO
185*57718be8SEnji Cooper struct scsi_rw_6 *param = (void *)cmd;
186*57718be8SEnji Cooper
187*57718be8SEnji Cooper printf("reading %d bytes from %d\n",
188*57718be8SEnji Cooper param->length * CDBLOCKSIZE,
189*57718be8SEnji Cooper _3btol(param->addr) * CDBLOCKSIZE);
190*57718be8SEnji Cooper rumpuser_pread(isofd, xs->data,
191*57718be8SEnji Cooper param->length * CDBLOCKSIZE,
192*57718be8SEnji Cooper _3btol(param->addr) * CDBLOCKSIZE,
193*57718be8SEnji Cooper &error);
194*57718be8SEnji Cooper #endif
195*57718be8SEnji Cooper
196*57718be8SEnji Cooper break;
197*57718be8SEnji Cooper }
198*57718be8SEnji Cooper case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
199*57718be8SEnji Cooper /* hardcoded for now */
200*57718be8SEnji Cooper break;
201*57718be8SEnji Cooper default:
202*57718be8SEnji Cooper printf("unhandled opcode 0x%x\n", cmd->opcode);
203*57718be8SEnji Cooper break;
204*57718be8SEnji Cooper }
205*57718be8SEnji Cooper
206*57718be8SEnji Cooper scsipi_done(xs);
207*57718be8SEnji Cooper }
208*57718be8SEnji Cooper
209*57718be8SEnji Cooper int
scsitest_match(device_t parent,cfdata_t match,void * aux)210*57718be8SEnji Cooper scsitest_match(device_t parent, cfdata_t match, void *aux)
211*57718be8SEnji Cooper {
212*57718be8SEnji Cooper #ifdef USE_TOSI_ISO
213*57718be8SEnji Cooper uint64_t fsize;
214*57718be8SEnji Cooper int error, ft;
215*57718be8SEnji Cooper
216*57718be8SEnji Cooper if (rumpuser_getfileinfo(MYCDISO, &fsize, &ft, &error))
217*57718be8SEnji Cooper return 0;
218*57718be8SEnji Cooper if (ft != RUMPUSER_FT_REG)
219*57718be8SEnji Cooper return 0;
220*57718be8SEnji Cooper mycdsize = fsize / CDBLOCKSIZE;
221*57718be8SEnji Cooper
222*57718be8SEnji Cooper if ((isofd = rumpuser_open(MYCDISO, RUMPUSER_OPEN_RDWR, &error)) == -1)
223*57718be8SEnji Cooper return 0;
224*57718be8SEnji Cooper #else
225*57718be8SEnji Cooper /*
226*57718be8SEnji Cooper * We pretend to have a medium present initially, so != -1.
227*57718be8SEnji Cooper */
228*57718be8SEnji Cooper isofd = -2;
229*57718be8SEnji Cooper #endif
230*57718be8SEnji Cooper
231*57718be8SEnji Cooper return 1;
232*57718be8SEnji Cooper }
233*57718be8SEnji Cooper
234*57718be8SEnji Cooper void
scsitest_attach(device_t parent,device_t self,void * aux)235*57718be8SEnji Cooper scsitest_attach(device_t parent, device_t self, void *aux)
236*57718be8SEnji Cooper {
237*57718be8SEnji Cooper struct scsitest *sc = device_private(self);
238*57718be8SEnji Cooper
239*57718be8SEnji Cooper aprint_naive("\n");
240*57718be8SEnji Cooper aprint_normal("\n");
241*57718be8SEnji Cooper
242*57718be8SEnji Cooper memset(&sc->sc_adapter, 0, sizeof(sc->sc_adapter));
243*57718be8SEnji Cooper sc->sc_adapter.adapt_nchannels = 1;
244*57718be8SEnji Cooper sc->sc_adapter.adapt_request = scsitest_request;
245*57718be8SEnji Cooper sc->sc_adapter.adapt_minphys = minphys;
246*57718be8SEnji Cooper sc->sc_adapter.adapt_dev = self;
247*57718be8SEnji Cooper sc->sc_adapter.adapt_max_periph = 1;
248*57718be8SEnji Cooper sc->sc_adapter.adapt_openings = 1;
249*57718be8SEnji Cooper
250*57718be8SEnji Cooper memset(&sc->sc_channel, 0, sizeof(sc->sc_channel));
251*57718be8SEnji Cooper sc->sc_channel.chan_bustype = &scsi_bustype;
252*57718be8SEnji Cooper sc->sc_channel.chan_ntargets = 2;
253*57718be8SEnji Cooper sc->sc_channel.chan_nluns = 1;
254*57718be8SEnji Cooper sc->sc_channel.chan_id = 0;
255*57718be8SEnji Cooper sc->sc_channel.chan_flags = SCSIPI_CHAN_NOSETTLE;
256*57718be8SEnji Cooper sc->sc_channel.chan_adapter = &sc->sc_adapter;
257*57718be8SEnji Cooper
258*57718be8SEnji Cooper config_found_ia(self, "scsi", &sc->sc_channel, scsiprint);
259*57718be8SEnji Cooper }
260