summaryrefslogtreecommitdiff
path: root/utils/imxtools/scsitools/stmp_scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/imxtools/scsitools/stmp_scsi.c')
-rw-r--r--utils/imxtools/scsitools/stmp_scsi.c616
1 files changed, 616 insertions, 0 deletions
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}