sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
scsi.c
1#include <errno.h>
2#include <stdio.h>
3#include <sysclib.h>
4#include <thsemap.h>
5
6#include "scsi.h"
7#include <bdm.h>
8
9// #define DEBUG //comment out this line when not debugging
10#include "module_debug.h"
11
12#define getBI32(__buf) ((((u8 *)(__buf))[3] << 0) | (((u8 *)(__buf))[2] << 8) | (((u8 *)(__buf))[1] << 16) | (((u8 *)(__buf))[0] << 24))
13#define SCSI_MAX_RETRIES 16
14
15typedef struct _inquiry_data
16{
17 u8 peripheral_device_type; // 00h - Direct access (Floppy), 1Fh none (no FDD connected)
18 u8 removable_media; // 80h - removeable
19 u8 iso_ecma_ansi;
20 u8 response_data_format;
21 u8 additional_length;
22 u8 res[3];
23 u8 vendor[8];
24 u8 product[16];
25 u8 revision[4];
26} inquiry_data;
27static_assert(sizeof(inquiry_data) == 36);
28
29typedef struct _sense_data
30{
31 u8 error_code;
32 u8 res1;
33 u8 sense_key;
34 u8 information[4];
35 u8 add_sense_len;
36 u8 res3[4];
37 u8 add_sense_code;
38 u8 add_sense_qual;
39 u8 res4[4];
40} sense_data;
41
42typedef struct _read_capacity10_data
43{
44 u8 last_lba[4];
45 u8 block_length[4];
46} read_capacity10_data;
47static_assert(sizeof(read_capacity10_data) == 8);
48
49typedef struct _read_capacity16_data
50{
51 u8 last_lba_msb[4];
52 u8 last_lba_lsb[4];
53 u8 block_length[4];
54 u8 args[4];
55 u8 reserved[16];
56} read_capacity16_data;
57static_assert(sizeof(read_capacity16_data) == 32);
58
59#define NUM_DEVICES 2
60static struct block_device g_scsi_bd[NUM_DEVICES];
61
62//
63// Private Low level SCSI commands
64//
65static int scsi_cmd(struct block_device *bd, unsigned char cmd, void *buffer, int buf_size, int cmd_size)
66{
67 unsigned char comData[12] = {0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
68 struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
69
70 // M_DEBUG("%s\n", __func__);
71
72 comData[0] = cmd;
73 comData[4] = cmd_size;
74
75 return scsi->queue_cmd(scsi, comData, sizeof(comData), buffer, buf_size, 0);
76}
77
78static inline int scsi_cmd_test_unit_ready(struct block_device *bd)
79{
80 M_DEBUG("%s\n", __func__);
81
82 return scsi_cmd(bd, TEST_UNIT_READY, NULL, 0, 0);
83}
84
85static inline int scsi_cmd_request_sense(struct block_device *bd, void *buffer, int size)
86{
87 M_DEBUG("%s\n", __func__);
88
89 return scsi_cmd(bd, REQUEST_SENSE, buffer, size, size);
90}
91
92static inline int scsi_cmd_inquiry(struct block_device *bd, void *buffer, int size)
93{
94 M_DEBUG("%s\n", __func__);
95
96 return scsi_cmd(bd, INQUIRY, buffer, size, size);
97}
98
99static int scsi_cmd_start_stop_unit(struct block_device *bd, u8 param)
100{
101 M_DEBUG("%s\n", __func__);
102
103 return scsi_cmd(bd, START_STOP_UNIT, NULL, 0, param);
104}
105
106static inline int scsi_cmd_read_capacity10(struct block_device *bd, void *buffer, int buf_size)
107{
108 M_DEBUG("%s\n", __func__);
109
110 return scsi_cmd(bd, READ_CAPACITY_10, buffer, buf_size, 0);
111}
112
113static inline int scsi_cmd_read_capacity16(struct block_device *bd, void *buffer, int buf_size)
114{
115 unsigned char comData[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
116 struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
117
118 M_DEBUG("%s\n", __func__);
119
120 comData[0] = SERVICE_ACTION_IN;
121 comData[1] = 0x10;
122 comData[13] = buf_size;
123
124 return scsi->queue_cmd(scsi, comData, sizeof(comData), buffer, buf_size, 0);
125}
126
127static int scsi_cmd_rw_sector(struct block_device *bd, u64 lba, const void *buffer, unsigned short int sectorCount, unsigned int write)
128{
129 struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
130
131 DEBUG_U64_2XU32(lba);
132 M_DEBUG("scsi_cmd_rw_sector - 0x%08x%08x %p 0x%04x\n", lba_u32[1], lba_u32[0], buffer, sectorCount);
133
134 if (lba <= 0xffffffffull)
135 {
136 unsigned char comData[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
137 comData[0] = write ? WRITE_10 : READ_10;
138 comData[2] = (lba >> 24) & 0xff; // lba 1 (MSB)
139 comData[3] = (lba >> 16) & 0xff; // lba 2
140 comData[4] = (lba >> 8) & 0xff; // lba 3
141 comData[5] = (lba >> 0) & 0xff; // lba 4 (LSB)
142 comData[7] = (sectorCount >> 8) & 0xff; // Transfer length MSB
143 comData[8] = (sectorCount >> 0) & 0xff; // Transfer length LSB
144 return scsi->queue_cmd(scsi, comData, sizeof(comData), (void *)buffer, bd->sectorSize * sectorCount, write);
145 }
146 else
147 {
148 unsigned char comData[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
149 comData[0] = write ? WRITE_16 : READ_16;
150 comData[2] = (lba >> 56) & 0xff; // lba (MSB)
151 comData[3] = (lba >> 48) & 0xff; // lba
152 comData[4] = (lba >> 40) & 0xff; // lba
153 comData[5] = (lba >> 32) & 0xff; // lba
154 comData[6] = (lba >> 24) & 0xff; // lba
155 comData[7] = (lba >> 16) & 0xff; // lba
156 comData[8] = (lba >> 8) & 0xff; // lba
157 comData[9] = (lba >> 0) & 0xff; // lba (LSB)
158 comData[10] = (sectorCount >> 24) & 0xff; // Transfer length MSB
159 comData[11] = (sectorCount >> 16) & 0xff; // Transfer length
160 comData[12] = (sectorCount >> 8) & 0xff; // Transfer length
161 comData[13] = (sectorCount >> 0) & 0xff; // Transfer length LSB
162 return scsi->queue_cmd(scsi, comData, sizeof(comData), (void *)buffer, bd->sectorSize * sectorCount, write);
163 }
164}
165
166//
167// Private
168//
169static int scsi_warmup(struct block_device *bd)
170{
171 struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
172 inquiry_data id;
173 sense_data sd;
174 read_capacity10_data rc10d;
175 read_capacity16_data rc16d;
176 int stat;
177
178 M_DEBUG("%s\n", __func__);
179
180 stat = scsi->get_max_lun(scsi);
181 M_DEBUG("scsi->get_max_lun %d\n", stat);
182
183 memset(&id, 0, sizeof(inquiry_data));
184 if ((stat = scsi_cmd_inquiry(bd, &id, sizeof(inquiry_data))) < 0) {
185 M_PRINTF("ERROR: scsi_cmd_inquiry %d\n", stat);
186 return -1;
187 }
188
189 M_PRINTF("Vendor: %.8s\n", id.vendor);
190 M_PRINTF("Product: %.16s\n", id.product);
191 M_PRINTF("Revision: %.4s\n", id.revision);
192
193 while ((stat = scsi_cmd_test_unit_ready(bd)) != 0) {
194 M_PRINTF("ERROR: scsi_cmd_test_unit_ready %d\n", stat);
195
196 memset(&sd, 0, sizeof(sense_data));
197 stat = scsi_cmd_request_sense(bd, &sd, sizeof(sense_data));
198 if (stat != 0) {
199 M_PRINTF("ERROR: scsi_cmd_request_sense %d\n", stat);
200 }
201
202 if ((sd.error_code == 0x70) && (sd.sense_key != 0x00)) {
203 M_PRINTF("Sense Data key: %02X code: %02X qual: %02X\n", sd.sense_key, sd.add_sense_code, sd.add_sense_qual);
204
205 if ((sd.sense_key == 0x02) && (sd.add_sense_code == 0x04) && (sd.add_sense_qual == 0x02)) {
206 M_PRINTF("ERROR: Additional initalization is required for this device!\n");
207 if ((stat = scsi_cmd_start_stop_unit(bd, 1)) != 0) {
208 M_PRINTF("ERROR: scsi_cmd_start_stop_unit %d\n", stat);
209 return -1;
210 }
211 }
212 }
213 }
214
215 memset(&rc10d, 0, sizeof(read_capacity10_data));
216 if ((stat = scsi_cmd_read_capacity10(bd, &rc10d, sizeof(read_capacity10_data))) != 0) {
217 M_PRINTF("ERROR: scsi_cmd_read_capacity10 %d\n", stat);
218 return -1;
219 }
220
221 bd->sectorCount = getBI32(&rc10d.last_lba) & 0xffffffff;
222 bd->sectorSize = getBI32(&rc10d.block_length);
223 bd->sectorOffset = 0;
224
225 u64 sectorCount = bd->sectorCount;
226 U64_2XU32(sectorCount);
227 M_PRINTF("rc10 = 0x%08x%08x %u-byte logical blocks: (%lu MB / %lu MiB)\n", sectorCount_u32[1], sectorCount_u32[0], bd->sectorSize,
228 (u32)(bd->sectorCount / ((1000 * 1000) / bd->sectorSize)), (u32)(bd->sectorCount / ((1024 * 1024) / bd->sectorSize)));
229
230 if (bd->sectorCount == 0xffffffffull)
231 {
232 memset(&rc16d, 0, sizeof(read_capacity16_data));
233 if (scsi_cmd_read_capacity16(bd, &rc16d, sizeof(read_capacity16_data)) == 0) {
234 bd->sectorCount = ((u64)getBI32(&rc16d.last_lba_msb) << 32) | (getBI32(&rc16d.last_lba_lsb) & 0xffffffff);
235 bd->sectorSize = getBI32(&rc16d.block_length);
236 bd->sectorOffset = 0;
237
238 sectorCount = bd->sectorCount;
239 U64_2XU32(sectorCount);
240 M_PRINTF("rc16 = 0x%08x%08x %u-byte logical blocks: (%lu MB / %lu MiB)\n", sectorCount_u32[1], sectorCount_u32[0], bd->sectorSize,
241 (u32)(bd->sectorCount / ((1000 * 1000) / bd->sectorSize)), (u32)(bd->sectorCount / ((1024 * 1024) / bd->sectorSize)));
242 }
243 }
244
245 return 0;
246}
247
248//
249// Block device interface
250//
251static int scsi_read(struct block_device *bd, u64 sector, void *buffer, u16 count)
252{
253 struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
254 u16 sc_remaining = count;
255 int retries;
256
257 DEBUG_U64_2XU32(sector);
258 M_DEBUG("%s: sector=0x%08x%08x, count=%d\n", __func__, sector_u32[1], sector_u32[0], count);
259
260 while (sc_remaining > 0) {
261 u16 sc = sc_remaining > scsi->max_sectors ? scsi->max_sectors : sc_remaining;
262
263 for (retries = SCSI_MAX_RETRIES; retries > 0; retries--) {
264 if (scsi_cmd_rw_sector(bd, sector, buffer, sc, 0) == 0)
265 break;
266 }
267
268 if (retries == 0) {
269 U64_2XU32(sector);
270 M_PRINTF("ERROR: unable to read sector after %d tries (sector=0x%08x%08x, count=%d)\n", SCSI_MAX_RETRIES, sector_u32[1], sector_u32[0], count);
271 return -EIO;
272 }
273
274 sc_remaining -= sc;
275 sector += sc;
276 buffer = (u8 *)buffer + (sc * bd->sectorSize);
277 }
278
279 return count;
280}
281
282static int scsi_write(struct block_device *bd, u64 sector, const void *buffer, u16 count)
283{
284 struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
285 u16 sc_remaining = count;
286 unsigned int sectorSize = bd->sectorSize;
287 void *misalign_buffer = NULL;
288 int retries;
289
290 DEBUG_U64_2XU32(sector);
291 M_DEBUG("%s: sector=0x%08x%08x, count=%d\n", __func__, sector_u32[1], sector_u32[0], count);
292
293 if (((uiptr)buffer & 3) != 0) {
294 /* Slow misalignment workaround */
295 misalign_buffer = __builtin_alloca(sectorSize + 4);
296
297 if (((uiptr)misalign_buffer & 3) != 0)
298 {
299 misalign_buffer = (u8 *)misalign_buffer + (4 - ((uiptr)misalign_buffer & 3));
300 }
301 }
302
303 while (sc_remaining > 0) {
304 u16 sc = sc_remaining > scsi->max_sectors ? scsi->max_sectors : sc_remaining;
305 const void *dst_buffer = buffer;
306
307 if (misalign_buffer != NULL) {
308 memcpy(misalign_buffer, buffer, sectorSize);
309 dst_buffer = misalign_buffer;
310 sc = 1;
311 }
312
313 for (retries = SCSI_MAX_RETRIES; retries > 0; retries--) {
314 if (scsi_cmd_rw_sector(bd, sector, dst_buffer, sc, 1) == 0)
315 break;
316 }
317
318 if (retries == 0) {
319 U64_2XU32(sector);
320 M_PRINTF("ERROR: unable to write sector after %d tries (sector=0x%08x%08x, count=%d)\n", SCSI_MAX_RETRIES, sector_u32[1], sector_u32[0], count);
321 return -EIO;
322 }
323
324 sc_remaining -= sc;
325 sector += sc;
326 buffer = (u8 *)buffer + (sc * sectorSize);
327 }
328
329 return count;
330}
331
332static void scsi_flush(struct block_device *bd)
333{
334 (void)bd;
335
336 M_DEBUG("%s\n", __func__);
337
338 // Dummy function
339}
340
341static int scsi_stop(struct block_device *bd)
342{
343 int stat;
344
345 M_DEBUG("%s\n", __func__);
346
347 if ((stat = scsi_cmd_start_stop_unit(bd, 0)) != 0) {
348 M_PRINTF("ERROR: scsi_cmd_start_stop_unit %d\n", stat);
349 }
350
351 return stat;
352}
353
354//
355// Public functions
356//
357void scsi_connect(struct scsi_interface *scsi)
358{
359 int i;
360
361 M_DEBUG("%s\n", __func__);
362
363 for (i = 0; i < NUM_DEVICES; ++i) {
364 if (g_scsi_bd[i].priv == NULL) {
365 struct block_device *bd = &g_scsi_bd[i];
366
367 bd->priv = scsi;
368 bd->name = scsi->name;
369 bd->path = "usb";
370 bd->devNr = scsi->devNr;
371 scsi_warmup(bd);
372 bdm_connect_bd(bd);
373 break;
374 }
375 }
376}
377
378void scsi_disconnect(struct scsi_interface *scsi)
379{
380 int i;
381
382 M_DEBUG("%s\n", __func__);
383
384 for (i = 0; i < NUM_DEVICES; ++i) {
385 if (g_scsi_bd[i].priv == scsi) {
386 struct block_device *bd = &g_scsi_bd[i];
387 bdm_disconnect_bd(bd);
388 bd->priv = NULL;
389 break;
390 }
391 }
392}
393
394int scsi_init(void)
395{
396 int i;
397
398 M_DEBUG("%s\n", __func__);
399
400 for (i = 0; i < NUM_DEVICES; ++i) {
401 g_scsi_bd[i].parNr = 0;
402 g_scsi_bd[i].parId = 0x00;
403
404 g_scsi_bd[i].priv = NULL;
405 g_scsi_bd[i].read = scsi_read;
406 g_scsi_bd[i].write = scsi_write;
407 g_scsi_bd[i].flush = scsi_flush;
408 g_scsi_bd[i].stop = scsi_stop;
409 }
410
411 return 0;
412}
#define EIO
Definition errno.h:38
u32 count
start sector of fragmented bd/file