2 Copyright © 2011-2012, The AROS Development Team. All rights reserved
5 Desc: Simple HD_SCSICMD emulator.
9 #include <aros/debug.h>
11 #include <exec/types.h>
12 #include <exec/exec.h>
13 #include <proto/exec.h>
14 #include <devices/scsidisk.h>
18 static void wl(UBYTE
*p
, ULONG v
)
26 static void ww(UBYTE
*p
, UWORD v
)
32 static ULONG
rl(UBYTE
*p
)
34 return (p
[0] << 24) | (p
[1] << 16) | (p
[2] << 8) | (p
[3]);
37 static UBYTE
scsi_read32(struct ata_Unit
*unit
, APTR data
, ULONG offset
, ULONG len
, ULONG
*outlen
)
39 return unit
->au_Read32(unit
, offset
, len
, data
, outlen
);
42 static UBYTE
scsi_write32(struct ata_Unit
*unit
, APTR data
, ULONG offset
, ULONG len
, ULONG
*outlen
)
44 return unit
->au_Write32(unit
, offset
, len
, data
, outlen
);
47 static UBYTE
scsi_inquiry(struct ata_Unit
*unit
, struct SCSICmd
*cmd
, ULONG
*outlen
)
49 UBYTE
*cmdbuf
= cmd
->scsi_Command
;
50 UBYTE
*out
= (UBYTE
*)cmd
->scsi_Data
;
53 if ((cmdbuf
[1] & 1) || cmdbuf
[2] != 0)
57 return 0xff; /* no lun supported */
58 out
[2] = 2; /* supports SCSI-2 */
59 out
[3] = 2; /* response data format */
60 out
[4] = 32; /* additional length */
61 out
[7] = 0x20; /* 16 bit bus */
62 *outlen
= len
< 36 ? len
: 36;
63 memset(out
+ 8, ' ', 8 + 16 + 4);
64 CopyMem(unit
->au_Model
, out
+ 8, strlen(unit
->au_Model
) > 16 + 8 ? 16 + 8 : strlen(unit
->au_Model
));
65 CopyMem(unit
->au_FirmwareRev
, out
+ 8 + 16, strlen(unit
->au_FirmwareRev
) > 4 ? 4 : strlen(unit
->au_FirmwareRev
));
69 static UBYTE
scsi_modesense(struct ata_Unit
*unit
, struct SCSICmd
*cmd
, ULONG
*outlen
)
71 UBYTE
*cmdbuf
= cmd
->scsi_Command
;
72 UBYTE
*out
= (UBYTE
*)cmd
->scsi_Data
;
73 UBYTE pcode
= cmdbuf
[2] & 0x3f;
74 UBYTE dbd
= cmdbuf
[1] & 8;
75 UWORD blocksize
= 1 << unit
->au_SectorShift
;
86 wl(out
+ 0, unit
->au_Capacity
);
87 wl(out
+ 4, blocksize
);
96 } else if (pcode
== 3) {
100 p
[10] = unit
->au_Sectors
>> 8;
101 p
[11] = unit
->au_Sectors
;
102 p
[12] = blocksize
>> 8;
104 p
[15] = 1; // interleave
107 } else if (pcode
== 4) {
109 wl(p
+ 1, unit
->au_Cylinders
);
111 p
[5] = unit
->au_Heads
;
112 wl(p
+ 13, unit
->au_Cylinders
);
119 *outlen
= out
[0] + 1;
123 static UBYTE
scsi_readcapacity(struct ata_Unit
*unit
, struct SCSICmd
*cmd
, ULONG
*outlen
)
125 UBYTE
*cmdbuf
= cmd
->scsi_Command
;
126 UBYTE
*out
= (UBYTE
*)cmd
->scsi_Data
;
130 blocks
= unit
->au_Capacity
;
132 lba
= (cmdbuf
[2] << 24) | (cmdbuf
[3] << 16) | (cmdbuf
[4] << 8) | cmdbuf
[5];
133 if (pmi
== 0 && lba
!= 0)
136 UWORD cylsize
= unit
->au_Heads
* unit
->au_Sectors
;
144 wl (out
+ 0, blocks
);
145 wl (out
+ 4, 1 << unit
->au_SectorShift
);
150 BYTE
SCSIEmu(struct ata_Unit
*unit
, struct SCSICmd
*cmd
)
154 UWORD scsi_sense_len
= (cmd
->scsi_Flags
& (1 << SCSIB_OLDAUTOSENSE
)) ? 4 :
155 (cmd
->scsi_Flags
& (1 << SCSIB_AUTOSENSE
)) ? cmd
->scsi_SenseLength
: 0;
156 UBYTE
*cmdbuf
= cmd
->scsi_Command
;
161 /* bug("SCSIEMU CMD=%02x\n", cmdbuf[0]); */
166 if (scsi_sense_len
> sizeof sense
)
167 scsi_sense_len
= sizeof sense
;
170 case 0x00: /* TEST UNIT READY */
173 case 0x08: /* READ (6) */
174 offset
= ((cmdbuf
[1] & 31) << 16) | (cmdbuf
[2] << 8) | cmdbuf
[3];
178 err
= scsi_read32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
180 case 0x28: /* READ (10) */
181 offset
= rl(cmdbuf
+ 2);
182 len
= rl(cmdbuf
+ 7 - 2) & 0xffff;
183 err
= scsi_read32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
185 case 0xa8: /* READ (12) */
186 offset
= rl(cmdbuf
+ 2);
187 len
= rl(cmdbuf
+ 6);
188 err
= scsi_read32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
190 case 0x0a: /* WRITE (6) */
191 offset
= ((cmdbuf
[1] & 31) << 16) | (cmdbuf
[2] << 8) | cmdbuf
[3];
195 err
= scsi_write32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
197 case 0x2a: /* WRITE (10) */
198 offset
= rl(cmdbuf
+ 2);
199 len
= rl(cmdbuf
+ 7 - 2) & 0xffff;
200 err
= scsi_write32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
202 case 0xaa: /* WRITE (12) */
203 offset
= rl(cmdbuf
+ 2);
204 len
= rl(cmdbuf
+ 6);
205 err
= scsi_write32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
208 case 0x37: /* READ DEFECT DATA */
211 memset(sense
, 0, senselen
);
217 case 0x12: /* INQUIRY */
218 err
= scsi_inquiry(unit
, cmd
, &scsi_len
);
220 case 0x1a: /* MODE SENSE(6) */
221 err
= scsi_modesense(unit
, cmd
, &scsi_len
);
223 case 0x25: /* READ CAPACITY */
224 err
= scsi_readcapacity(unit
, cmd
, &scsi_len
);
227 case 0x1d: /* SEND DIAGNOSTICS */
228 case 0x35: /* SYNCHRONIZE CACHE */
237 status
= 2; /* CHECK CONDITION */
239 memset(sense
, 0, senselen
);
241 sense
[2] = 5; /* ILLEGAL REQUEST */
242 sense
[12] = 0x24; /* ILLEGAL FIELD IN CDB */
243 err
= TDERR_NotSpecified
;
246 if (senselen
&& scsi_sense_len
) {
247 if (senselen
> scsi_sense_len
)
248 senselen
= scsi_sense_len
;
249 CopyMem(sense
, cmd
->scsi_SenseData
, senselen
);
250 cmd
->scsi_SenseActual
= senselen
;
252 cmd
->scsi_Status
= status
;
253 cmd
->scsi_CmdActual
= status
!= 0 ? 0 : cmd
->scsi_CmdLength
;
254 cmd
->scsi_Actual
= scsi_len
;