PS2SDK
PS2 Homebrew Libraries
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];
27
28typedef 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];
40
41typedef struct _read_capacity_data
42{
43 u8 last_lba[4];
44 u8 block_length[4];
46
47#define NUM_DEVICES 2
48static struct block_device g_scsi_bd[NUM_DEVICES];
49
50//
51// Private Low level SCSI commands
52//
53static 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
66static 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
73static 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
80static 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
87static 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
94static 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
101static 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//
125static 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;
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("%u %u-byte logical blocks: (%uMB / %uMiB)\n", bd->sectorCount, bd->sectorSize, bd->sectorCount / ((1000 * 1000) / bd->sectorSize), bd->sectorCount / ((1024 * 1024) / bd->sectorSize));
178
179 return 0;
180}
181
182//
183// Block device interface
184//
185static 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 U64_2XU32(sector);
204 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);
205 return -EIO;
206 }
207
208 sc_remaining -= sc;
209 sector += sc;
210 buffer = (u8 *)buffer + (sc * bd->sectorSize);
211 }
212
213 return count;
214}
215
216static int scsi_write(struct block_device *bd, u64 sector, const void *buffer, u16 count)
217{
218 struct scsi_interface *scsi = (struct scsi_interface *)bd->priv;
219 u16 sc_remaining = count;
220 unsigned int sectorSize = bd->sectorSize;
221 void *misalign_buffer = NULL;
222 int retries;
223
224 DEBUG_U64_2XU32(sector);
225 M_DEBUG("%s: sector=0x%08x%08x, count=%d\n", __func__, sector_u32[1], sector_u32[0], count);
226
227 if (((uiptr)buffer & 3) != 0) {
228 /* Slow misalignment workaround */
229 misalign_buffer = __builtin_alloca(sectorSize + 4);
230
231 if (((uiptr)misalign_buffer & 3) != 0)
232 {
233 misalign_buffer = (u8 *)misalign_buffer + (4 - ((uiptr)misalign_buffer & 3));
234 }
235 }
236
237 while (sc_remaining > 0) {
238 u16 sc = sc_remaining > scsi->max_sectors ? scsi->max_sectors : sc_remaining;
239 const void *dst_buffer = buffer;
240
241 if (misalign_buffer != NULL) {
242 memcpy(misalign_buffer, buffer, sectorSize);
243 dst_buffer = misalign_buffer;
244 sc = 1;
245 }
246
247 for (retries = SCSI_MAX_RETRIES; retries > 0; retries--) {
248 if (scsi_cmd_rw_sector(bd, sector, dst_buffer, sc, 1) == 0)
249 break;
250 }
251
252 if (retries == 0) {
253 U64_2XU32(sector);
254 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);
255 return -EIO;
256 }
257
258 sc_remaining -= sc;
259 sector += sc;
260 buffer = (u8 *)buffer + (sc * sectorSize);
261 }
262
263 return count;
264}
265
266static void scsi_flush(struct block_device *bd)
267{
268 (void)bd;
269
270 M_DEBUG("%s\n", __func__);
271
272 // Dummy function
273}
274
275static int scsi_stop(struct block_device *bd)
276{
277 int stat;
278
279 M_DEBUG("%s\n", __func__);
280
281 if ((stat = scsi_cmd_start_stop_unit(bd, 0)) != 0) {
282 M_PRINTF("ERROR: scsi_cmd_start_stop_unit %d\n", stat);
283 }
284
285 return stat;
286}
287
288//
289// Public functions
290//
291void scsi_connect(struct scsi_interface *scsi)
292{
293 int i;
294
295 M_DEBUG("%s\n", __func__);
296
297 for (i = 0; i < NUM_DEVICES; ++i) {
298 if (g_scsi_bd[i].priv == NULL) {
299 struct block_device *bd = &g_scsi_bd[i];
300
301 bd->priv = scsi;
302 bd->name = scsi->name;
303 scsi_warmup(bd);
304 bdm_connect_bd(bd);
305 break;
306 }
307 }
308}
309
310void scsi_disconnect(struct scsi_interface *scsi)
311{
312 int i;
313
314 M_DEBUG("%s\n", __func__);
315
316 for (i = 0; i < NUM_DEVICES; ++i) {
317 if (g_scsi_bd[i].priv == scsi) {
318 struct block_device *bd = &g_scsi_bd[i];
319 bdm_disconnect_bd(bd);
320 bd->priv = NULL;
321 break;
322 }
323 }
324}
325
326int scsi_init(void)
327{
328 int i;
329
330 M_DEBUG("%s\n", __func__);
331
332 for (i = 0; i < NUM_DEVICES; ++i) {
333 g_scsi_bd[i].devNr = i;
334 g_scsi_bd[i].parNr = 0;
335 g_scsi_bd[i].parId = 0x00;
336
337 g_scsi_bd[i].priv = NULL;
338 g_scsi_bd[i].read = scsi_read;
339 g_scsi_bd[i].write = scsi_write;
340 g_scsi_bd[i].flush = scsi_flush;
341 g_scsi_bd[i].stop = scsi_stop;
342 }
343
344 return 0;
345}
#define EIO
Definition errno.h:29
u32 count
start sector of fragmented bd/file