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 return -EIO;
204
205 sc_remaining -= sc;
206 sector += sc;
207 buffer = (u8 *)buffer + (sc * bd->sectorSize);
208 }
209
210 return count;
211}
212
213static 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
241static void scsi_flush(struct block_device *bd)
242{
243 (void)bd;
244
245 M_DEBUG("%s\n", __func__);
246
247 // Dummy function
248}
249
250static 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//
266void 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 scsi_warmup(bd);
279 bdm_connect_bd(bd);
280 break;
281 }
282 }
283}
284
285void scsi_disconnect(struct scsi_interface *scsi)
286{
287 int i;
288
289 M_DEBUG("%s\n", __func__);
290
291 for (i = 0; i < NUM_DEVICES; ++i) {
292 if (g_scsi_bd[i].priv == scsi) {
293 struct block_device *bd = &g_scsi_bd[i];
294 bdm_disconnect_bd(bd);
295 bd->priv = NULL;
296 break;
297 }
298 }
299}
300
301int scsi_init(void)
302{
303 int i;
304
305 M_DEBUG("%s\n", __func__);
306
307 for (i = 0; i < NUM_DEVICES; ++i) {
308 g_scsi_bd[i].devNr = i;
309 g_scsi_bd[i].parNr = 0;
310 g_scsi_bd[i].parId = 0x00;
311
312 g_scsi_bd[i].priv = NULL;
313 g_scsi_bd[i].read = scsi_read;
314 g_scsi_bd[i].write = scsi_write;
315 g_scsi_bd[i].flush = scsi_flush;
316 g_scsi_bd[i].stop = scsi_stop;
317 }
318
319 return 0;
320}
#define EIO
Definition errno.h:29
u32 count
start sector of fragmented bd/file