summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-01-04 00:41:35 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2017-01-07 15:52:33 +0100
commit07781847826d6901e047c3c55d227aae487a9f4c (patch)
treeec5326ae19ba1d4aa01290ca44ee34a4e8d1a72c
parent7fafbe1fc13bec744d1fcc70ba431fa77472680a (diff)
downloadrockbox-07781847826d6901e047c3c55d227aae487a9f4c.tar.gz
rockbox-07781847826d6901e047c3c55d227aae487a9f4c.zip
imxtools/scsitools: move stmp scsi api to its own file
No code modification code, just moving code around. Change-Id: I30744d3994aa7540f4b5b158f31b51959d5d8586
-rw-r--r--utils/imxtools/scsitools/Makefile3
-rw-r--r--utils/imxtools/scsitools/scsitool.c586
-rw-r--r--utils/imxtools/scsitools/stmp_scsi.c616
3 files changed, 618 insertions, 587 deletions
diff --git a/utils/imxtools/scsitools/Makefile b/utils/imxtools/scsitools/Makefile
index ed7db99732..955f413c8f 100644
--- a/utils/imxtools/scsitools/Makefile
+++ b/utils/imxtools/scsitools/Makefile
@@ -12,7 +12,8 @@ all: $(BINS)
12%.o: %.c 12%.o: %.c
13 $(CC) $(CFLAGS) -c -o $@ $< 13 $(CC) $(CFLAGS) -c -o $@ $<
14 14
15scsitool: scsitool.o misc.o 15scsitool: scsitool.o misc.o stmp_scsi.o
16 $(MAKE) -C $(TOOLS_DIR)
16 $(LD) -o $@ $^ $(LDFLAGS) 17 $(LD) -o $@ $^ $(LDFLAGS)
17 18
18clean: 19clean:
diff --git a/utils/imxtools/scsitools/scsitool.c b/utils/imxtools/scsitools/scsitool.c
index a1f1b7a2ba..a84b5919d7 100644
--- a/utils/imxtools/scsitools/scsitool.c
+++ b/utils/imxtools/scsitools/scsitool.c
@@ -39,42 +39,6 @@ bool g_debug = false;
39bool g_force = false; 39bool g_force = false;
40stmp_device_t g_dev_fd; 40stmp_device_t g_dev_fd;
41 41
42struct stmp_device_t
43{
44 rb_scsi_device_t dev;
45 unsigned flags;
46 void *user;
47 stmp_printf_t printf;
48};
49
50static inline int little_endian(void)
51{
52 static int g_endian = -1;
53 if(g_endian == -1)
54 {
55 int i = 1;
56 g_endian = (int)*((unsigned char *)&i) == 1;
57 }
58 return g_endian;
59}
60
61uint16_t stmp_fix_endian16be(uint16_t w)
62{
63 return little_endian() ? w << 8 | w >> 8 : w;
64}
65
66uint32_t stmp_fix_endian32be(uint32_t w)
67{
68 return !little_endian() ? w :
69 (uint32_t)stmp_fix_endian16be(w) << 16 | stmp_fix_endian16be(w >> 16);
70}
71
72uint64_t stmp_fix_endian64be(uint64_t w)
73{
74 return !little_endian() ? w :
75 (uint64_t)stmp_fix_endian32be(w) << 32 | stmp_fix_endian32be(w >> 32);
76}
77
78static void print_hex(void *_buffer, int buffer_size) 42static void print_hex(void *_buffer, int buffer_size)
79{ 43{
80 uint8_t *buffer = _buffer; 44 uint8_t *buffer = _buffer;
@@ -101,556 +65,6 @@ static void print_hex(void *_buffer, int buffer_size)
101 printf("\n"); 65 printf("\n");
102} 66}
103 67
104static void misc_std_printf(void *user, const char *fmt, ...)
105{
106 (void) user;
107 va_list args;
108 va_start(args, fmt);
109 vprintf(fmt, args);
110 va_end(args);
111}
112
113#define stmp_printf(dev, ...) \
114 dev->printf(dev->user, __VA_ARGS__)
115
116#define stmp_debugf(dev, ...) \
117 do{ if(dev->flags & STMP_DEBUG) stmp_printf(dev, __VA_ARGS__); }while(0)
118
119stmp_device_t stmp_open(rb_scsi_device_t rdev, unsigned flags, void *user, stmp_printf_t printf)
120{
121 if(printf == NULL)
122 printf = misc_std_printf;
123 stmp_device_t sdev = malloc(sizeof(struct stmp_device_t));
124 memset(sdev, 0, sizeof(struct stmp_device_t));
125 sdev->dev = rdev;
126 sdev->flags = flags;
127 sdev->user = user;
128 sdev->printf = printf;
129 return sdev;
130}
131
132void stmp_close(stmp_device_t dev)
133{
134 free(dev);
135}
136
137/* returns <0 on error and status otherwise */
138int stmp_scsi(stmp_device_t dev, uint8_t *cdb, int cdb_size, unsigned flags,
139 void *sense, int *sense_size, void *buffer, int *buf_size)
140{
141 struct rb_scsi_raw_cmd_t cmd;
142 memset(&cmd, 0, sizeof(cmd));
143 cmd.dir = RB_SCSI_NONE;
144 if(flags & STMP_READ)
145 cmd.dir = RB_SCSI_READ;
146 if(flags & STMP_WRITE)
147 cmd.dir = RB_SCSI_WRITE;
148 cmd.cdb = cdb;
149 cmd.cdb_len = cdb_size;
150 cmd.sense = sense;
151 cmd.sense_len = *sense_size;
152 cmd.buf = buffer;
153 cmd.buf_len = *buf_size;
154 cmd.tmo = 1;
155 int ret = rb_scsi_raw_xfer(dev->dev, &cmd);
156 *sense_size = cmd.sense_len;
157 *buf_size = cmd.buf_len;
158 return ret == RB_SCSI_OK || ret == RB_SCSI_SENSE ? cmd.status : -ret;
159}
160
161int stmp_sense_analysis(stmp_device_t dev, int status, uint8_t *sense, int sense_size)
162{
163 if(status != 0 && (dev->flags & STMP_DEBUG))
164 {
165 stmp_printf(dev, "Status: %d\n", status);
166 stmp_printf(dev, "Sense:");
167 for(int i = 0; i < sense_size; i++)
168 stmp_printf(dev, " %02x", sense[i]);
169 stmp_printf(dev, "\n");
170 }
171 return status;
172}
173
174static int stmp_scsi_read_cmd(stmp_device_t dev, uint8_t cmd, uint8_t subcmd,
175 uint8_t subsubcmd, void *buf, int *len)
176{
177 uint8_t cdb[16];
178 memset(cdb, 0, sizeof(cdb));
179 cdb[0] = SCSI_STMP_READ;
180 cdb[1] = cmd;
181 cdb[2] = subcmd;
182 cdb[3] = subsubcmd;
183
184 uint8_t sense[32];
185 int sense_size = sizeof(sense);
186
187 int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buf, len);
188 if(ret < 0)
189 return ret;
190 ret = stmp_sense_analysis(dev, ret, sense, sense_size);
191 if(ret)
192 return ret;
193 return 0;
194}
195
196int stmp_scsi_inquiry(stmp_device_t dev, uint8_t *dev_type, char vendor[9], char product[17])
197{
198 unsigned char buffer[36];
199 uint8_t cdb[10];
200 memset(cdb, 0, sizeof(cdb));
201 cdb[0] = 0x12;
202 cdb[4] = sizeof(buffer);
203
204 uint8_t sense[32];
205 int sense_size = sizeof(sense);
206
207 int buf_sz = sizeof(buffer);
208 int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buffer, &buf_sz);
209 if(ret < 0)
210 return ret;
211 ret = stmp_sense_analysis(dev, ret, sense, sense_size);
212 if(ret)
213 return ret;
214 if(buf_sz != sizeof(buffer))
215 return -1;
216 *dev_type = buffer[0];
217 memcpy(vendor, buffer + 8, 8);
218 vendor[8] = 0;
219 memcpy(product, buffer + 16, 16);
220 product[16] = 0;
221 return 0;
222}
223
224int stmp_scsi_get_protocol_version(stmp_device_t dev, void *buf, int *len)
225{
226 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_PROTOCOL_VERSION, 0, 0, buf, len);
227}
228
229int stmp_get_protocol_version(stmp_device_t dev, struct scsi_stmp_protocol_version_t *ver)
230{
231 int len = sizeof(*ver);
232 int ret = stmp_scsi_get_protocol_version(dev, ver, &len);
233 if(ret || len != sizeof(*ver))
234 return -1;
235 return 0;
236}
237
238int stmp_scsi_get_chip_major_rev_id(stmp_device_t dev, void *buf, int *len)
239{
240 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_CHIP_MAJOR_REV_ID, 0, 0, buf, len);
241}
242
243int stmp_get_chip_major_rev_id(stmp_device_t dev, uint16_t *ver)
244{
245 int len = sizeof(*ver);
246 int ret = stmp_scsi_get_chip_major_rev_id(dev, ver, &len);
247 if(ret || len != sizeof(*ver))
248 return -1;
249 *ver = stmp_fix_endian16be(*ver);
250 return 0;
251}
252
253int stmp_scsi_get_rom_rev_id(stmp_device_t dev, void *buf, int *len)
254{
255 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_ROM_REV_ID, 0, 0, buf, len);
256}
257
258int stmp_get_rom_rev_id(stmp_device_t dev, uint16_t *ver)
259{
260 int len = sizeof(*ver);
261 int ret = stmp_scsi_get_rom_rev_id(dev, ver, &len);
262 if(ret || len != sizeof(*ver))
263 return -1;
264 *ver = stmp_fix_endian16be(*ver);
265 return 0;
266}
267
268int stmp_scsi_get_logical_media_info(stmp_device_t dev, uint8_t info, void *data, int *len)
269{
270 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_MEDIA_INFO, info, 0, data, len);
271}
272
273int stmp_scsi_get_logical_table(stmp_device_t dev, int entry_count, void *buf, int *len)
274{
275 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_TABLE, entry_count, 0, buf, len);
276}
277
278int stmp_get_logical_media_table(stmp_device_t dev, struct stmp_logical_media_table_t **table)
279{
280 struct scsi_stmp_logical_table_header_t header;
281 int len = sizeof(header);
282 int ret = stmp_scsi_get_logical_table(dev, 0, &header, &len);
283 if(ret || len != sizeof(header))
284 return -1;
285 header.count = stmp_fix_endian16be(header.count);
286 int sz = sizeof(header) + header.count * sizeof(struct scsi_stmp_logical_table_entry_t);
287 len = sz;
288 *table = malloc(sz);
289 ret = stmp_scsi_get_logical_table(dev, header.count, &(*table)->header, &len);
290 if(ret || len != sz)
291 return -1;
292 (*table)->header.count = stmp_fix_endian16be((*table)->header.count);
293 for(unsigned i = 0; i < (*table)->header.count; i++)
294 (*table)->entry[i].size = stmp_fix_endian64be((*table)->entry[i].size);
295 return 0;
296}
297
298int stmp_scsi_get_logical_drive_info(stmp_device_t dev, uint8_t drive, uint8_t info, void *data, int *len)
299{
300 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_DRIVE_INFO, drive, info, data, len);
301}
302
303int stmp_scsi_get_device_info(stmp_device_t dev, uint8_t info, void *data, int *len)
304{
305 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_DEVICE_INFO, info, 0, data, len);
306}
307
308int stmp_scsi_get_serial_number(stmp_device_t dev, uint8_t info, void *data, int *len)
309{
310 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_CHIP_SERIAL_NUMBER, info, 0, data, len);
311}
312
313int stmp_scsi_read_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
314 uint32_t count, void *buffer, int *buffer_size)
315{
316 uint8_t cdb[16];
317 memset(cdb, 0, sizeof(cdb));
318 cdb[0] = SCSI_STMP_READ;
319 cdb[1] = SCSI_STMP_CMD_READ_LOGICAL_DRIVE_SECTOR;
320 cdb[2] = drive;
321 address = stmp_fix_endian64be(address);
322 memcpy(&cdb[3], &address, sizeof(address));
323 count = stmp_fix_endian32be(count);
324 memcpy(&cdb[11], &count, sizeof(count));
325
326 uint8_t sense[32];
327 int sense_size = sizeof(sense);
328
329 int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buffer, buffer_size);
330 if(ret < 0)
331 return ret;
332 return stmp_sense_analysis(dev, ret, sense, sense_size);
333}
334
335int stmp_scsi_write_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
336 uint32_t count, void *buffer, int *buffer_size)
337{
338 uint8_t cdb[16];
339 memset(cdb, 0, sizeof(cdb));
340 cdb[0] = SCSI_STMP_WRITE;
341 cdb[1] = SCSI_STMP_CMD_WRITE_LOGICAL_DRIVE_SECTOR;
342 cdb[2] = drive;
343 address = stmp_fix_endian64be(address);
344 memcpy(&cdb[3], &address, sizeof(address));
345 count = stmp_fix_endian32be(count);
346 memcpy(&cdb[11], &count, sizeof(count));
347
348 uint8_t sense[32];
349 int sense_size = sizeof(sense);
350
351 int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_WRITE, sense, &sense_size, buffer, buffer_size);
352 if(ret < 0)
353 return ret;
354 return stmp_sense_analysis(dev, ret, sense, sense_size);
355}
356
357int stmp_read_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
358 uint32_t count, void *buffer, int buffer_size)
359{
360 int len = buffer_size;
361 int ret = stmp_scsi_read_logical_drive_sectors(dev, drive, address, count, buffer, &len);
362 if(ret || len != buffer_size)
363 return -1;
364 return 0;
365}
366
367int stmp_write_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
368 uint32_t count, void *buffer, int buffer_size)
369{
370 int len = buffer_size;
371 int ret = stmp_scsi_write_logical_drive_sectors(dev, drive, address, count, buffer, &len);
372 if(ret || len != buffer_size)
373 return -1;
374 return 0;
375}
376
377#define check_len(l) if(len != l) return -1;
378#define fixn(n, p) *(uint##n##_t *)(p) = stmp_fix_endian##n##be(*(uint##n##_t *)(p))
379#define fix16(p) fixn(16, p)
380#define fix32(p) fixn(32, p)
381#define fix64(p) fixn(64, p)
382
383int stmp_fix_logical_media_info(uint8_t info, void *data, int len)
384{
385 switch(info)
386 {
387 case SCSI_STMP_MEDIA_INFO_NR_DRIVES:
388 check_len(2);
389 fix16(data);
390 return 0;
391 case SCSI_STMP_MEDIA_INFO_TYPE:
392 case SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER_SIZE:
393 case SCSI_STMP_MEDIA_INFO_VENDOR:
394 case SCSI_STMP_MEDIA_INFO_ALLOC_UNIT_SIZE:
395 case SCSI_STMP_MEDIA_INFO_PAGE_SIZE:
396 case SCSI_STMP_MEDIA_INFO_NR_DEVICES:
397 check_len(4);
398 fix32(data);
399 return 0;
400 case SCSI_STMP_MEDIA_INFO_SIZE:
401 case SCSI_STMP_MEDIA_INFO_NAND_ID:
402 check_len(8);
403 fix64(data);
404 return 0;
405 case SCSI_STMP_MEDIA_INFO_IS_INITIALISED:
406 case SCSI_STMP_MEDIA_INFO_STATE:
407 case SCSI_STMP_MEDIA_INFO_IS_WRITE_PROTECTED:
408 case SCSI_STMP_MEDIA_INFO_IS_SYSTEM_MEDIA:
409 case SCSI_STMP_MEDIA_INFO_IS_MEDIA_PRESENT:
410 check_len(1);
411 return 0;
412 case SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER:
413 return 0;
414 default:
415 return -1;
416 }
417}
418
419static void stmp_fix_version(struct scsi_stmp_logical_drive_info_version_t *w)
420{
421 w->major = stmp_fix_endian16be(w->major);
422 w->minor = stmp_fix_endian16be(w->minor);
423 w->revision = stmp_fix_endian16be(w->revision);
424}
425
426int stmp_fix_logical_drive_info(uint8_t info, void *data, int len)
427{
428 switch(info)
429 {
430 case SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER_SIZE:
431 check_len(2);
432 fix16(data);
433 return 0;
434 case SCSI_STMP_DRIVE_INFO_SECTOR_SIZE:
435 case SCSI_STMP_DRIVE_INFO_ERASE_SIZE:
436 case SCSI_STMP_DRIVE_INFO_SIZE_MEGA:
437 case SCSI_STMP_DRIVE_INFO_TYPE:
438 case SCSI_STMP_DRIVE_INFO_SECTOR_ALLOCATION:
439 check_len(4);
440 fix32(data);
441 return 0;
442 case SCSI_STMP_DRIVE_INFO_SIZE:
443 case SCSI_STMP_DRIVE_INFO_SECTOR_COUNT:
444 check_len(8);
445 fix64(data);
446 return 0;
447 case SCSI_STMP_DRIVE_INFO_TAG:
448 case SCSI_STMP_DRIVE_INFO_IS_WRITE_PROTETED:
449 case SCSI_STMP_DRIVE_INFO_MEDIA_PRESENT:
450 case SCSI_STMP_DRIVE_INFO_MEDIA_CHANGE:
451 check_len(1);
452 return 0;
453 case SCSI_STMP_DRIVE_INFO_COMPONENT_VERSION:
454 case SCSI_STMP_DRIVE_INFO_PROJECT_VERSION:
455 check_len(6)
456 stmp_fix_version(data);
457 return 0;
458 case SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER:
459 return 0;
460 default:
461 return -1;
462 }
463}
464
465int stmp_fix_device_info(uint8_t info, void *data, int len)
466{
467 switch(info)
468 {
469 case 0: case 1:
470 check_len(4);
471 fix32(data);
472 return 0;
473 default:
474 return -1;
475 }
476}
477#undef fix64
478#undef fix32
479#undef fix16
480#undef fixn
481#undef checl_len
482
483const char *stmp_get_logical_media_type_string(uint32_t type)
484{
485 switch(type)
486 {
487 case SCSI_STMP_MEDIA_TYPE_NAND: return "NAND";
488 case SCSI_STMP_MEDIA_TYPE_SDMMC: return "SD/MMC";
489 case SCSI_STMP_MEDIA_TYPE_HDD: return "HDD";
490 case SCSI_STMP_MEDIA_TYPE_RAM: return "RAM";
491 case SCSI_STMP_MEDIA_TYPE_iNAND: return "iNAND";
492 default: return "?";
493 }
494}
495
496const char *stmp_get_logical_media_vendor_string(uint32_t type)
497{
498 switch(type)
499 {
500 case SCSI_STMP_MEDIA_VENDOR_SAMSUNG: return "Samsung";
501 case SCSI_STMP_MEDIA_VENDOR_STMICRO: return "ST Micro";
502 case SCSI_STMP_MEDIA_VENDOR_HYNIX: return "Hynix";
503 case SCSI_STMP_MEDIA_VENDOR_MICRON: return "Micron";
504 case SCSI_STMP_MEDIA_VENDOR_TOSHIBA: return "Toshiba";
505 case SCSI_STMP_MEDIA_VENDOR_RENESAS: return "Renesas";
506 case SCSI_STMP_MEDIA_VENDOR_INTEL: return "Intel";
507 case SCSI_STMP_MEDIA_VENDOR_SANDISK: return "Sandisk";
508 default: return "?";
509 }
510}
511
512const char *stmp_get_logical_drive_type_string(uint32_t type)
513{
514 switch(type)
515 {
516 case SCSI_STMP_DRIVE_TYPE_DATA: return "Data";
517 case SCSI_STMP_DRIVE_TYPE_SYSTEM: return "System";
518 case SCSI_STMP_DRIVE_TYPE_HIDDEN: return "Hidden";
519 case SCSI_STMP_DRIVE_TYPE_UNKNOWN: return "Unknown";
520 default: return "?";
521 }
522}
523
524const char *stmp_get_logical_drive_tag_string(uint32_t type)
525{
526 switch(type)
527 {
528 case SCSI_STMP_DRIVE_TAG_STMPSYS_S: return "System";
529 case SCSI_STMP_DRIVE_TAG_HOSTLINK_S: return "Hostlink";
530 case SCSI_STMP_DRIVE_TAG_RESOURCE_BIN: return "Resource";
531 case SCSI_STMP_DRIVE_TAG_EXTRA_S: return "Extra";
532 case SCSI_STMP_DRIVE_TAG_RESOURCE1_BIN: return "Resource1";
533 case SCSI_STMP_DRIVE_TAG_OTGHOST_S: return "OTG";
534 case SCSI_STMP_DRIVE_TAG_HOSTRSC_BIN: return "Host Resource";
535 case SCSI_STMP_DRIVE_TAG_DATA: return "Data";
536 case SCSI_STMP_DRIVE_TAG_HIDDEN: return "Hidden";
537 case SCSI_STMP_DRIVE_TAG_BOOTMANAGER_S: return "Boot";
538 case SCSI_STMP_DRIVE_TAG_UPDATER_S: return "Updater";
539 default: return "?";
540 }
541}
542
543const char *stmp_get_logical_media_state_string(uint8_t state)
544{
545 switch(state)
546 {
547 case SCSI_STMP_MEDIA_STATE_UNKNOWN: return "Unknown";
548 case SCSI_STMP_MEDIA_STATE_ERASED: return "Erased";
549 case SCSI_STMP_MEDIA_STATE_ALLOCATED: return "Allocated";
550 default: return "?";
551 }
552}
553
554int stmp_get_device_serial(stmp_device_t dev, uint8_t **buffer, int *len)
555{
556 *len = 2;
557 uint16_t len16;
558 int ret = stmp_scsi_get_serial_number(dev, 0, &len16, len);
559 if(!ret && *len == 2)
560 {
561 len16 = stmp_fix_endian16be(len16);
562 *len = len16;
563 *buffer = malloc(*len);
564 ret = stmp_scsi_get_serial_number(dev, 1, *buffer, len);
565 }
566 else
567 ret = -1;
568 return ret;
569}
570
571#define ARRAYLEN(x) (int)(sizeof(x)/sizeof((x)[0]))
572
573int stmp_get_logical_media_info(stmp_device_t dev, struct stmp_logical_media_info_t *info)
574{
575 memset(info, 0, sizeof(struct stmp_logical_media_info_t));
576 int len, ret;
577#define entry(name, def) \
578 len = sizeof(info->name); \
579 ret = stmp_scsi_get_logical_media_info(dev, SCSI_STMP_MEDIA_INFO_##def, &info->name, &len); \
580 if(!ret) \
581 ret = stmp_fix_logical_media_info(SCSI_STMP_MEDIA_INFO_##def, &info->name, len); \
582 if(!ret) \
583 info->has.name = true;
584
585 entry(nr_drives, NR_DRIVES);
586 entry(size, SIZE);
587 entry(alloc_size, ALLOC_UNIT_SIZE);
588 entry(initialised, IS_INITIALISED);
589 entry(state, STATE);
590 entry(write_protected, IS_WRITE_PROTECTED);
591 entry(type, TYPE);
592 entry(serial_len, SERIAL_NUMBER_SIZE);
593 entry(system, IS_SYSTEM_MEDIA);
594 entry(present, IS_MEDIA_PRESENT);
595 entry(page_size, PAGE_SIZE);
596 entry(vendor, VENDOR);
597 entry(nand_id, NAND_ID);
598 entry(nr_devices, NR_DEVICES);
599#undef entry
600 if(info->has.serial_len)
601 {
602 info->serial = malloc(info->serial_len);
603 int len = info->serial_len;
604 ret = stmp_scsi_get_logical_media_info(dev, SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER,
605 info->serial, &len);
606 if(ret || len != (int)info->serial_len)
607 free(info->serial);
608 else
609 info->has.serial = true;
610 }
611 return 0;
612}
613
614int stmp_get_logical_drive_info(stmp_device_t dev, uint8_t drive, struct stmp_logical_drive_info_t *info)
615{
616 memset(info, 0, sizeof(struct stmp_logical_drive_info_t));
617 int len, ret;
618#define entry(name, def) \
619 len = sizeof(info->name); \
620 ret = stmp_scsi_get_logical_drive_info(dev, drive, SCSI_STMP_DRIVE_INFO_##def, &info->name, &len); \
621 if(!ret) \
622 ret = stmp_fix_logical_drive_info(SCSI_STMP_DRIVE_INFO_##def, &info->name, len); \
623 if(!ret) \
624 info->has.name = true;
625
626 entry(sector_size, SECTOR_SIZE);
627 entry(erase_size, ERASE_SIZE);
628 entry(size, SIZE);
629 entry(sector_count, SECTOR_COUNT);
630 entry(type, TYPE);
631 entry(tag, TAG);
632 entry(component_version, COMPONENT_VERSION);
633 entry(project_version, PROJECT_VERSION);
634 entry(write_protected, IS_WRITE_PROTECTED);
635 entry(serial_len, SERIAL_NUMBER_SIZE);
636 entry(present, MEDIA_PRESENT);
637 entry(change, MEDIA_CHANGE);
638 entry(sector_alloc, SECTOR_ALLOCATION);
639#undef entry
640 if(info->has.serial_len)
641 {
642 info->serial = malloc(info->serial_len);
643 int len = info->serial_len;
644 ret = stmp_scsi_get_logical_media_info(dev, SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER,
645 info->serial, &len);
646 if(ret || len != (int)info->serial_len)
647 free(info->serial);
648 else
649 info->has.serial = true;
650 }
651 return 0;
652}
653
654static const char *get_size_suffix(unsigned long long size) 68static const char *get_size_suffix(unsigned long long size)
655{ 69{
656 int order = 0; 70 int order = 0;
diff --git a/utils/imxtools/scsitools/stmp_scsi.c b/utils/imxtools/scsitools/stmp_scsi.c
new file mode 100644
index 0000000000..dcda91e295
--- /dev/null
+++ b/utils/imxtools/scsitools/stmp_scsi.c
@@ -0,0 +1,616 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdlib.h>
22#include <string.h>
23#include <stdarg.h>
24#include <stdio.h>
25#define _BSD_SOURCE
26#include <endian.h>
27#include "stmp_scsi.h"
28
29#define MIN(a, b) ((a) < (b) ? (a) : (b))
30
31static int g_endian = -1;
32
33struct stmp_device_t
34{
35 rb_scsi_device_t dev;
36 unsigned flags;
37 void *user;
38 stmp_printf_t printf;
39};
40
41static inline int little_endian(void)
42{
43 if(g_endian == -1)
44 {
45 int i = 1;
46 g_endian = (int)*((unsigned char *)&i) == 1;
47 }
48 return g_endian;
49}
50
51uint16_t stmp_fix_endian16be(uint16_t w)
52{
53 return little_endian() ? w << 8 | w >> 8 : w;
54}
55
56uint32_t stmp_fix_endian32be(uint32_t w)
57{
58 return !little_endian() ? w :
59 (uint32_t)stmp_fix_endian16be(w) << 16 | stmp_fix_endian16be(w >> 16);
60}
61
62uint64_t stmp_fix_endian64be(uint64_t w)
63{
64 return !little_endian() ? w :
65 (uint64_t)stmp_fix_endian32be(w) << 32 | stmp_fix_endian32be(w >> 32);
66}
67
68static void misc_std_printf(void *user, const char *fmt, ...)
69{
70 (void) user;
71 va_list args;
72 va_start(args, fmt);
73 vprintf(fmt, args);
74 va_end(args);
75}
76
77#define stmp_printf(dev, ...) \
78 dev->printf(dev->user, __VA_ARGS__)
79
80#define stmp_debugf(dev, ...) \
81 do{ if(dev->flags & STMP_DEBUG) stmp_printf(dev, __VA_ARGS__); }while(0)
82
83stmp_device_t stmp_open(rb_scsi_device_t rdev, unsigned flags, void *user, stmp_printf_t printf)
84{
85 if(printf == NULL)
86 printf = misc_std_printf;
87 stmp_device_t sdev = malloc(sizeof(struct stmp_device_t));
88 memset(sdev, 0, sizeof(struct stmp_device_t));
89 sdev->dev = rdev;
90 sdev->flags = flags;
91 sdev->user = user;
92 sdev->printf = printf;
93 return sdev;
94}
95
96void stmp_close(stmp_device_t dev)
97{
98 free(dev);
99}
100
101/* returns <0 on error and status otherwise */
102int stmp_scsi(stmp_device_t dev, uint8_t *cdb, int cdb_size, unsigned flags,
103 void *sense, int *sense_size, void *buffer, int *buf_size)
104{
105 struct rb_scsi_raw_cmd_t cmd;
106 memset(&cmd, 0, sizeof(cmd));
107 cmd.dir = RB_SCSI_NONE;
108 if(flags & STMP_READ)
109 cmd.dir = RB_SCSI_READ;
110 if(flags & STMP_WRITE)
111 cmd.dir = RB_SCSI_WRITE;
112 cmd.cdb = cdb;
113 cmd.cdb_len = cdb_size;
114 cmd.sense = sense;
115 cmd.sense_len = *sense_size;
116 cmd.buf = buffer;
117 cmd.buf_len = *buf_size;
118 cmd.tmo = 1;
119 int ret = rb_scsi_raw_xfer(dev->dev, &cmd);
120 *sense_size = cmd.sense_len;
121 *buf_size = cmd.buf_len;
122 return ret == RB_SCSI_OK || ret == RB_SCSI_SENSE ? cmd.status : -ret;
123}
124
125int stmp_sense_analysis(stmp_device_t dev, int status, uint8_t *sense, int sense_size)
126{
127 if(status != 0 && (dev->flags & STMP_DEBUG))
128 {
129 stmp_printf(dev, "Status: %d\n", status);
130 stmp_printf(dev, "Sense:");
131 for(int i = 0; i < sense_size; i++)
132 stmp_printf(dev, " %02x", sense[i]);
133 stmp_printf(dev, "\n");
134 }
135 return status;
136}
137
138static int stmp_scsi_read_cmd(stmp_device_t dev, uint8_t cmd, uint8_t subcmd,
139 uint8_t subsubcmd, void *buf, int *len)
140{
141 uint8_t cdb[16];
142 memset(cdb, 0, sizeof(cdb));
143 cdb[0] = SCSI_STMP_READ;
144 cdb[1] = cmd;
145 cdb[2] = subcmd;
146 cdb[3] = subsubcmd;
147
148 uint8_t sense[32];
149 int sense_size = sizeof(sense);
150
151 int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buf, len);
152 if(ret < 0)
153 return ret;
154 ret = stmp_sense_analysis(dev, ret, sense, sense_size);
155 if(ret)
156 return ret;
157 return 0;
158}
159
160int stmp_scsi_inquiry(stmp_device_t dev, uint8_t *dev_type, char vendor[9], char product[17])
161{
162 unsigned char buffer[36];
163 uint8_t cdb[10];
164 memset(cdb, 0, sizeof(cdb));
165 cdb[0] = 0x12;
166 cdb[4] = sizeof(buffer);
167
168 uint8_t sense[32];
169 int sense_size = sizeof(sense);
170
171 int buf_sz = sizeof(buffer);
172 int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buffer, &buf_sz);
173 if(ret < 0)
174 return ret;
175 ret = stmp_sense_analysis(dev, ret, sense, sense_size);
176 if(ret)
177 return ret;
178 if(buf_sz != sizeof(buffer))
179 return -1;
180 *dev_type = buffer[0];
181 memcpy(vendor, buffer + 8, 8);
182 vendor[8] = 0;
183 memcpy(product, buffer + 16, 16);
184 product[16] = 0;
185 return 0;
186}
187
188int stmp_scsi_get_protocol_version(stmp_device_t dev, void *buf, int *len)
189{
190 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_PROTOCOL_VERSION, 0, 0, buf, len);
191}
192
193int stmp_get_protocol_version(stmp_device_t dev, struct scsi_stmp_protocol_version_t *ver)
194{
195 int len = sizeof(*ver);
196 int ret = stmp_scsi_get_protocol_version(dev, ver, &len);
197 if(ret || len != sizeof(*ver))
198 return -1;
199 return 0;
200}
201
202int stmp_scsi_get_chip_major_rev_id(stmp_device_t dev, void *buf, int *len)
203{
204 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_CHIP_MAJOR_REV_ID, 0, 0, buf, len);
205}
206
207int stmp_get_chip_major_rev_id(stmp_device_t dev, uint16_t *ver)
208{
209 int len = sizeof(*ver);
210 int ret = stmp_scsi_get_chip_major_rev_id(dev, ver, &len);
211 if(ret || len != sizeof(*ver))
212 return -1;
213 *ver = stmp_fix_endian16be(*ver);
214 return 0;
215}
216
217int stmp_scsi_get_rom_rev_id(stmp_device_t dev, void *buf, int *len)
218{
219 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_ROM_REV_ID, 0, 0, buf, len);
220}
221
222int stmp_get_rom_rev_id(stmp_device_t dev, uint16_t *ver)
223{
224 int len = sizeof(*ver);
225 int ret = stmp_scsi_get_rom_rev_id(dev, ver, &len);
226 if(ret || len != sizeof(*ver))
227 return -1;
228 *ver = stmp_fix_endian16be(*ver);
229 return 0;
230}
231
232int stmp_scsi_get_logical_media_info(stmp_device_t dev, uint8_t info, void *data, int *len)
233{
234 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_MEDIA_INFO, info, 0, data, len);
235}
236
237int stmp_scsi_get_logical_table(stmp_device_t dev, int entry_count, void *buf, int *len)
238{
239 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_TABLE, entry_count, 0, buf, len);
240}
241
242int stmp_get_logical_media_table(stmp_device_t dev, struct stmp_logical_media_table_t **table)
243{
244 struct scsi_stmp_logical_table_header_t header;
245 int len = sizeof(header);
246 int ret = stmp_scsi_get_logical_table(dev, 0, &header, &len);
247 if(ret || len != sizeof(header))
248 return -1;
249 header.count = stmp_fix_endian16be(header.count);
250 int sz = sizeof(header) + header.count * sizeof(struct scsi_stmp_logical_table_entry_t);
251 len = sz;
252 *table = malloc(sz);
253 ret = stmp_scsi_get_logical_table(dev, header.count, &(*table)->header, &len);
254 if(ret || len != sz)
255 return -1;
256 (*table)->header.count = stmp_fix_endian16be((*table)->header.count);
257 for(unsigned i = 0; i < (*table)->header.count; i++)
258 (*table)->entry[i].size = stmp_fix_endian64be((*table)->entry[i].size);
259 return 0;
260}
261
262int stmp_scsi_get_logical_drive_info(stmp_device_t dev, uint8_t drive, uint8_t info, void *data, int *len)
263{
264 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_DRIVE_INFO, drive, info, data, len);
265}
266
267int stmp_scsi_get_device_info(stmp_device_t dev, uint8_t info, void *data, int *len)
268{
269 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_DEVICE_INFO, info, 0, data, len);
270}
271
272int stmp_scsi_get_serial_number(stmp_device_t dev, uint8_t info, void *data, int *len)
273{
274 return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_CHIP_SERIAL_NUMBER, info, 0, data, len);
275}
276
277int stmp_scsi_read_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
278 uint32_t count, void *buffer, int *buffer_size)
279{
280 uint8_t cdb[16];
281 memset(cdb, 0, sizeof(cdb));
282 cdb[0] = SCSI_STMP_READ;
283 cdb[1] = SCSI_STMP_CMD_READ_LOGICAL_DRIVE_SECTOR;
284 cdb[2] = drive;
285 address = stmp_fix_endian64be(address);
286 memcpy(&cdb[3], &address, sizeof(address));
287 count = stmp_fix_endian32be(count);
288 memcpy(&cdb[11], &count, sizeof(count));
289
290 uint8_t sense[32];
291 int sense_size = sizeof(sense);
292
293 int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buffer, buffer_size);
294 if(ret < 0)
295 return ret;
296 return stmp_sense_analysis(dev, ret, sense, sense_size);
297}
298
299int stmp_scsi_write_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
300 uint32_t count, void *buffer, int *buffer_size)
301{
302 uint8_t cdb[16];
303 memset(cdb, 0, sizeof(cdb));
304 cdb[0] = SCSI_STMP_WRITE;
305 cdb[1] = SCSI_STMP_CMD_WRITE_LOGICAL_DRIVE_SECTOR;
306 cdb[2] = drive;
307 address = stmp_fix_endian64be(address);
308 memcpy(&cdb[3], &address, sizeof(address));
309 count = stmp_fix_endian32be(count);
310 memcpy(&cdb[11], &count, sizeof(count));
311
312 uint8_t sense[32];
313 int sense_size = sizeof(sense);
314
315 int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_WRITE, sense, &sense_size, buffer, buffer_size);
316 if(ret < 0)
317 return ret;
318 return stmp_sense_analysis(dev, ret, sense, sense_size);
319}
320
321int stmp_read_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
322 uint32_t count, void *buffer, int buffer_size)
323{
324 int len = buffer_size;
325 int ret = stmp_scsi_read_logical_drive_sectors(dev, drive, address, count, buffer, &len);
326 if(ret || len != buffer_size)
327 return -1;
328 return 0;
329}
330
331int stmp_write_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
332 uint32_t count, void *buffer, int buffer_size)
333{
334 int len = buffer_size;
335 int ret = stmp_scsi_write_logical_drive_sectors(dev, drive, address, count, buffer, &len);
336 if(ret || len != buffer_size)
337 return -1;
338 return 0;
339}
340
341#define check_len(l) if(len != l) return -1;
342#define fixn(n, p) *(uint##n##_t *)(p) = stmp_fix_endian##n##be(*(uint##n##_t *)(p))
343#define fix16(p) fixn(16, p)
344#define fix32(p) fixn(32, p)
345#define fix64(p) fixn(64, p)
346
347int stmp_fix_logical_media_info(uint8_t info, void *data, int len)
348{
349 switch(info)
350 {
351 case SCSI_STMP_MEDIA_INFO_NR_DRIVES:
352 check_len(2);
353 fix16(data);
354 return 0;
355 case SCSI_STMP_MEDIA_INFO_TYPE:
356 case SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER_SIZE:
357 case SCSI_STMP_MEDIA_INFO_VENDOR:
358 case SCSI_STMP_MEDIA_INFO_ALLOC_UNIT_SIZE:
359 case SCSI_STMP_MEDIA_INFO_PAGE_SIZE:
360 case SCSI_STMP_MEDIA_INFO_NR_DEVICES:
361 check_len(4);
362 fix32(data);
363 return 0;
364 case SCSI_STMP_MEDIA_INFO_SIZE:
365 case SCSI_STMP_MEDIA_INFO_NAND_ID:
366 check_len(8);
367 fix64(data);
368 return 0;
369 case SCSI_STMP_MEDIA_INFO_IS_INITIALISED:
370 case SCSI_STMP_MEDIA_INFO_STATE:
371 case SCSI_STMP_MEDIA_INFO_IS_WRITE_PROTECTED:
372 case SCSI_STMP_MEDIA_INFO_IS_SYSTEM_MEDIA:
373 case SCSI_STMP_MEDIA_INFO_IS_MEDIA_PRESENT:
374 check_len(1);
375 return 0;
376 case SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER:
377 return 0;
378 default:
379 return -1;
380 }
381}
382
383static void stmp_fix_version(struct scsi_stmp_logical_drive_info_version_t *w)
384{
385 w->major = stmp_fix_endian16be(w->major);
386 w->minor = stmp_fix_endian16be(w->minor);
387 w->revision = stmp_fix_endian16be(w->revision);
388}
389
390int stmp_fix_logical_drive_info(uint8_t info, void *data, int len)
391{
392 switch(info)
393 {
394 case SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER_SIZE:
395 check_len(2);
396 fix16(data);
397 return 0;
398 case SCSI_STMP_DRIVE_INFO_SECTOR_SIZE:
399 case SCSI_STMP_DRIVE_INFO_ERASE_SIZE:
400 case SCSI_STMP_DRIVE_INFO_SIZE_MEGA:
401 case SCSI_STMP_DRIVE_INFO_TYPE:
402 case SCSI_STMP_DRIVE_INFO_SECTOR_ALLOCATION:
403 check_len(4);
404 fix32(data);
405 return 0;
406 case SCSI_STMP_DRIVE_INFO_SIZE:
407 case SCSI_STMP_DRIVE_INFO_SECTOR_COUNT:
408 check_len(8);
409 fix64(data);
410 return 0;
411 case SCSI_STMP_DRIVE_INFO_TAG:
412 case SCSI_STMP_DRIVE_INFO_IS_WRITE_PROTETED:
413 case SCSI_STMP_DRIVE_INFO_MEDIA_PRESENT:
414 case SCSI_STMP_DRIVE_INFO_MEDIA_CHANGE:
415 check_len(1);
416 return 0;
417 case SCSI_STMP_DRIVE_INFO_COMPONENT_VERSION:
418 case SCSI_STMP_DRIVE_INFO_PROJECT_VERSION:
419 check_len(6)
420 stmp_fix_version(data);
421 return 0;
422 case SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER:
423 return 0;
424 default:
425 return -1;
426 }
427}
428
429int stmp_fix_device_info(uint8_t info, void *data, int len)
430{
431 switch(info)
432 {
433 case 0: case 1:
434 check_len(4);
435 fix32(data);
436 return 0;
437 default:
438 return -1;
439 }
440}
441#undef fix64
442#undef fix32
443#undef fix16
444#undef fixn
445#undef checl_len
446
447const char *stmp_get_logical_media_type_string(uint32_t type)
448{
449 switch(type)
450 {
451 case SCSI_STMP_MEDIA_TYPE_NAND: return "NAND";
452 case SCSI_STMP_MEDIA_TYPE_SDMMC: return "SD/MMC";
453 case SCSI_STMP_MEDIA_TYPE_HDD: return "HDD";
454 case SCSI_STMP_MEDIA_TYPE_RAM: return "RAM";
455 case SCSI_STMP_MEDIA_TYPE_iNAND: return "iNAND";
456 default: return "?";
457 }
458}
459
460const char *stmp_get_logical_media_vendor_string(uint32_t type)
461{
462 switch(type)
463 {
464 case SCSI_STMP_MEDIA_VENDOR_SAMSUNG: return "Samsung";
465 case SCSI_STMP_MEDIA_VENDOR_STMICRO: return "ST Micro";
466 case SCSI_STMP_MEDIA_VENDOR_HYNIX: return "Hynix";
467 case SCSI_STMP_MEDIA_VENDOR_MICRON: return "Micron";
468 case SCSI_STMP_MEDIA_VENDOR_TOSHIBA: return "Toshiba";
469 case SCSI_STMP_MEDIA_VENDOR_RENESAS: return "Renesas";
470 case SCSI_STMP_MEDIA_VENDOR_INTEL: return "Intel";
471 case SCSI_STMP_MEDIA_VENDOR_SANDISK: return "Sandisk";
472 default: return "?";
473 }
474}
475
476const char *stmp_get_logical_drive_type_string(uint32_t type)
477{
478 switch(type)
479 {
480 case SCSI_STMP_DRIVE_TYPE_DATA: return "Data";
481 case SCSI_STMP_DRIVE_TYPE_SYSTEM: return "System";
482 case SCSI_STMP_DRIVE_TYPE_HIDDEN: return "Hidden";
483 case SCSI_STMP_DRIVE_TYPE_UNKNOWN: return "Unknown";
484 default: return "?";
485 }
486}
487
488const char *stmp_get_logical_drive_tag_string(uint32_t type)
489{
490 switch(type)
491 {
492 case SCSI_STMP_DRIVE_TAG_STMPSYS_S: return "System";
493 case SCSI_STMP_DRIVE_TAG_HOSTLINK_S: return "Hostlink";
494 case SCSI_STMP_DRIVE_TAG_RESOURCE_BIN: return "Resource";
495 case SCSI_STMP_DRIVE_TAG_EXTRA_S: return "Extra";
496 case SCSI_STMP_DRIVE_TAG_RESOURCE1_BIN: return "Resource1";
497 case SCSI_STMP_DRIVE_TAG_OTGHOST_S: return "OTG";
498 case SCSI_STMP_DRIVE_TAG_HOSTRSC_BIN: return "Host Resource";
499 case SCSI_STMP_DRIVE_TAG_DATA: return "Data";
500 case SCSI_STMP_DRIVE_TAG_HIDDEN: return "Hidden";
501 case SCSI_STMP_DRIVE_TAG_BOOTMANAGER_S: return "Boot";
502 case SCSI_STMP_DRIVE_TAG_UPDATER_S: return "Updater";
503 default: return "?";
504 }
505}
506
507const char *stmp_get_logical_media_state_string(uint8_t state)
508{
509 switch(state)
510 {
511 case SCSI_STMP_MEDIA_STATE_UNKNOWN: return "Unknown";
512 case SCSI_STMP_MEDIA_STATE_ERASED: return "Erased";
513 case SCSI_STMP_MEDIA_STATE_ALLOCATED: return "Allocated";
514 default: return "?";
515 }
516}
517
518int stmp_get_device_serial(stmp_device_t dev, uint8_t **buffer, int *len)
519{
520 *len = 2;
521 uint16_t len16;
522 int ret = stmp_scsi_get_serial_number(dev, 0, &len16, len);
523 if(!ret && *len == 2)
524 {
525 len16 = stmp_fix_endian16be(len16);
526 *len = len16;
527 *buffer = malloc(*len);
528 ret = stmp_scsi_get_serial_number(dev, 1, *buffer, len);
529 }
530 else
531 ret = -1;
532 return ret;
533}
534
535#define ARRAYLEN(x) (int)(sizeof(x)/sizeof((x)[0]))
536
537int stmp_get_logical_media_info(stmp_device_t dev, struct stmp_logical_media_info_t *info)
538{
539 memset(info, 0, sizeof(struct stmp_logical_media_info_t));
540 int len, ret;
541#define entry(name, def) \
542 len = sizeof(info->name); \
543 ret = stmp_scsi_get_logical_media_info(dev, SCSI_STMP_MEDIA_INFO_##def, &info->name, &len); \
544 if(!ret) \
545 ret = stmp_fix_logical_media_info(SCSI_STMP_MEDIA_INFO_##def, &info->name, len); \
546 if(!ret) \
547 info->has.name = true;
548
549 entry(nr_drives, NR_DRIVES);
550 entry(size, SIZE);
551 entry(alloc_size, ALLOC_UNIT_SIZE);
552 entry(initialised, IS_INITIALISED);
553 entry(state, STATE);
554 entry(write_protected, IS_WRITE_PROTECTED);
555 entry(type, TYPE);
556 entry(serial_len, SERIAL_NUMBER_SIZE);
557 entry(system, IS_SYSTEM_MEDIA);
558 entry(present, IS_MEDIA_PRESENT);
559 entry(page_size, PAGE_SIZE);
560 entry(vendor, VENDOR);
561 entry(nand_id, NAND_ID);
562 entry(nr_devices, NR_DEVICES);
563#undef entry
564 if(info->has.serial_len)
565 {
566 info->serial = malloc(info->serial_len);
567 int len = info->serial_len;
568 ret = stmp_scsi_get_logical_media_info(dev, SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER,
569 info->serial, &len);
570 if(ret || len != (int)info->serial_len)
571 free(info->serial);
572 else
573 info->has.serial = true;
574 }
575 return 0;
576}
577
578int stmp_get_logical_drive_info(stmp_device_t dev, uint8_t drive, struct stmp_logical_drive_info_t *info)
579{
580 memset(info, 0, sizeof(struct stmp_logical_drive_info_t));
581 int len, ret;
582#define entry(name, def) \
583 len = sizeof(info->name); \
584 ret = stmp_scsi_get_logical_drive_info(dev, drive, SCSI_STMP_DRIVE_INFO_##def, &info->name, &len); \
585 if(!ret) \
586 ret = stmp_fix_logical_drive_info(SCSI_STMP_DRIVE_INFO_##def, &info->name, len); \
587 if(!ret) \
588 info->has.name = true;
589
590 entry(sector_size, SECTOR_SIZE);
591 entry(erase_size, ERASE_SIZE);
592 entry(size, SIZE);
593 entry(sector_count, SECTOR_COUNT);
594 entry(type, TYPE);
595 entry(tag, TAG);
596 entry(component_version, COMPONENT_VERSION);
597 entry(project_version, PROJECT_VERSION);
598 entry(write_protected, IS_WRITE_PROTECTED);
599 entry(serial_len, SERIAL_NUMBER_SIZE);
600 entry(present, MEDIA_PRESENT);
601 entry(change, MEDIA_CHANGE);
602 entry(sector_alloc, SECTOR_ALLOCATION);
603#undef entry
604 if(info->has.serial_len)
605 {
606 info->serial = malloc(info->serial_len);
607 int len = info->serial_len;
608 ret = stmp_scsi_get_logical_media_info(dev, SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER,
609 info->serial, &len);
610 if(ret || len != (int)info->serial_len)
611 free(info->serial);
612 else
613 info->has.serial = true;
614 }
615 return 0;
616}