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 
28 typedef struct _sense_data
29 {
30  u8 error_code;
31  u8 res1;
32  u8 sense_key;
33  u8 information[4];
34  u8 add_sense_len;
35  u8 res3[4];
36  u8 add_sense_code;
37  u8 add_sense_qual;
38  u8 res4[4];
39 } sense_data;
40 
41 typedef struct _read_capacity_data
42 {
43  u8 last_lba[4];
44  u8 block_length[4];
46 
47 #define NUM_DEVICES 2
48 static struct block_device g_scsi_bd[NUM_DEVICES];
49 
50 //
51 // Private Low level SCSI commands
52 //
53 static int scsi_cmd(struct block_device *bd, unsigned char cmd, void *buffer, int buf_size, int cmd_size)
54 {
55  unsigned char comData[12] = {0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
56  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
57 
58  // M_DEBUG("%s\n", __func__);
59 
60  comData[0] = cmd;
61  comData[4] = cmd_size;
62 
63  return scsi->queue_cmd(scsi, comData, 12, buffer, buf_size, 0);
64 }
65 
66 static inline int scsi_cmd_test_unit_ready(struct block_device *bd)
67 {
68  M_DEBUG("%s\n", __func__);
69 
70  return scsi_cmd(bd, 0x00, NULL, 0, 0);
71 }
72 
73 static inline int scsi_cmd_request_sense(struct block_device *bd, void *buffer, int size)
74 {
75  M_DEBUG("%s\n", __func__);
76 
77  return scsi_cmd(bd, 0x03, buffer, size, size);
78 }
79 
80 static inline int scsi_cmd_inquiry(struct block_device *bd, void *buffer, int size)
81 {
82  M_DEBUG("%s\n", __func__);
83 
84  return scsi_cmd(bd, 0x12, buffer, size, size);
85 }
86 
87 static int scsi_cmd_start_stop_unit(struct block_device *bd, u8 param)
88 {
89  M_DEBUG("%s\n", __func__);
90 
91  return scsi_cmd(bd, 0x1b, NULL, 0, param);
92 }
93 
94 static inline int scsi_cmd_read_capacity(struct block_device *bd, void *buffer, int size)
95 {
96  M_DEBUG("%s\n", __func__);
97 
98  return scsi_cmd(bd, 0x25, buffer, size, 0);
99 }
100 
101 static int scsi_cmd_rw_sector(struct block_device *bd, u64 lba, const void *buffer, unsigned short int sectorCount, unsigned int write)
102 {
103  unsigned char comData[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
104  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
105 
106  DEBUG_U64_2XU32(lba);
107  M_DEBUG("scsi_cmd_rw_sector - 0x%08x%08x %p 0x%04x\n", lba_u32[1], lba_u32[0], buffer, sectorCount);
108 
109  // Note: LBA from bdm is 64bit but SCSI commands being used are 32bit. These need to be updated to 64bit LBA SCSI
110  // commands to work with large capacity drives. For now the 32bit LBA will only support up to 2TB drives.
111 
112  comData[0] = write ? 0x2a : 0x28;
113  comData[2] = (lba & 0xFF000000) >> 24; // lba 1 (MSB)
114  comData[3] = (lba & 0xFF0000) >> 16; // lba 2
115  comData[4] = (lba & 0xFF00) >> 8; // lba 3
116  comData[5] = (lba & 0xFF); // lba 4 (LSB)
117  comData[7] = (sectorCount & 0xFF00) >> 8; // Transfer length MSB
118  comData[8] = (sectorCount & 0xFF); // Transfer length LSB
119  return scsi->queue_cmd(scsi, comData, 12, (void *)buffer, bd->sectorSize * sectorCount, write);
120 }
121 
122 //
123 // Private
124 //
125 static int scsi_warmup(struct block_device *bd)
126 {
127  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
128  inquiry_data id;
129  sense_data sd;
130  read_capacity_data rcd;
131  int stat;
132 
133  M_DEBUG("%s\n", __func__);
134 
135  stat = scsi->get_max_lun(scsi);
136  M_DEBUG("scsi->get_max_lun %d\n", stat);
137 
138  memset(&id, 0, sizeof(inquiry_data));
139  if ((stat = scsi_cmd_inquiry(bd, &id, sizeof(inquiry_data))) < 0) {
140  M_PRINTF("ERROR: scsi_cmd_inquiry %d\n", stat);
141  return -1;
142  }
143 
144  M_PRINTF("Vendor: %.8s\n", id.vendor);
145  M_PRINTF("Product: %.16s\n", id.product);
146  M_PRINTF("Revision: %.4s\n", id.revision);
147 
148  while ((stat = scsi_cmd_test_unit_ready(bd)) != 0) {
149  M_PRINTF("ERROR: scsi_cmd_test_unit_ready %d\n", stat);
150 
151  stat = scsi_cmd_request_sense(bd, &sd, sizeof(sense_data));
152  if (stat != 0) {
153  M_PRINTF("ERROR: scsi_cmd_request_sense %d\n", stat);
154  }
155 
156  if ((sd.error_code == 0x70) && (sd.sense_key != 0x00)) {
157  M_PRINTF("Sense Data key: %02X code: %02X qual: %02X\n", sd.sense_key, sd.add_sense_code, sd.add_sense_qual);
158 
159  if ((sd.sense_key == 0x02) && (sd.add_sense_code == 0x04) && (sd.add_sense_qual == 0x02)) {
160  M_PRINTF("ERROR: Additional initalization is required for this device!\n");
161  if ((stat = scsi_cmd_start_stop_unit(bd, 1)) != 0) {
162  M_PRINTF("ERROR: scsi_cmd_start_stop_unit %d\n", stat);
163  return -1;
164  }
165  }
166  }
167  }
168 
169  if ((stat = scsi_cmd_read_capacity(bd, &rcd, sizeof(read_capacity_data))) != 0) {
170  M_PRINTF("ERROR: scsi_cmd_read_capacity %d\n", stat);
171  return -1;
172  }
173 
174  bd->sectorSize = getBI32(&rcd.block_length);
175  bd->sectorOffset = 0;
176  bd->sectorCount = getBI32(&rcd.last_lba);
177  M_PRINTF("%lu %u-byte logical blocks: (%luMB / %luMiB)\n", (u32)bd->sectorCount, bd->sectorSize, (u32)bd->sectorCount / ((1000 * 1000) / bd->sectorSize), (u32)bd->sectorCount / ((1024 * 1024) / bd->sectorSize));
178 
179  return 0;
180 }
181 
182 //
183 // Block device interface
184 //
185 static int scsi_read(struct block_device *bd, u64 sector, void *buffer, u16 count)
186 {
187  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
188  u16 sc_remaining = count;
189  int retries;
190 
191  DEBUG_U64_2XU32(sector);
192  M_DEBUG("%s: sector=0x%08x%08x, count=%d\n", __func__, sector_u32[1], sector_u32[0], count);
193 
194  while (sc_remaining > 0) {
195  u16 sc = sc_remaining > scsi->max_sectors ? scsi->max_sectors : sc_remaining;
196 
197  for (retries = SCSI_MAX_RETRIES; retries > 0; retries--) {
198  if (scsi_cmd_rw_sector(bd, sector, buffer, sc, 0) == 0)
199  break;
200  }
201 
202  if (retries == 0)
203  return -EIO;
204 
205  sc_remaining -= sc;
206  sector += sc;
207  buffer = (u8 *)buffer + (sc * bd->sectorSize);
208  }
209 
210  return count;
211 }
212 
213 static int scsi_write(struct block_device *bd, u64 sector, const void *buffer, u16 count)
214 {
215  struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
216  u16 sc_remaining = count;
217  int retries;
218 
219  DEBUG_U64_2XU32(sector);
220  M_DEBUG("%s: sector=0x%08x%08x, count=%d\n", __func__, sector_u32[1], sector_u32[0], count);
221 
222  while (sc_remaining > 0) {
223  u16 sc = sc_remaining > scsi->max_sectors ? scsi->max_sectors : sc_remaining;
224 
225  for (retries = SCSI_MAX_RETRIES; retries > 0; retries--) {
226  if (scsi_cmd_rw_sector(bd, sector, buffer, sc, 1) == 0)
227  break;
228  }
229 
230  if (retries == 0)
231  return -EIO;
232 
233  sc_remaining -= sc;
234  sector += sc;
235  buffer = (u8 *)buffer + (sc * bd->sectorSize);
236  }
237 
238  return count;
239 }
240 
241 static void scsi_flush(struct block_device *bd)
242 {
243  (void)bd;
244 
245  M_DEBUG("%s\n", __func__);
246 
247  // Dummy function
248 }
249 
250 static int scsi_stop(struct block_device *bd)
251 {
252  int stat;
253 
254  M_DEBUG("%s\n", __func__);
255 
256  if ((stat = scsi_cmd_start_stop_unit(bd, 0)) != 0) {
257  M_PRINTF("ERROR: scsi_cmd_start_stop_unit %d\n", stat);
258  }
259 
260  return stat;
261 }
262 
263 //
264 // Public functions
265 //
266 void scsi_connect(struct scsi_interface *scsi)
267 {
268  int i;
269 
270  M_DEBUG("%s\n", __func__);
271 
272  for (i = 0; i < NUM_DEVICES; ++i) {
273  if (g_scsi_bd[i].priv == NULL) {
274  struct block_device *bd = &g_scsi_bd[i];
275 
276  bd->priv = scsi;
277  bd->name = scsi->name;
278  bd->path = "ilink";
279  bd->devNr = scsi->devNr;
280  scsi_warmup(bd);
281  bdm_connect_bd(bd);
282  break;
283  }
284  }
285 }
286 
287 void scsi_disconnect(struct scsi_interface *scsi)
288 {
289  int i;
290 
291  M_DEBUG("%s\n", __func__);
292 
293  for (i = 0; i < NUM_DEVICES; ++i) {
294  if (g_scsi_bd[i].priv == scsi) {
295  struct block_device *bd = &g_scsi_bd[i];
296  bdm_disconnect_bd(bd);
297  bd->priv = NULL;
298  break;
299  }
300  }
301 }
302 
303 int scsi_init(void)
304 {
305  int i;
306 
307  M_DEBUG("%s\n", __func__);
308 
309  for (i = 0; i < NUM_DEVICES; ++i) {
310  g_scsi_bd[i].parNr = 0;
311  g_scsi_bd[i].parId = 0x00;
312 
313  g_scsi_bd[i].priv = NULL;
314  g_scsi_bd[i].read = scsi_read;
315  g_scsi_bd[i].write = scsi_write;
316  g_scsi_bd[i].flush = scsi_flush;
317  g_scsi_bd[i].stop = scsi_stop;
318  }
319 
320  return 0;
321 }
_inquiry_data
Definition: scsi.c:15
bdm.h
sysclib.h
EIO
#define EIO
Definition: errno.h:29
_read_capacity_data
Definition: scsi.c:41
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
thsemap.h
stdio.h
_sense_data
Definition: scsi.c:28
block_device
Definition: bdm.h:21
scsi_interface
Definition: scsi.h:4
errno.h