PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
scsi.c
1#include <errno.h>
2#include <intrman.h>
3#include <stdio.h>
4#include <sysclib.h>
5#include <sysmem.h>
6
7// #define DEBUG
8
9#include "iLinkman.h"
10#include "sbp2_disk.h"
11#include "scsi.h"
12
13#include "usbhd_common.h"
14#include "scache.h"
15#include "part_driver.h"
16#include "mass_debug.h"
17
18/* Function prototypes */
19static int scsiTestUnitReady(struct SBP2Device *dev);
20static int scsiInquiry(struct SBP2Device *dev, void *buffer, int size);
21static int scsiRequestSense(struct SBP2Device *dev, void *buffer, int size);
22static int scsiStartStopUnit(struct SBP2Device *dev);
23static int scsiReadCapacity(struct SBP2Device *dev, void *buffer, int size);
24
25static int scsiTestUnitReady(struct SBP2Device *dev)
26{
27 struct CommandDescriptorBlock cdb;
28
29 XPRINTF("scsiTestUnitReady.\n");
30
31 cdb.misc = (u32)(ORB_NOTIFY | ORB_REQUEST_FORMAT(0) | CDB_MAX_PAYLOAD(dev->max_payload) | CDB_DIRECTION(WRITE_TRANSACTION) | CDB_SPEED(dev->speed));
32
33 cdb.DataDescriptor.low = cdb.DataDescriptor.high = 0;
34 cdb.DataDescriptor.NodeID = dev->InitiatorNodeID;
35
36 cdb.NextOrb.high = cdb.NextOrb.low = 0;
37 cdb.NextOrb.reserved = NULL_POINTER;
38
39 // scsi command packet
40 cdb.CDBs[3] = 0x00; // test unit ready operation code
41 cdb.CDBs[2] = 0; // reserved
42 cdb.CDBs[1] = 0; // reserved
43 cdb.CDBs[0] = 0; // reserved
44 cdb.CDBs[7] = 0; // reserved
45 cdb.CDBs[6] = 0; // reserved
46 cdb.CDBs[5] = 0; // reserved
47 cdb.CDBs[4] = 0; // reserved
48 cdb.CDBs[11] = 0; // reserved
49 cdb.CDBs[10] = 0; // reserved
50 cdb.CDBs[9] = 0; // reserved
51 cdb.CDBs[8] = 0; // reserved
52
53 ieee1394_SendCommandBlockORB(dev, &cdb);
54 return (ieee1394_Sync());
55}
56
57static int scsiRequestSense(struct SBP2Device *dev, void *buffer, int size)
58{
59 int ret;
60 struct CommandDescriptorBlock cdb;
61
62 XPRINTF("scsiRequestSense.\n");
63
64 cdb.misc = (ORB_NOTIFY | ORB_REQUEST_FORMAT(0) | CDB_MAX_PAYLOAD(dev->max_payload) | CDB_DIRECTION(WRITE_TRANSACTION) | CDB_SPEED(dev->speed) | CDB_DATA_SIZE(size));
65
66 cdb.DataDescriptor.low = (u32)buffer;
67 cdb.DataDescriptor.high = 0;
68 cdb.DataDescriptor.NodeID = dev->InitiatorNodeID;
69
70 cdb.NextOrb.high = cdb.NextOrb.low = 0;
71 cdb.NextOrb.reserved = NULL_POINTER;
72
73 // scsi command packet
74 cdb.CDBs[3] = 0x03; // request sense operation code
75 cdb.CDBs[2] = 0; // reserved
76 cdb.CDBs[1] = 0; // reserved
77 cdb.CDBs[0] = 0; // reserved
78 cdb.CDBs[7] = size; // allocation length
79 cdb.CDBs[6] = 0; // reserved
80 cdb.CDBs[5] = 0; // reserved
81 cdb.CDBs[4] = 0; // reserved
82 cdb.CDBs[11] = 0; // reserved
83 cdb.CDBs[10] = 0; // reserved
84 cdb.CDBs[9] = 0; // reserved
85 cdb.CDBs[8] = 0; // reserved
86
87 ieee1394_SendCommandBlockORB(dev, &cdb);
88 ret = ieee1394_Sync();
89
90 if (ret != 0) {
91 XPRINTF("scsiRequestSense error: %d\n", ret);
92 }
93
94 return ret;
95}
96
97static int scsiInquiry(struct SBP2Device *dev, void *buffer, int size)
98{
99 int ret;
100 struct CommandDescriptorBlock cdb;
101
102 XPRINTF("scsiInquiry. buffer: %p\n", buffer);
103
104 cdb.misc = (ORB_NOTIFY | ORB_REQUEST_FORMAT(0) | CDB_MAX_PAYLOAD(dev->max_payload) | CDB_DIRECTION(WRITE_TRANSACTION) | CDB_SPEED(dev->speed) | CDB_DATA_SIZE(size));
105
106 cdb.DataDescriptor.low = (u32)buffer;
107 cdb.DataDescriptor.high = 0;
108 cdb.DataDescriptor.NodeID = dev->InitiatorNodeID;
109
110 cdb.NextOrb.high = cdb.NextOrb.low = 0;
111 cdb.NextOrb.reserved = NULL_POINTER;
112
113 // scsi command packet
114 cdb.CDBs[3] = 0x12; // inquiry operation code
115 cdb.CDBs[2] = 0; // reserved
116 cdb.CDBs[1] = 0; // page code
117 cdb.CDBs[0] = 0; // reserved
118 cdb.CDBs[7] = size; // inquiry reply length
119 cdb.CDBs[6] = 0; // reserved
120 cdb.CDBs[5] = 0; // reserved
121 cdb.CDBs[4] = 0; // reserved
122 cdb.CDBs[11] = 0; // reserved
123 cdb.CDBs[10] = 0; // reserved
124 cdb.CDBs[9] = 0; // reserved
125 cdb.CDBs[8] = 0; // reserved
126
127 ieee1394_SendCommandBlockORB(dev, &cdb);
128 ret = ieee1394_Sync();
129
130 if (ret != 0) {
131 XPRINTF("scsiInquiry error %d\n", ret);
132 } else {
133 unsigned int i;
134
135 for (i = 0; i < (unsigned int)(size / 4); i++)
136 ((unsigned int *)buffer)[i] = BSWAP32(((unsigned int *)buffer)[i]);
137 }
138
139 return ret;
140}
141
142static int scsiStartStopUnit(struct SBP2Device *dev)
143{
144 struct CommandDescriptorBlock cdb;
145
146 XPRINTF("scsiStartStopUnit.\n");
147
148 cdb.misc = (ORB_NOTIFY | ORB_REQUEST_FORMAT(0) | CDB_MAX_PAYLOAD(dev->max_payload) | CDB_DIRECTION(WRITE_TRANSACTION) | CDB_SPEED(dev->speed));
149
150 cdb.DataDescriptor.low = cdb.DataDescriptor.high = 0;
151 cdb.DataDescriptor.NodeID = dev->InitiatorNodeID;
152
153 cdb.NextOrb.high = cdb.NextOrb.low = 0;
154 cdb.NextOrb.reserved = NULL_POINTER;
155
156 // scsi command packet
157 cdb.CDBs[3] = 0x1B; // start stop unit operation code
158 cdb.CDBs[2] = 1; // reserved/immed
159 cdb.CDBs[1] = 0; // reserved
160 cdb.CDBs[0] = 0; // reserved
161 cdb.CDBs[7] = 1; // POWER CONDITIONS/reserved/LoEj/Start "Start the media and acquire the format type"
162 cdb.CDBs[6] = 0; // reserved
163 cdb.CDBs[5] = 0; // reserved
164 cdb.CDBs[4] = 0; // reserved
165 cdb.CDBs[11] = 0; // reserved
166 cdb.CDBs[10] = 0; // reserved
167 cdb.CDBs[9] = 0; // reserved
168 cdb.CDBs[8] = 0; // reserved
169
170 ieee1394_SendCommandBlockORB(dev, &cdb);
171 return (ieee1394_Sync());
172}
173
174static int scsiReadCapacity(struct SBP2Device *dev, void *buffer, int size)
175{
176 struct CommandDescriptorBlock cdb;
177
178 XPRINTF("scsiReadCapacity.\n");
179
180 cdb.misc = (ORB_NOTIFY | ORB_REQUEST_FORMAT(0) | CDB_MAX_PAYLOAD(dev->max_payload) | CDB_DIRECTION(WRITE_TRANSACTION) | CDB_SPEED(dev->speed) | CDB_DATA_SIZE(size));
181
182 cdb.DataDescriptor.low = (u32)buffer;
183 cdb.DataDescriptor.high = 0;
184 cdb.DataDescriptor.NodeID = dev->InitiatorNodeID;
185
186 cdb.NextOrb.high = cdb.NextOrb.low = 0;
187 cdb.NextOrb.reserved = NULL_POINTER;
188
189 // scsi command packet
190 cdb.CDBs[3] = 0x25; // read capacity operation code
191 cdb.CDBs[2] = 0; // reserved
192 cdb.CDBs[1] = 0; // LBA 1
193 cdb.CDBs[0] = 0; // LBA 2
194 cdb.CDBs[7] = 0; // LBA 3
195 cdb.CDBs[6] = 0; // LBA 4
196 cdb.CDBs[5] = 0; // Reserved
197 cdb.CDBs[4] = 0; // Reserved
198 cdb.CDBs[11] = 0; // Reserved
199 cdb.CDBs[10] = 0; // reserved
200 cdb.CDBs[9] = 0; // reserved
201 cdb.CDBs[8] = 0; // reserved
202
203 ieee1394_SendCommandBlockORB(dev, &cdb);
204 return (ieee1394_Sync());
205}
206
207#define MAX_ORBS 256
208
209static struct CommandDescriptorBlock cdb[MAX_ORBS];
210
211int scsiReadSector(struct SBP2Device *dev, unsigned long int lba, void *buffer, int sectorCount)
212{
213 unsigned int nOrbs, OrbsRemaining, i, sectorsToRead, sectorsRemaining, SectorsPerBlock, BlockNum;
214 unsigned long int startingLBA;
215 void *bufferPtr, *PreviousReqBufferPtr;
216 int result;
217
218 XPRINTF("scsiReadSector. buffer: %p, lba: 0x%08lx, numsectors: %d.\n", buffer, lba, sectorCount);
219 SectorsPerBlock = XFER_BLOCK_SIZE / dev->sectorSize;
220 OrbsRemaining = sectorCount / SectorsPerBlock;
221 if ((sectorCount % SectorsPerBlock) != 0)
222 OrbsRemaining++;
223
224 XPRINTF("NumOrbs=%d cdb: %p.\n", OrbsRemaining, cdb);
225
226 startingLBA = lba;
227 sectorsRemaining = sectorCount;
228 bufferPtr = buffer;
229
230 result = 0;
231 for (PreviousReqBufferPtr = NULL, BlockNum = 0, sectorsToRead = 0; (OrbsRemaining > 0) && (result == 0); OrbsRemaining -= nOrbs, BlockNum++) {
232 nOrbs = (OrbsRemaining > MAX_ORBS) ? MAX_ORBS : OrbsRemaining;
233
234 if (BlockNum > 0) { /* While waiting for the read request that was just sent to be processed, byte-swap the previously read in data. */
235 for (i = 0; i < sectorsToRead << 7; i++)
236 ((unsigned int *)PreviousReqBufferPtr)[i] = BSWAP32(((unsigned int *)PreviousReqBufferPtr)[i]);
237 result = ieee1394_Sync(); /* Only sync if a read request is being processed. Otherwise, it'll wait eternally.. */
238 }
239
240 /* Save the current pointer to the buffer, so that the code above can byte-swap the payload of the request below that will be read in,
241 when this loop loops around.
242 */
243 PreviousReqBufferPtr = bufferPtr;
244
245 for (i = 0; i < nOrbs; i++) {
246 sectorsToRead = (sectorsRemaining > SectorsPerBlock) ? SectorsPerBlock : sectorsRemaining;
247
248 cdb[i].misc = (ORB_NOTIFY | ORB_REQUEST_FORMAT(0) | CDB_MAX_PAYLOAD(dev->max_payload) | CDB_DIRECTION(WRITE_TRANSACTION) | CDB_SPEED(dev->speed) | CDB_DATA_SIZE((dev->sectorSize * sectorsToRead)));
249
250 cdb[i].DataDescriptor.low = (u32)bufferPtr;
251 cdb[i].DataDescriptor.high = 0;
252 cdb[i].DataDescriptor.NodeID = dev->InitiatorNodeID;
253
254 if (i > 0) {
255 cdb[i - 1].NextOrb.high = 0;
256 cdb[i - 1].NextOrb.low = (u32)&cdb[i];
257 cdb[i - 1].NextOrb.reserved = 0;
258 }
259
260 // scsi command packet
261 cdb[i].CDBs[3] = 0x28; // read operation code
262 cdb[i].CDBs[2] = 0; // Reserved
263 cdb[i].CDBs[1] = (startingLBA & 0xFF000000) >> 24; // lba 1 (MSB)
264 cdb[i].CDBs[0] = (startingLBA & 0xFF0000) >> 16; // lba 2
265 cdb[i].CDBs[7] = (startingLBA & 0xFF00) >> 8; // lba 3
266 cdb[i].CDBs[6] = (startingLBA & 0xFF); // lba 4 (LSB)
267 cdb[i].CDBs[5] = 0; // Reserved
268 cdb[i].CDBs[4] = (sectorsToRead & 0xFF00) >> 8; // Transfer length MSB
269 cdb[i].CDBs[11] = (sectorsToRead & 0xFF); // Transfer length LSB
270 cdb[i].CDBs[10] = 0; // reserved
271 cdb[i].CDBs[9] = 0; // reserved
272 cdb[i].CDBs[8] = 0; // reserved
273
274 startingLBA += sectorsToRead;
275 sectorsRemaining -= sectorsToRead;
276 bufferPtr = (void *)((u8 *)bufferPtr + (dev->sectorSize * sectorsToRead));
277 }
278
279 /* NULL terminate the last ORB. */
280 cdb[i - 1].NextOrb.high = cdb[i - 1].NextOrb.low = 0;
281 cdb[i - 1].NextOrb.reserved = NULL_POINTER;
282
283 ieee1394_SendCommandBlockORB(dev, cdb);
284 }
285
286 /* Sync and byte-swap the last block. */
287 result = ieee1394_Sync();
288 for (i = 0; i < sectorsToRead << 7; i++)
289 ((unsigned int *)PreviousReqBufferPtr)[i] = BSWAP32(((unsigned int *)PreviousReqBufferPtr)[i]);
290
291 XPRINTF("scsiReadSector done.\n");
292
293 return result;
294}
295
296int scsiWriteSector(struct SBP2Device *dev, unsigned long int lba, void *buffer, int sectorCount)
297{
298 unsigned int nOrbs, OrbsRemaining, i, sectorsToRead, sectorsRemaining, SectorsPerBlock;
299 unsigned long int startingLBA;
300 void *bufferPtr;
301 int result, max_payload;
302
303 XPRINTF("scsiWriteSector.\n");
304 SectorsPerBlock = XFER_BLOCK_SIZE / dev->sectorSize;
305 OrbsRemaining = sectorCount / SectorsPerBlock;
306 if ((sectorCount % SectorsPerBlock) != 0)
307 OrbsRemaining++;
308
309 startingLBA = lba;
310 sectorsRemaining = sectorCount;
311 bufferPtr = buffer;
312 max_payload = (dev->max_payload > 7) ? 7 : dev->max_payload; /* Do not allow the maximum payload to exceed 512 bytes (Actually, is this necessary?). */
313
314 result = 0;
315 for (; (OrbsRemaining > 0) && (result == 0); OrbsRemaining -= nOrbs) {
316 nOrbs = (OrbsRemaining > MAX_ORBS) ? MAX_ORBS : OrbsRemaining;
317
318 for (i = 0; i < nOrbs; i++) {
319 sectorsToRead = (sectorsRemaining > SectorsPerBlock) ? SectorsPerBlock : sectorsRemaining;
320
321 cdb[i].misc = (ORB_NOTIFY | ORB_REQUEST_FORMAT(0) | CDB_MAX_PAYLOAD(max_payload) | CDB_DIRECTION(READ_TRANSACTION) | CDB_SPEED(dev->speed) | CDB_DATA_SIZE((dev->sectorSize * sectorsToRead)));
322
323 cdb[i].DataDescriptor.low = (u32)bufferPtr;
324 cdb[i].DataDescriptor.high = 0;
325 cdb[i].DataDescriptor.NodeID = dev->InitiatorNodeID;
326
327 if (i > 0) {
328 cdb[i - 1].NextOrb.high = 0;
329 cdb[i - 1].NextOrb.low = (u32)&cdb[i];
330 cdb[i - 1].NextOrb.reserved = 0;
331 }
332
333 // scsi command packet
334 cdb[i].CDBs[3] = 0x2A; // write operation code
335 cdb[i].CDBs[2] = 0; // Reserved
336 cdb[i].CDBs[1] = (startingLBA & 0xFF000000) >> 24; // lba 1 (MSB)
337 cdb[i].CDBs[0] = (startingLBA & 0xFF0000) >> 16; // lba 2
338 cdb[i].CDBs[7] = (startingLBA & 0xFF00) >> 8; // lba 3
339 cdb[i].CDBs[6] = (startingLBA & 0xFF); // lba 4 (LSB)
340 cdb[i].CDBs[5] = 0; // Reserved
341 cdb[i].CDBs[4] = (sectorsToRead & 0xFF00) >> 8; // Transfer length MSB
342 cdb[i].CDBs[11] = (sectorsToRead & 0xFF); // Transfer length LSB
343 cdb[i].CDBs[10] = 0; // reserved
344 cdb[i].CDBs[9] = 0; // reserved
345 cdb[i].CDBs[8] = 0; // reserved
346
347 startingLBA += sectorsToRead;
348 sectorsRemaining -= sectorsToRead;
349 bufferPtr = (void *)((u8 *)bufferPtr + (dev->sectorSize * sectorsToRead));
350 }
351
352 /* NULL terminate the last ORB. */
353 cdb[i - 1].NextOrb.high = cdb[i - 1].NextOrb.low = 0;
354 cdb[i - 1].NextOrb.reserved = NULL_POINTER;
355
356 ieee1394_SendCommandBlockORB(dev, cdb);
357 result = ieee1394_Sync();
358 }
359
360 return result;
361}
362
363static inline int InitializeSCSIDevice(struct SBP2Device *dev)
364{
365 inquiry_data id;
366 sense_data sd;
368 int stat;
369
370 XPRINTF("InitializeSCSIDevice.\n");
371
372 memset(&id, 0, sizeof(inquiry_data));
373 if ((stat = scsiInquiry(dev, &id, sizeof(inquiry_data))) < 0) {
374 XPRINTF("Error - scsiInquiry returned %d.\n", stat);
375 return -1;
376 }
377
378 printf("Vendor: %.8s\n", id.vendor);
379 printf("Product: %.16s\n", id.product);
380 printf("Revision: %.4s\n", id.revision);
381
382 if ((stat = scsiReadCapacity(dev, &rcd, sizeof(read_capacity_data))) != 0) {
383 XPRINTF("Error - scsiReadCapacity %d\n", stat);
384 return -1;
385 }
386
387 dev->sectorSize = rcd.block_length;
388 dev->maxLBA = rcd.last_lba;
389
390 printf("sectorSize %lu maxLBA %lu\n", dev->sectorSize, dev->maxLBA);
391
392 while ((stat = scsiTestUnitReady(dev)) != 0) {
393 XPRINTF("Error - scsiTestUnitReady %d\n", stat);
394
395 stat = scsiRequestSense(dev, &sd, sizeof(sense_data));
396 if (stat != 0) {
397 XPRINTF("Error - scsiRequestSense %d\n", stat);
398 }
399
400 if ((sd.error_code == 0x70) && (sd.sense_key != 0x00)) {
401 XPRINTF("Sense Data key: %02X code: %02X qual: %02X\n", sd.sense_key, sd.add_sense_code, sd.add_sense_qual);
402
403 if ((sd.sense_key == 0x02) && (sd.add_sense_code == 0x04) && (sd.add_sense_qual == 0x02)) {
404 XPRINTF("Error - Additional initalization is required for this device!\n");
405 if ((stat = scsiStartStopUnit(dev)) != 0) {
406 XPRINTF("Error - scsiStartStopUnit %d\n", stat);
407 return -1;
408 }
409 }
410 }
411 }
412
413 return 0;
414}
415
416void releaseSBP2Device(struct SBP2Device *dev)
417{
418 part_disconnect(dev);
419 scache_kill(dev->cache);
420}
421
422int ConfigureSBP2Device(struct SBP2Device *dev)
423{
424 int ret;
425
426 if ((ret = InitializeSCSIDevice(dev)) < 0) {
427 XPRINTF("Error - failed to warmup device 0x%08x\n", dev->nodeID);
428 return ret;
429 }
430
431 if ((dev->cache = scache_init(dev, dev->sectorSize)) == NULL) {
432 XPRINTF("Error - scache_init failed \n");
433 return ret;
434 }
435
436 return (part_connect(dev));
437}