1 /* $NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $ */
4 * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * A SCSI target which is useful for debugging our scsipi driver stack.
30 * Currently it pretends to be a single CD.
32 * Freely add the necessary features for your tests. Just remember to
33 * run the atf test suite to make sure you didn't cause regressions to
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: scsitest.c,v 1.2 2014/04/25 00:24:39 pooka Exp $");
40 #include <sys/param.h>
41 #include <sys/atomic.h>
43 #include <sys/device.h>
44 #include <sys/malloc.h>
45 #include <sys/fcntl.h>
47 #include <dev/scsipi/scsiconf.h>
48 #include <dev/scsipi/scsipiconf.h>
49 #include <dev/scsipi/scsi_disk.h>
50 #include <dev/scsipi/scsipi_cd.h>
51 #include <dev/scsipi/scsipi_all.h>
53 #include <rump/rumpuser.h>
57 int scsitest_match(device_t
, cfdata_t
, void *);
58 void scsitest_attach(device_t
, device_t
, void *);
61 struct scsipi_channel sc_channel
;
62 struct scsipi_adapter sc_adapter
;
65 CFATTACH_DECL_NEW(scsitest
, sizeof(struct scsitest
), scsitest_match
,
66 scsitest_attach
, NULL
, NULL
);
69 * tosi.iso can be used to deliver CD requests to a host file with the
70 * name in USE_TOSI_ISO (yes, it's extrasimplistic).
72 //#define USE_TOSI_ISO
74 #define CDBLOCKSIZE 2048
75 static uint32_t mycdsize
= 2048;
78 #define MYCDISO "tosi.iso"
80 unsigned rump_scsitest_err
[RUMP_SCSITEST_MAXERROR
];
83 sense_notready(struct scsipi_xfer
*xs
)
85 struct scsi_sense_data
*sense
= &xs
->sense
.scsi_sense
;
89 sense
->response_code
= 0x70;
90 sense
->flags
= SKEY_NOT_READY
;
97 * This is pretty much a CD target for now
100 scsitest_request(struct scsipi_channel
*chan
,
101 scsipi_adapter_req_t req
, void *arg
)
103 struct scsipi_xfer
*xs
= arg
;
104 struct scsipi_generic
*cmd
= xs
->cmd
;
109 if (req
!= ADAPTER_REQ_RUN_XFER
)
112 //show_scsipi_xs(xs);
114 switch (cmd
->opcode
) {
115 case SCSI_TEST_UNIT_READY
:
121 struct scsipi_inquiry_data
*inqbuf
= (void *)xs
->data
;
123 memset(inqbuf
, 0, sizeof(*inqbuf
));
124 inqbuf
->device
= T_CDROM
;
125 inqbuf
->dev_qual2
= SID_REMOVABLE
;
126 strcpy(inqbuf
->vendor
, "RUMPHOBO");
127 strcpy(inqbuf
->product
, "It's a LIE");
128 strcpy(inqbuf
->revision
, "0.00");
131 case READ_CD_CAPACITY
: {
132 struct scsipi_read_cd_cap_data
*ret
= (void *)xs
->data
;
134 _lto4b(CDBLOCKSIZE
, ret
->length
);
135 _lto4b(mycdsize
, ret
->addr
);
139 case READ_DISCINFO
: {
140 struct scsipi_read_discinfo_data
*ret
= (void *)xs
->data
;
142 memset(ret
, 0, sizeof(*ret
));
145 case READ_TRACKINFO
: {
146 struct scsipi_read_trackinfo_data
*ret
= (void *)xs
->data
;
148 _lto4b(mycdsize
, ret
->track_size
);
152 struct scsipi_toc_header
*ret
= (void *)xs
->data
;
154 memset(ret
, 0, sizeof(*ret
));
158 struct scsipi_start_stop
*param
= (void *)cmd
;
160 if (param
->how
& SSS_LOEJ
) {
162 rumpuser_close(isofd
, &error
);
168 case SCSI_SYNCHRONIZE_CACHE_10
: {
170 if ((xs
->xs_control
& XS_CTL_SILENT
) == 0)
171 atomic_inc_uint(&rump_scsitest_err
172 [RUMP_SCSITEST_NOISYSYNC
]);
179 case GET_CONFIGURATION
: {
180 memset(xs
->data
, 0, sizeof(struct scsipi_get_conf_data
));
183 case SCSI_READ_6_COMMAND
: {
185 struct scsi_rw_6
*param
= (void *)cmd
;
187 printf("reading %d bytes from %d\n",
188 param
->length
* CDBLOCKSIZE
,
189 _3btol(param
->addr
) * CDBLOCKSIZE
);
190 rumpuser_pread(isofd
, xs
->data
,
191 param
->length
* CDBLOCKSIZE
,
192 _3btol(param
->addr
) * CDBLOCKSIZE
,
198 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL
:
199 /* hardcoded for now */
202 printf("unhandled opcode 0x%x\n", cmd
->opcode
);
210 scsitest_match(device_t parent
, cfdata_t match
, void *aux
)
216 if (rumpuser_getfileinfo(MYCDISO
, &fsize
, &ft
, &error
))
218 if (ft
!= RUMPUSER_FT_REG
)
220 mycdsize
= fsize
/ CDBLOCKSIZE
;
222 if ((isofd
= rumpuser_open(MYCDISO
, RUMPUSER_OPEN_RDWR
, &error
)) == -1)
226 * We pretend to have a medium present initially, so != -1.
235 scsitest_attach(device_t parent
, device_t self
, void *aux
)
237 struct scsitest
*sc
= device_private(self
);
242 memset(&sc
->sc_adapter
, 0, sizeof(sc
->sc_adapter
));
243 sc
->sc_adapter
.adapt_nchannels
= 1;
244 sc
->sc_adapter
.adapt_request
= scsitest_request
;
245 sc
->sc_adapter
.adapt_minphys
= minphys
;
246 sc
->sc_adapter
.adapt_dev
= self
;
247 sc
->sc_adapter
.adapt_max_periph
= 1;
248 sc
->sc_adapter
.adapt_openings
= 1;
250 memset(&sc
->sc_channel
, 0, sizeof(sc
->sc_channel
));
251 sc
->sc_channel
.chan_bustype
= &scsi_bustype
;
252 sc
->sc_channel
.chan_ntargets
= 2;
253 sc
->sc_channel
.chan_nluns
= 1;
254 sc
->sc_channel
.chan_id
= 0;
255 sc
->sc_channel
.chan_flags
= SCSIPI_CHAN_NOSETTLE
;
256 sc
->sc_channel
.chan_adapter
= &sc
->sc_adapter
;
258 config_found_ia(self
, "scsi", &sc
->sc_channel
, scsiprint
);