2 Copyright © 2011, 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
)
25 static void ww(UBYTE
*p
, UWORD v
)
30 static ULONG
rl(UBYTE
*p
)
32 return (p
[0] << 24) | (p
[1] << 16) | (p
[2] << 8) | (p
[3]);
35 static UBYTE
scsi_read32(struct ata_Unit
*unit
, APTR data
, ULONG offset
, ULONG len
, ULONG
*outlen
)
37 return unit
->au_Read32(unit
, offset
, len
, data
, outlen
);
39 static UBYTE
scsi_write32(struct ata_Unit
*unit
, APTR data
, ULONG offset
, ULONG len
, ULONG
*outlen
)
41 return unit
->au_Write32(unit
, offset
, len
, data
, outlen
);
44 static UBYTE
scsi_inquiry(struct ata_Unit
*unit
, struct SCSICmd
*cmd
, ULONG
*outlen
)
46 UBYTE
*cmdbuf
= cmd
->scsi_Command
;
47 UBYTE
*out
= (UBYTE
*)cmd
->scsi_Data
;
50 if ((cmdbuf
[1] & 1) || cmdbuf
[2] != 0)
54 return 0xff; /* no lun supported */
55 out
[2] = 2; /* supports SCSI-2 */
56 out
[3] = 2; /* response data format */
57 out
[4] = 32; /* additional length */
58 out
[7] = 0x20; /* 16 bit bus */
59 *outlen
= len
< 36 ? len
: 36;
60 memset(out
+ 8, ' ', 8 + 16 + 4);
61 CopyMem(unit
->au_Model
, out
+ 8, strlen(unit
->au_Model
) > 16 + 8 ? 16 + 8 : strlen(unit
->au_Model
));
62 CopyMem(unit
->au_FirmwareRev
, out
+ 8 + 16, strlen(unit
->au_FirmwareRev
) > 4 ? 4 : strlen(unit
->au_FirmwareRev
));
66 static UBYTE
scsi_modesense(struct ata_Unit
*unit
, struct SCSICmd
*cmd
, ULONG
*outlen
)
68 UBYTE
*cmdbuf
= cmd
->scsi_Command
;
69 UBYTE
*out
= (UBYTE
*)cmd
->scsi_Data
;
70 UBYTE pcode
= cmdbuf
[2] & 0x3f;
71 UBYTE dbd
= cmdbuf
[1] & 8;
72 UWORD blocksize
= 1 << unit
->au_SectorShift
;
83 wl(out
+ 0, unit
->au_Capacity
);
84 wl(out
+ 4, blocksize
);
93 } else if (pcode
== 3) {
97 p
[10] = unit
->au_Sectors
>> 8;
98 p
[11] = unit
->au_Sectors
;
99 p
[12] = blocksize
>> 8;
101 p
[15] = 1; // interleave
104 } else if (pcode
== 4) {
106 wl(p
+ 1, unit
->au_Cylinders
);
108 p
[5] = unit
->au_Heads
;
109 wl(p
+ 13, unit
->au_Cylinders
);
116 *outlen
= out
[0] + 1;
120 static UBYTE
scsi_readcapacity(struct ata_Unit
*unit
, struct SCSICmd
*cmd
, ULONG
*outlen
)
122 UBYTE
*cmdbuf
= cmd
->scsi_Command
;
123 UBYTE
*out
= (UBYTE
*)cmd
->scsi_Data
;
127 blocks
= unit
->au_Capacity
;
129 lba
= (cmdbuf
[2] << 24) | (cmdbuf
[3] << 16) | (cmdbuf
[4] << 8) | cmdbuf
[5];
130 if (pmi
== 0 && lba
!= 0)
133 UWORD cylsize
= unit
->au_Heads
* unit
->au_Sectors
;
141 wl (out
+ 0, blocks
);
142 wl (out
+ 4, 1 << unit
->au_SectorShift
);
147 UBYTE
SCSIEmu(struct ata_Unit
*unit
, struct SCSICmd
*cmd
)
151 UWORD scsi_sense_len
= (cmd
->scsi_Flags
& (1 << SCSIB_OLDAUTOSENSE
)) ? 4 :
152 (cmd
->scsi_Flags
& (1 << SCSIB_AUTOSENSE
)) ? cmd
->scsi_SenseLength
: 32;
153 UBYTE
*cmdbuf
= cmd
->scsi_Command
;
158 /* bug("SCSIEMU CMD=%02x\n", cmdbuf[0]); */
163 if (scsi_sense_len
> sizeof sense
)
164 scsi_sense_len
= sizeof sense
;
167 case 0x00: /* TEST UNIT READY */
170 case 0x08: /* READ (6) */
171 offset
= ((cmdbuf
[1] & 31) << 16) | (cmdbuf
[2] << 8) | cmdbuf
[3];
175 err
= scsi_read32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
177 case 0x28: /* READ (10) */
178 offset
= rl(cmdbuf
+ 2);
179 len
= rl(cmdbuf
+ 7 - 2) & 0xffff;
180 err
= scsi_read32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
182 case 0xa8: /* READ (12) */
183 offset
= rl(cmdbuf
+ 2);
184 len
= rl(cmdbuf
+ 6);
185 err
= scsi_read32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
187 case 0x0a: /* WRITE (6) */
188 offset
= ((cmdbuf
[1] & 31) << 16) | (cmdbuf
[2] << 8) | cmdbuf
[3];
192 err
= scsi_write32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
194 case 0x2a: /* WRITE (10) */
195 offset
= rl(cmdbuf
+ 2);
196 len
= rl(cmdbuf
+ 7 - 2) & 0xffff;
197 err
= scsi_write32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
199 case 0xaa: /* WRITE (12) */
200 offset
= rl(cmdbuf
+ 2);
201 len
= rl(cmdbuf
+ 6);
202 err
= scsi_write32(unit
, cmd
->scsi_Data
, offset
, len
, &scsi_len
);
205 case 0x37: /* READ DEFECT DATA */
208 memset(sense
, 0, senselen
);
214 case 0x12: /* INQUIRY */
215 err
= scsi_inquiry(unit
, cmd
, &scsi_len
);
217 case 0x1a: /* MODE SENSE(6) */
218 err
= scsi_modesense(unit
, cmd
, &scsi_len
);
220 case 0x25: /* READ CAPACITY */
221 err
= scsi_readcapacity(unit
, cmd
, &scsi_len
);
224 case 0x1d: /* SEND DIAGNOSTICS */
225 case 0x35: /* SYNCRONIZE CACHE */
234 status
= 2; /* CHECK CONDITION */
236 memset(sense
, 0, senselen
);
238 sense
[2] = 5; /* ILLEGAL REQUEST */
239 sense
[12] = 0x24; /* ILLEGAL FIELD IN CDB */
244 if (senselen
> scsi_sense_len
)
245 senselen
= scsi_sense_len
;
246 CopyMem(sense
, cmd
->scsi_SenseData
, senselen
);
247 cmd
->scsi_SenseActual
= senselen
;
249 cmd
->scsi_Status
= status
;
250 cmd
->scsi_CmdActual
= status
!= 0 ? 0 : cmd
->scsi_CmdLength
;
251 cmd
->scsi_Actual
= scsi_len
;