1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #include "diskimage_device.h"
32 static BOOL
GetGeometry (struct DiskImageUnit
*unit
, struct DriveGeometry
*dg
) {
33 struct DiskImagePlugin
*plugin
= unit
->Plugin
;
35 ClearMem(dg
, sizeof(*dg
));
36 dg
->dg_SectorSize
= 512;
37 dg
->dg_CylSectors
= 1;
39 dg
->dg_TrackSectors
= 1;
40 dg
->dg_BufMemType
= MEMF_ANY
;
41 dg
->dg_DeviceType
= unit
->DeviceType
;
42 dg
->dg_Flags
= unit
->Flags
;
44 if (unit
->ImageData
&& plugin
) {
45 return Plugin_Geometry(plugin
, unit
->ImageData
, dg
) == IOERR_SUCCESS
;
51 static void WriteSenseData (BytePackBuffer
*sense
, UBYTE sensekey
, UBYTE asc
, UBYTE ascq
) {
52 BytePackWrite8(sense
, 0x70);
53 BytePackWrite8(sense
, 0);
54 BytePackWrite8(sense
, sensekey
);
55 BytePackWrite32MSB(sense
, 0);
56 BytePackWrite8(sense
, 10);
57 BytePackWrite32MSB(sense
, 0);
58 BytePackWrite8(sense
, asc
);
59 BytePackWrite8(sense
, ascq
);
60 BytePackWrite8(sense
, 0);
61 BytePackWrite24MSB(sense
, 0);
64 LONG
DoSCSICmd (struct IOStdReq
*io
, struct SCSICmd
*scsi
) {
65 struct DiskImageUnit
*unit
= (struct DiskImageUnit
*)io
->io_Unit
;
66 APTR image
= unit
->ImageData
;
67 struct DiskImagePlugin
*plugin
= unit
->Plugin
;
74 if (io
->io_Length
< sizeof(struct SCSICmd
)) {
75 return IOERR_BADLENGTH
;
77 io
->io_Actual
= sizeof(struct SCSICmd
);
79 cmd
= scsi
->scsi_Command
;
80 cmd_len
= scsi
->scsi_CmdLength
;
81 BytePackInit(&data
, scsi
->scsi_Data
, scsi
->scsi_Length
);
82 if (scsi
->scsi_Flags
& SCSIF_AUTOSENSE
) {
83 BytePackInit(&sense
, scsi
->scsi_SenseData
, scsi
->scsi_SenseLength
);
85 BytePackInit(&sense
, NULL
, 0);
89 scsi
->scsi_CmdActual
= 1;
91 case SCSICMD_TEST_UNIT_READY
:
92 scsi
->scsi_CmdActual
= 6;
93 if (cmd_len
>= 6 && cmd
[1] == 0 && cmd
[2] == 0 && cmd
[3] == 0 &&
94 cmd
[4] == 0 && cmd
[5] == 0)
96 if (image
&& plugin
) {
99 status
= SCSI_CheckCondition
;
100 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x3a, 0x00);
103 status
= SCSI_CheckCondition
;
104 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x24, 0x00);
108 case SCSICMD_INQUIRY
:
109 scsi
->scsi_CmdActual
= 6;
110 if (cmd_len
>= 6 && (cmd
[1] & 0xfe) == 0 && cmd
[3] == 0 && cmd
[5] == 0) {
113 BytePackWrite8(&data
, unit
->DeviceType
);
114 BytePackWrite8(&data
, 0x01);
115 } else if (cmd
[2] == 0) {
117 BytePackWrite8(&data
, unit
->DeviceType
);
118 BytePackWrite8(&data
, (unit
->Flags
& DGF_REMOVABLE
) ? 0x80 : 0x00);
119 BytePackWrite8(&data
, 5);
120 BytePackWrite8(&data
, 0x02);
121 BytePackWrite8(&data
, 31);
122 BytePackWrite24MSB(&data
, 0);
123 BytePackWriteText(&data
, "a500.org", 8);
124 BytePackWriteText(&data
, "diskimage.device", 16);
125 BytePackWriteText(&data
, "DI52", 4);
127 status
= SCSI_CheckCondition
;
128 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x24, 0x00);
131 status
= SCSI_CheckCondition
;
132 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x24, 0x00);
136 case SCSICMD_READ_CAPACITY
:
137 scsi
->scsi_CmdActual
= 10;
138 if (unit
->DeviceType
== DG_CDROM
) {
139 status
= SCSI_CheckCondition
;
140 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x20, 0x00);
143 if (cmd_len
>= 10 && cmd
[1] == 0 && cmd
[2] == 0 && cmd
[3] == 0 &&
144 cmd
[4] == 0 && cmd
[5] == 0 && cmd
[6] == 0 && cmd
[7] == 0 &&
145 cmd
[8] == 0 && cmd
[9] == 0)
147 struct DriveGeometry dg
;
148 if (GetGeometry(unit
, &dg
)) {
150 BytePackWrite32MSB(&data
, dg
.dg_TotalSectors
-1);
151 BytePackWrite32MSB(&data
, dg
.dg_SectorSize
);
153 status
= SCSI_CheckCondition
;
154 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x3a, 0x00);
157 status
= SCSI_CheckCondition
;
158 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x24, 0x00);
162 case SCSICMD_READ_TOC
:
163 scsi
->scsi_CmdActual
= 10;
164 if (unit
->DeviceType
!= DG_CDROM
) {
165 status
= SCSI_CheckCondition
;
166 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x20, 0x00);
169 if (cmd_len
>= 10 && (cmd
[1] & 0xfd) == 0 && cmd
[2] == 0 &&
170 cmd
[3] == 0 && cmd
[4] == 0 && cmd
[5] == 0 && cmd
[9] == 0)
172 if (image
&& plugin
) {
173 struct CDTrack
*track
= NULL
;
174 ULONG num_tracks
= 0;
175 struct CDTrack data_track
;
176 if (plugin
->plugin_GetCDTracks
) {
177 Plugin_GetCDTracks(plugin
, image
, &track
, &num_tracks
);
179 struct DriveGeometry dg
;
180 if (GetGeometry(unit
, &dg
)) {
182 total_sectors
= ((UQUAD
)dg
.dg_TotalSectors
* (UQUAD
)dg
.dg_SectorSize
) >> 11;
183 data_track
.next
= NULL
;
184 data_track
.track_num
= 1;
185 data_track
.audio
= FALSE
;
186 data_track
.sector_size
= 2048;
187 data_track
.sync_size
= 0;
188 data_track
.offset
= 0;
189 data_track
.length
= total_sectors
<< 11;
190 data_track
.sectors
= total_sectors
;
195 if (track
&& num_tracks
) {
200 while (track
&& track
->track_num
!= cmd
[6]) {
201 type
= track
->audio
? 0x10 : 0x14;
202 addr
+= track
->sectors
;
207 BytePackWrite16MSB(&data
, 2 + ((num_tracks
+ 1) * 8));
208 BytePackWrite8(&data
, 1);
209 BytePackWrite8(&data
, num_tracks
);
211 type
= track
->audio
? 0x10 : 0x14;
212 BytePackWrite8(&data
, 0);
213 BytePackWrite8(&data
, type
);
214 BytePackWrite8(&data
, track
->track_num
);
215 BytePackWrite8(&data
, 0);
218 ADDR2MSF(addr
, m
, s
, f
);
219 BytePackWrite8(&data
, 0);
220 BytePackWrite8(&data
, m
);
221 BytePackWrite8(&data
, s
);
222 BytePackWrite8(&data
, f
);
224 BytePackWrite32MSB(&data
, addr
);
226 addr
+= track
->sectors
;
229 BytePackWrite8(&data
, 0);
230 BytePackWrite8(&data
, type
);
231 BytePackWrite8(&data
, 0xaa);
232 BytePackWrite8(&data
, 0);
235 ADDR2MSF(addr
, m
, s
, f
);
236 BytePackWrite8(&data
, 0);
237 BytePackWrite8(&data
, m
);
238 BytePackWrite8(&data
, s
);
239 BytePackWrite8(&data
, f
);
241 BytePackWrite32MSB(&data
, addr
);
244 status
= SCSI_CheckCondition
;
245 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x3a, 0x00);
248 status
= SCSI_CheckCondition
;
249 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x3a, 0x00);
252 status
= SCSI_CheckCondition
;
253 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x24, 0x00);
257 case SCSICMD_READ_CD
:
258 scsi
->scsi_CmdActual
= 12;
259 if (unit
->DeviceType
!= DG_CDROM
) {
260 status
= SCSI_CheckCondition
;
261 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x20, 0x00);
264 if (cmd_len
>= 12 && (cmd
[1] == 0x00 || cmd
[1] == 0x04) &&
265 cmd
[9] == 0x10 && cmd
[10] == 0 && cmd
[11] == 0)
267 if (image
&& plugin
) {
268 if (plugin
->plugin_ReadCDDA
) {
270 addr
= rbe32(&cmd
[2]);
271 frames
= rbe32(&cmd
[6]) >> 8;
274 data
.current
= data
.start
+ Plugin_ReadCDDA(plugin
, image
,
275 data
.start
, addr
, frames
);
278 status
= SCSI_CheckCondition
;
279 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x20, 0x00);
282 status
= SCSI_CheckCondition
;
283 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x3a, 0x00);
286 status
= SCSI_CheckCondition
;
287 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x24, 0x00);
291 case SCSICMD_READ_CD_MSF
:
292 scsi
->scsi_CmdActual
= 12;
293 if (unit
->DeviceType
!= DG_CDROM
) {
294 status
= SCSI_CheckCondition
;
295 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x20, 0x00);
298 if (cmd_len
>= 12 && (cmd
[1] == 0x00 || cmd
[1] == 0x04) &&
299 cmd
[2] == 0 && cmd
[9] == 0x10 && cmd
[10] == 0 && cmd
[11] == 0)
301 if (image
&& plugin
) {
302 if (plugin
->plugin_ReadCDDA
) {
303 ULONG startaddr
, endaddr
;
304 startaddr
= MSF2ADDR(cmd
[3], cmd
[4], cmd
[5]);
305 endaddr
= MSF2ADDR(cmd
[6], cmd
[7], cmd
[8]);
307 if (startaddr
>= (2*75) && endaddr
> startaddr
) {
308 ULONG addr
= startaddr
- (2*75);
309 ULONG frames
= endaddr
- startaddr
;
310 data
.current
= data
.start
+ Plugin_ReadCDDA(plugin
, image
,
311 data
.start
, addr
, frames
);
314 status
= SCSI_CheckCondition
;
315 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x20, 0x00);
318 status
= SCSI_CheckCondition
;
319 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x3a, 0x00);
322 status
= SCSI_CheckCondition
;
323 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x24, 0x00);
328 status
= SCSI_CheckCondition
;
329 WriteSenseData(&sense
, SENSEKEY_IllegalRequest
, 0x20, 0x00);
333 scsi
->scsi_Status
= status
;
334 scsi
->scsi_Actual
= BytePackBytesWritten(&data
);
335 scsi
->scsi_SenseActual
= BytePackBytesWritten(&sense
);
337 if (status
== SCSI_Good
) {
338 return IOERR_SUCCESS
;
340 return HFERR_BadStatus
;