Merging diskimagedevice 52.78 into the main branch.
[AROS.git] / workbench / devs / diskimage / device / scsicmd.c
blob89f398b794b91d223ed9852dd56b1da2acc233cd
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
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"
28 #include "scsicmd.h"
29 #include "endian.h"
30 #include "bytepack.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;
38 dg->dg_Heads = 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;
46 } else {
47 return FALSE;
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;
68 const UBYTE *cmd;
69 ULONG cmd_len;
70 BytePackBuffer data;
71 BytePackBuffer sense;
72 UBYTE status;
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);
84 } else {
85 BytePackInit(&sense, NULL, 0);
88 status = SCSI_Good;
89 scsi->scsi_CmdActual = 1;
90 switch (cmd[0]) {
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) {
97 status = SCSI_Good;
98 } else {
99 status = SCSI_CheckCondition;
100 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x3a, 0x00);
102 } else {
103 status = SCSI_CheckCondition;
104 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x24, 0x00);
106 break;
108 case SCSICMD_INQUIRY:
109 scsi->scsi_CmdActual = 6;
110 if (cmd_len >= 6 && (cmd[1] & 0xfe) == 0 && cmd[3] == 0 && cmd[5] == 0) {
111 if (cmd[1] & 1) {
112 status = SCSI_Good;
113 BytePackWrite8(&data, unit->DeviceType);
114 BytePackWrite8(&data, 0x01);
115 } else if (cmd[2] == 0) {
116 status = SCSI_Good;
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);
126 } else {
127 status = SCSI_CheckCondition;
128 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x24, 0x00);
130 } else {
131 status = SCSI_CheckCondition;
132 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x24, 0x00);
134 break;
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);
141 break;
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)) {
149 status = SCSI_Good;
150 BytePackWrite32MSB(&data, dg.dg_TotalSectors-1);
151 BytePackWrite32MSB(&data, dg.dg_SectorSize);
152 } else {
153 status = SCSI_CheckCondition;
154 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x3a, 0x00);
156 } else {
157 status = SCSI_CheckCondition;
158 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x24, 0x00);
160 break;
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);
167 break;
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);
178 } else {
179 struct DriveGeometry dg;
180 if (GetGeometry(unit, &dg)) {
181 ULONG total_sectors;
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;
191 track = &data_track;
192 num_tracks = 1;
195 if (track && num_tracks) {
196 ULONG addr = 0;
197 UBYTE type = 0x14;
198 status = SCSI_Good;
199 if (cmd[6]) {
200 while (track && track->track_num != cmd[6]) {
201 type = track->audio ? 0x10 : 0x14;
202 addr += track->sectors;
203 track = track->next;
204 num_tracks--;
207 BytePackWrite16MSB(&data, 2 + ((num_tracks + 1) * 8));
208 BytePackWrite8(&data, 1);
209 BytePackWrite8(&data, num_tracks);
210 while (track) {
211 type = track->audio ? 0x10 : 0x14;
212 BytePackWrite8(&data, 0);
213 BytePackWrite8(&data, type);
214 BytePackWrite8(&data, track->track_num);
215 BytePackWrite8(&data, 0);
216 if (cmd[1] & 2) {
217 uint8 m, s, f;
218 ADDR2MSF(addr, m, s, f);
219 BytePackWrite8(&data, 0);
220 BytePackWrite8(&data, m);
221 BytePackWrite8(&data, s);
222 BytePackWrite8(&data, f);
223 } else {
224 BytePackWrite32MSB(&data, addr);
226 addr += track->sectors;
227 track = track->next;
229 BytePackWrite8(&data, 0);
230 BytePackWrite8(&data, type);
231 BytePackWrite8(&data, 0xaa);
232 BytePackWrite8(&data, 0);
233 if (cmd[1] & 2) {
234 uint8 m, s, f;
235 ADDR2MSF(addr, m, s, f);
236 BytePackWrite8(&data, 0);
237 BytePackWrite8(&data, m);
238 BytePackWrite8(&data, s);
239 BytePackWrite8(&data, f);
240 } else {
241 BytePackWrite32MSB(&data, addr);
243 } else {
244 status = SCSI_CheckCondition;
245 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x3a, 0x00);
247 } else {
248 status = SCSI_CheckCondition;
249 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x3a, 0x00);
251 } else {
252 status = SCSI_CheckCondition;
253 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x24, 0x00);
255 break;
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);
262 break;
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) {
269 ULONG addr, frames;
270 addr = rbe32(&cmd[2]);
271 frames = rbe32(&cmd[6]) >> 8;
272 status = SCSI_Good;
273 if (frames > 0) {
274 data.current = data.start + Plugin_ReadCDDA(plugin, image,
275 data.start, addr, frames);
277 } else {
278 status = SCSI_CheckCondition;
279 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x20, 0x00);
281 } else {
282 status = SCSI_CheckCondition;
283 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x3a, 0x00);
285 } else {
286 status = SCSI_CheckCondition;
287 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x24, 0x00);
289 break;
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);
296 break;
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]);
306 status = SCSI_Good;
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);
313 } else {
314 status = SCSI_CheckCondition;
315 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x20, 0x00);
317 } else {
318 status = SCSI_CheckCondition;
319 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x3a, 0x00);
321 } else {
322 status = SCSI_CheckCondition;
323 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x24, 0x00);
325 break;
327 default:
328 status = SCSI_CheckCondition;
329 WriteSenseData(&sense, SENSEKEY_IllegalRequest, 0x20, 0x00);
330 break;
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;
339 } else {
340 return HFERR_BadStatus;