PS2SDK
PS2 Homebrew Libraries
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 
15 typedef 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;
27 static_assert(sizeof(inquiry_data) == 36);
28 
29 typedef 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 
42 typedef struct _read_capacity10_data
43 {
44  u8 last_lba[4];
45  u8 block_length[4];
47 static_assert(sizeof(read_capacity10_data) == 8);
48 
49 typedef 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];
57 static_assert(sizeof(read_capacity16_data) == 32);
58 
59 #define NUM_DEVICES 2
60 static struct block_device g_scsi_bd[NUM_DEVICES];
61 
62 //
63 // Private Low level SCSI commands
64 //
65 static 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 
78 static 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 
85 static 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 
92 static 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 
99 static 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 
106 static 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 
113 static 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 
127 static 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 //
169 static 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 //
251 static 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  return -EIO;
270 
271  sc_remaining -= sc;
272  sector += sc;
273  buffer = (u8 *)buffer + (sc * bd->sectorSize);
274  }
275 
276  return count;
277 }
278 
279 static int scsi_write(struct block_device *bd, u64 sector, const void *buffer, u16 count)
280 {
281  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
282  u16 sc_remaining = count;
283  int retries;
284 
285  DEBUG_U64_2XU32(sector);
286  M_DEBUG("%s: sector=0x%08x%08x, count=%d\n", __func__, sector_u32[1], sector_u32[0], count);
287 
288  while (sc_remaining > 0) {
289  u16 sc = sc_remaining > scsi->max_sectors ? scsi->max_sectors : sc_remaining;
290 
291  for (retries = SCSI_MAX_RETRIES; retries > 0; retries--) {
292  if (scsi_cmd_rw_sector(bd, sector, buffer, sc, 1) == 0)
293  break;
294  }
295 
296  if (retries == 0)
297  return -EIO;
298 
299  sc_remaining -= sc;
300  sector += sc;
301  buffer = (u8 *)buffer + (sc * bd->sectorSize);
302  }
303 
304  return count;
305 }
306 
307 static void scsi_flush(struct block_device *bd)
308 {
309  (void)bd;
310 
311  M_DEBUG("%s\n", __func__);
312 
313  // Dummy function
314 }
315 
316 static int scsi_stop(struct block_device *bd)
317 {
318  int stat;
319 
320  M_DEBUG("%s\n", __func__);
321 
322  if ((stat = scsi_cmd_start_stop_unit(bd, 0)) != 0) {
323  M_PRINTF("ERROR: scsi_cmd_start_stop_unit %d\n", stat);
324  }
325 
326  return stat;
327 }
328 
329 //
330 // Public functions
331 //
332 void scsi_connect(struct scsi_interface *scsi)
333 {
334  int i;
335 
336  M_DEBUG("%s\n", __func__);
337 
338  for (i = 0; i < NUM_DEVICES; ++i) {
339  if (g_scsi_bd[i].priv == NULL) {
340  struct block_device *bd = &g_scsi_bd[i];
341 
342  bd->priv = scsi;
343  bd->name = scsi->name;
344  bd->path = "ilink";
345  bd->devNr = scsi->devNr;
346  scsi_warmup(bd);
347  bdm_connect_bd(bd);
348  break;
349  }
350  }
351 }
352 
353 void scsi_disconnect(struct scsi_interface *scsi)
354 {
355  int i;
356 
357  M_DEBUG("%s\n", __func__);
358 
359  for (i = 0; i < NUM_DEVICES; ++i) {
360  if (g_scsi_bd[i].priv == scsi) {
361  struct block_device *bd = &g_scsi_bd[i];
362  bdm_disconnect_bd(bd);
363  bd->priv = NULL;
364  break;
365  }
366  }
367 }
368 
369 int scsi_init(void)
370 {
371  int i;
372 
373  M_DEBUG("%s\n", __func__);
374 
375  for (i = 0; i < NUM_DEVICES; ++i) {
376  g_scsi_bd[i].parNr = 0;
377  g_scsi_bd[i].parId = 0x00;
378 
379  g_scsi_bd[i].priv = NULL;
380  g_scsi_bd[i].read = scsi_read;
381  g_scsi_bd[i].write = scsi_write;
382  g_scsi_bd[i].flush = scsi_flush;
383  g_scsi_bd[i].stop = scsi_stop;
384  }
385 
386  return 0;
387 }
_inquiry_data
Definition: scsi.c:15
bdm.h
sysclib.h
_read_capacity16_data
Definition: scsi.c:49
EIO
#define EIO
Definition: errno.h:29
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
thsemap.h
stdio.h
_sense_data
Definition: scsi.c:29
_read_capacity10_data
Definition: scsi.c:42
block_device
Definition: bdm.h:21
scsi_interface
Definition: scsi.h:4
errno.h