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, 12, 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, 0x00, 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, 0x03, 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, 0x12, 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, 0x1b, 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, 0x25, 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] = 0x9e;
121  comData[1] = 0x10;
122  comData[13] = buf_size;
123 
124  return scsi->queue_cmd(scsi, comData, 16, 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  unsigned char comData[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
130  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
131 
132  DEBUG_U64_2XU32(lba);
133  M_DEBUG("scsi_cmd_rw_sector - 0x%08x%08x %p 0x%04x\n", lba_u32[1], lba_u32[0], buffer, sectorCount);
134 
135  // Note: LBA from bdm is 64bit but SCSI commands being used are 32bit. These need to be updated to 64bit LBA SCSI
136  // commands to work with large capacity drives. For now the 32bit LBA will only support up to 2TB drives.
137 
138  comData[0] = write ? 0x2a : 0x28;
139  comData[2] = (lba & 0xFF000000) >> 24; // lba 1 (MSB)
140  comData[3] = (lba & 0xFF0000) >> 16; // lba 2
141  comData[4] = (lba & 0xFF00) >> 8; // lba 3
142  comData[5] = (lba & 0xFF); // lba 4 (LSB)
143  comData[7] = (sectorCount & 0xFF00) >> 8; // Transfer length MSB
144  comData[8] = (sectorCount & 0xFF); // Transfer length LSB
145  return scsi->queue_cmd(scsi, comData, 12, (void *)buffer, bd->sectorSize * sectorCount, write);
146 }
147 
148 //
149 // Private
150 //
151 static int scsi_warmup(struct block_device *bd)
152 {
153  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
154  inquiry_data id;
155  sense_data sd;
156  int stat;
157 
158  M_DEBUG("%s\n", __func__);
159 
160  stat = scsi->get_max_lun(scsi);
161  M_DEBUG("scsi->get_max_lun %d\n", stat);
162 
163  memset(&id, 0, sizeof(inquiry_data));
164  if ((stat = scsi_cmd_inquiry(bd, &id, sizeof(inquiry_data))) < 0) {
165  M_PRINTF("ERROR: scsi_cmd_inquiry %d\n", stat);
166  return -1;
167  }
168 
169  M_PRINTF("Vendor: %.8s\n", id.vendor);
170  M_PRINTF("Product: %.16s\n", id.product);
171  M_PRINTF("Revision: %.4s\n", id.revision);
172 
173  while ((stat = scsi_cmd_test_unit_ready(bd)) != 0) {
174  M_PRINTF("ERROR: scsi_cmd_test_unit_ready %d\n", stat);
175 
176  memset(&sd, 0, sizeof(sense_data));
177  stat = scsi_cmd_request_sense(bd, &sd, sizeof(sense_data));
178  if (stat != 0) {
179  M_PRINTF("ERROR: scsi_cmd_request_sense %d\n", stat);
180  }
181 
182  if ((sd.error_code == 0x70) && (sd.sense_key != 0x00)) {
183  M_PRINTF("Sense Data key: %02X code: %02X qual: %02X\n", sd.sense_key, sd.add_sense_code, sd.add_sense_qual);
184 
185  if ((sd.sense_key == 0x02) && (sd.add_sense_code == 0x04) && (sd.add_sense_qual == 0x02)) {
186  M_PRINTF("ERROR: Additional initalization is required for this device!\n");
187  if ((stat = scsi_cmd_start_stop_unit(bd, 1)) != 0) {
188  M_PRINTF("ERROR: scsi_cmd_start_stop_unit %d\n", stat);
189  return -1;
190  }
191  }
192  }
193  }
194 
195  //*
196  read_capacity10_data rc10d;
197  memset(&rc10d, 0, sizeof(read_capacity10_data));
198  if ((stat = scsi_cmd_read_capacity10(bd, &rc10d, sizeof(read_capacity10_data))) != 0) {
199  M_PRINTF("ERROR: scsi_cmd_read_capacity10 %d\n", stat);
200  return -1;
201  }
202  bd->sectorCount = getBI32(&rc10d.last_lba);
203  bd->sectorSize = getBI32(&rc10d.block_length);
204  bd->sectorOffset = 0;
205  /*/
206  read_capacity16_data rc16d;
207  memset(&rc16d, 0, sizeof(read_capacity16_data));
208  if ((stat = scsi_cmd_read_capacity16(bd, &rc16d, sizeof(read_capacity16_data))) != 0) {
209  M_PRINTF("ERROR: scsi_cmd_read_capacity16 %d\n", stat);
210  return -1;
211  }
212  bd->sectorCount = ((u64)getBI32(&rc16d.last_lba_msb) << 32) | (getBI32(&rc16d.last_lba_lsb));
213  bd->sectorSize = getBI32(&rc16d.block_length);
214  bd->sectorOffset = 0;
215  //*/
216 
217  u64 sectorCount = bd->sectorCount;
218  U64_2XU32(sectorCount);
219  M_PRINTF("0x%08x%08x %u-byte logical blocks: (%lu MB / %lu MiB)\n", sectorCount_u32[1], sectorCount_u32[0], bd->sectorSize,
220  (u32)(bd->sectorCount / ((1000 * 1000) / bd->sectorSize)), (u32)(bd->sectorCount / ((1024 * 1024) / bd->sectorSize)));
221 
222  return 0;
223 }
224 
225 //
226 // Block device interface
227 //
228 static int scsi_read(struct block_device *bd, u64 sector, void *buffer, u16 count)
229 {
230  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
231  u16 sc_remaining = count;
232  int retries;
233 
234  DEBUG_U64_2XU32(sector);
235  M_DEBUG("%s: sector=0x%08x%08x, count=%d\n", __func__, sector_u32[1], sector_u32[0], count);
236 
237  while (sc_remaining > 0) {
238  u16 sc = sc_remaining > scsi->max_sectors ? scsi->max_sectors : sc_remaining;
239 
240  for (retries = SCSI_MAX_RETRIES; retries > 0; retries--) {
241  if (scsi_cmd_rw_sector(bd, sector, buffer, sc, 0) == 0)
242  break;
243  }
244 
245  if (retries == 0)
246  return -EIO;
247 
248  sc_remaining -= sc;
249  sector += sc;
250  buffer = (u8 *)buffer + (sc * bd->sectorSize);
251  }
252 
253  return count;
254 }
255 
256 static int scsi_write(struct block_device *bd, u64 sector, const void *buffer, u16 count)
257 {
258  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
259  u16 sc_remaining = count;
260  int retries;
261 
262  DEBUG_U64_2XU32(sector);
263  M_DEBUG("%s: sector=0x%08x%08x, count=%d\n", __func__, sector_u32[1], sector_u32[0], count);
264 
265  while (sc_remaining > 0) {
266  u16 sc = sc_remaining > scsi->max_sectors ? scsi->max_sectors : sc_remaining;
267 
268  for (retries = SCSI_MAX_RETRIES; retries > 0; retries--) {
269  if (scsi_cmd_rw_sector(bd, sector, buffer, sc, 1) == 0)
270  break;
271  }
272 
273  if (retries == 0)
274  return -EIO;
275 
276  sc_remaining -= sc;
277  sector += sc;
278  buffer = (u8 *)buffer + (sc * bd->sectorSize);
279  }
280 
281  return count;
282 }
283 
284 static void scsi_flush(struct block_device *bd)
285 {
286  (void)bd;
287 
288  M_DEBUG("%s\n", __func__);
289 
290  // Dummy function
291 }
292 
293 static int scsi_stop(struct block_device *bd)
294 {
295  int stat;
296 
297  M_DEBUG("%s\n", __func__);
298 
299  if ((stat = scsi_cmd_start_stop_unit(bd, 0)) != 0) {
300  M_PRINTF("ERROR: scsi_cmd_start_stop_unit %d\n", stat);
301  }
302 
303  return stat;
304 }
305 
306 //
307 // Public functions
308 //
309 void scsi_connect(struct scsi_interface *scsi)
310 {
311  int i;
312 
313  M_DEBUG("%s\n", __func__);
314 
315  for (i = 0; i < NUM_DEVICES; ++i) {
316  if (g_scsi_bd[i].priv == NULL) {
317  struct block_device *bd = &g_scsi_bd[i];
318 
319  bd->priv = scsi;
320  bd->name = scsi->name;
321  bd->path = "ilink";
322  bd->devNr = scsi->devNr;
323  scsi_warmup(bd);
324  bdm_connect_bd(bd);
325  break;
326  }
327  }
328 }
329 
330 void scsi_disconnect(struct scsi_interface *scsi)
331 {
332  int i;
333 
334  M_DEBUG("%s\n", __func__);
335 
336  for (i = 0; i < NUM_DEVICES; ++i) {
337  if (g_scsi_bd[i].priv == scsi) {
338  struct block_device *bd = &g_scsi_bd[i];
339  bdm_disconnect_bd(bd);
340  bd->priv = NULL;
341  break;
342  }
343  }
344 }
345 
346 int scsi_init(void)
347 {
348  int i;
349 
350  M_DEBUG("%s\n", __func__);
351 
352  for (i = 0; i < NUM_DEVICES; ++i) {
353  g_scsi_bd[i].parNr = 0;
354  g_scsi_bd[i].parId = 0x00;
355 
356  g_scsi_bd[i].priv = NULL;
357  g_scsi_bd[i].read = scsi_read;
358  g_scsi_bd[i].write = scsi_write;
359  g_scsi_bd[i].flush = scsi_flush;
360  g_scsi_bd[i].stop = scsi_stop;
361  }
362 
363  return 0;
364 }
_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