USB Mass Storage BOT чиним multi LUN у STM32

в 15:40, , рубрики: LUN, msc multi LUN, stm32, stm32 hal, stm32l, USB Mass Storage, программирование микроконтроллеров

Попалась задача в проекте реализовать, чтобы по USB микроконтроллер прикидывался несколькими дисковыми устройствами для MicroSD, встроенной EEPROM и нескольких страничек оперативной памяти. Решил, что вполне логично, пойти по пути наименьшего сопротивления, попробовав запустить из коробки, то что ST реализовали в своей библиотеке. Работа c USB разделена у них на уровни абстракции: драйвер + MiddleWare:

USB библиотека STM32
USB библиотека STM32

Ошибки у нас закрались MiddleWare и благодаря тому, что MiddleWare максимально абстрагирован от железа, этом метод позволит исправить реализацию и для остальных семейств с минимальными правками кода. Подробное описание MiddleWare расписано у ST в UM1717, UM0424, UM1021, UM1720.

Запускаем из коробки (в чистом виде, что ST предоставил)

Создаём в кубе проект, застраиваем USB и выбираем в MiddleWare Class For FS IP: Mass Storage Class и правим при желании дескрипторы. Затем в файле USB_DEVICE->App->usbd_storage_if.c прописываем логику работы нашего устройства и описание LUN. Привожу изменённую часть файла:

/* USER CODE BEGIN PRIVATE_TYPES */

typedef enum LUN_NUM{
	LUN_NUM_MICROSD	 =	0,
	LUN_NUM_EEPROM,
	LUN_NUM_SYSTEM,
	LUN_NUM_TEST
} lun_num_t;

/* USER CODE END PRIVATE_TYPES */

/* USER CODE BEGIN PRIVATE_DEFINES */

#define STORAGE_LUNS	0x8

#define EEPROM_BLOCK_SIZE 512
#define EEPROM_BLOCKS 	  64

/* USER CODE END PRIVATE_DEFINES */

/** USB Mass storage Standard Inquiry Data. */
const int8_t STORAGE_Inquirydata_FS[] = {/* 36 */

  /* LUN 0 */
  0x00,
  0x00, // Disable MSB bit - for multipartishion recognize in windows, removeble device = 0x80
  0x02,
  0x02,
  (STANDARD_INQUIRY_DATA_LEN - 5),
  0x00,
  0x00,
  0x00,
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
  'M', 'i', 'c', 'r', 'o', 'S', 'D', ' ', /* Product      : 16 Bytes */
  'D', 'e', 'v', 'i', 'c', 'e', ' ', ' ',
  '0', '.', '0' ,'1',                      /* Version      : 4 Bytes */

  /* LUN 1 */
  0x00, // bit4:0 - peripheral device type, bit7:5 - reserved
  0x00, // bit6:0 - reserved, bit7 - removable media bit (set to 1 to indicate removable media)
  0x02, // bit2:0 - ANSI version, bit5:3 - ECMA version, bit7:6 - ISO version
  0x02, // bit3:0 - Response data format, bit7:4 - reserved
  (STANDARD_INQUIRY_DATA_LEN - 5), // additional length - specify the length in bytes of the parameters.
  0x00, // reserved
  0x00, // reserved
  0x00, // reserved
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer: 8 bytes */
  'E', 'E', 'P', 'R', 'O', 'M', ' ', ' ', /* Product : 16 Bytes */
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  '0', '.', '0', '1', /* Version : 4 Bytes */

  /* LUN 2 */
  0x00, // bit4:0 - peripheral device type, bit7:5 - reserved
  0x00, // bit6:0 - reserved, bit7 - removable media bit (set to 1 to indicate removable media)
  0x02, // bit2:0 - ANSI version, bit5:3 - ECMA version, bit7:6 - ISO version
  0x02, // bit3:0 - Response data format, bit7:4 - reserved
  (STANDARD_INQUIRY_DATA_LEN - 5), // additional length - specify the length in bytes of the parameters.
  0x00, // reserved
  0x00, // reserved
  0x00, // reserved
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer: 8 bytes */
  'S', 'y', 's', 't', 'e', 'm', ' ', ' ', /* Product : 16 Bytes */
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  '0', '.', '0', '1', /* Version : 4 Bytes */

   /* LUN 3 */
  0x00, // bit4:0 - peripheral device type, bit7:5 - reserved
  0x00, // bit6:0 - reserved, bit7 - removable media bit (set to 1 to indicate removable media)
  0x02, // bit2:0 - ANSI version, bit5:3 - ECMA version, bit7:6 - ISO version
  0x02, // bit3:0 - Response data format, bit7:4 - reserved
  (STANDARD_INQUIRY_DATA_LEN - 5), // additional length - specify the length in bytes of the parameters.
  0x00, // reserved
  0x00, // reserved
  0x00, // reserved
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer: 8 bytes */
  'T', 'e', 's', 't', ' ', ' ', ' ', ' ', /* Product : 16 Bytes */
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  '0', '.', '0', '1', /* Version : 4 Bytes */


  /* LUN 4 */
  0x00,
  0x00, // Disable MSB bit - for multipartishion recognize in windows, removeble device = 0x80
  0x02,
  0x02,
  (STANDARD_INQUIRY_DATA_LEN - 5),
  0x00,
  0x00,
  0x00,
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
  'M', 'i', 'c', 'r', 'o', 'S', 'D', '2', /* Product      : 16 Bytes */
  'D', 'e', 'v', 'i', 'c', 'e', ' ', ' ',
  '0', '.', '0' ,'1',                      /* Version      : 4 Bytes */

  /* LUN 5 */
  0x00, // bit4:0 - peripheral device type, bit7:5 - reserved
  0x00, // bit6:0 - reserved, bit7 - removable media bit (set to 1 to indicate removable media)
  0x02, // bit2:0 - ANSI version, bit5:3 - ECMA version, bit7:6 - ISO version
  0x02, // bit3:0 - Response data format, bit7:4 - reserved
  (STANDARD_INQUIRY_DATA_LEN - 5), // additional length - specify the length in bytes of the parameters.
  0x00, // reserved
  0x00, // reserved
  0x00, // reserved
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer: 8 bytes */
  'E', 'E', 'P', 'R', 'O', 'M', '2', ' ', /* Product : 16 Bytes */
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  '0', '.', '0', '1', /* Version : 4 Bytes */

  /* LUN 6 */
  0x00, // bit4:0 - peripheral device type, bit7:5 - reserved
  0x00, // bit6:0 - reseForrved, bit7 - removable media bit (set to 1 to indicate removable media)
  0x02, // bit2:0 - ANSI version, bit5:3 - ECMA version, bit7:6 - ISO version
  0x02, // bit3:0 - Response data format, bit7:4 - reserved
  (STANDARD_INQUIRY_DATA_LEN - 5), // additional length - specify the length in bytes of the parameters.
  0x00, // reserved
  0x00, // reserved
  0x00, // reserved
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer: 8 bytes */
  'S', 'y', 's', 't', 'e', 'm', '2', ' ', /* Product : 16 Bytes */
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  '0', '.', '0', '1', /* Version : 4 Bytes */

   /* LUN 7 */
  0x00, // bit4:0 - peripheral device type, bit7:5 - reserved
  0x00, // bit6:0 - reserved, bit7 - removable media bit (set to 1 to indicate removable media)
  0x02, // bit2:0 - ANSI version, bit5:3 - ECMA version, bit7:6 - ISO version
  0x02, // bit3:0 - Response data format, bit7:4 - reserved
  (STANDARD_INQUIRY_DATA_LEN - 5), // additional length - specify the length in bytes of the parameters.
  0x00, // reserved
  0x00, // reserved
  0x00, // reserved
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer: 8 bytes */
  'T', 'e', 's', 't', '2', ' ', ' ', ' ', /* Product : 16 Bytes */
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  '0', '.', '0', '1', /* Version : 4 Bytes */

 };
/* USER CODE END INQUIRY_DATA_FS */

int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
  /* USER CODE BEGIN 3 */
  switch(lun){
  	  case LUN_NUM_MICROSD:
  		  *block_num  = sd_card_glb->data.size_kb << 1;
  		  *block_size = sd_card_glb->data.block_size;
  		  break;
  	  case LUN_NUM_EEPROM:
  	  	  *block_num  = EEPROM_BLOCKS;
  	  	  *block_size = EEPROM_BLOCK_SIZE;
  	  	  break;
  	  case LUN_NUM_SYSTEM:
  	  	  *block_num  = EEPROM_BLOCKS << 2;
  	  	  *block_size = EEPROM_BLOCK_SIZE;
  	  	  break;
  	  case LUN_NUM_TEST:
  	  	  *block_num  = EEPROM_BLOCKS << 4;
  	  	  *block_size = EEPROM_BLOCK_SIZE;
  	  	  break;
  	  case 0x04:
  	  	  *block_num  = EEPROM_BLOCKS << 5;
  	  	  *block_size = EEPROM_BLOCK_SIZE;
  	  	  break;
  	  case 0x05:
  	  	  *block_num  = EEPROM_BLOCKS << 6;
  	  	  *block_size = EEPROM_BLOCK_SIZE;
  	  	  break;
  	  case 0x06:
  	  	  *block_num  = EEPROM_BLOCKS << 7;
  	  	  *block_size = EEPROM_BLOCK_SIZE;
  	  	  break;
  	  case 0x07:
  	  	  *block_num  = EEPROM_BLOCKS << 8;
  	  	  *block_size = EEPROM_BLOCK_SIZE;
  	  	  break;
  }


  return (USBD_OK);
  /* USER CODE END 3 */
}

int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */

  switch(lun){
  	  case LUN_NUM_MICROSD:
  		  sd_card_read_single_block(sd_card_glb, blk_addr, buf);
		/*	for (int i =0 ; i<512; i++){
						  buf[i] = blk_addr;
			}*/
		  break;
	  case LUN_NUM_EEPROM:
		  for (int i =0 ; i<512; i++){
			  buf[i] = i;
		  }
		  break;
	  case LUN_NUM_SYSTEM:
  	  	  for (int i =0 ; i<512; i++){
			  buf[i] = blk_addr;
		  }
  	  	  break;
  	  case LUN_NUM_TEST:
  	  	  for (int i =0 ; i<512; i++){
			  buf[i] = lun;
		  }
  	  	  break;
  }


  return (USBD_OK);
  /* USER CODE END 6 */
}

Собираем проект, запускаем и видим, что у нас вместо тестовых 8 LUN определилось только 2, да и нормально работают, если в STORAGE_GetCapacity_FS выдать одинаковый размер для обоих LUN, да ещё устройство переодически сбрасывается...

В kernel log:

usb 1-1: new full-speed USB device number 10 using xhci_hcd
usb 1-1: New USB device found, idVendor=0483, idProduct=572a, bcdDevice= 2.00
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1: Product: Test MASS Storage
usb 1-1: Manufacturer: Developer
usb 1-1: SerialNumber: 2062369C5950
usb-storage 1-1:1.0: USB Mass Storage device detected
scsi host4: usb-storage 1-1:1.0
scsi 4:0:0:0: Direct-Access     STM      MicroSD Device   0.01 PQ: 0 ANSI: 2
scsi 4:0:0:1: Direct-Access     STM      EEPROM           0.01 PQ: 0 ANSI: 2
scsi 4:0:0:0: Attached scsi generic sg1 type 0
scsi 4:0:0:1: Attached scsi generic sg2 type 0
sd 4:0:0:0: [sdb] 1030144 512-byte logical blocks: (527 MB/503 MiB)
sd 4:0:0:1: [sdc] 64 512-byte logical blocks: (32.8 kB/32.0 KiB)
sd 4:0:0:1: [sdc] Write Protect is off
sd 4:0:0:1: [sdc] Mode Sense: 22 0 0 0
sd 4:0:0:1: [sdc] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
 sdb: sdb1 sdb2 sdb3
usb 1-1: reset full-speed USB device number 10 using xhci_hcd
sd 4:0:0:0: [sdb] Attached SCSI disk
usb 1-1: reset full-speed USB device number 10 using xhci_hcd
usb 1-1: reset full-speed USB device number 10 using xhci_hcd
sd 4:0:0:0: [sdb] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE cmd_age=0s
sd 4:0:0:0: [sdb] tag#0 Sense Key : Illegal Request [current]
sd 4:0:0:0: [sdb] tag#0 Add. Sense: Logical block address out of range
sd 4:0:0:0: [sdb] tag#0 CDB: Read(10) 28 0 0 0f b7 f8 0 0 1 0
blk_update_request: critical target error, dev sdb, sector 1030136 op 0x0:(READ) flags 0x80700 phys_seg 1 prio class 0
sd 4:0:0:1: [sdc] Attached SCSI disk
sd 4:0:0:0: [sdb] tag#0 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE cmd_age=0s
sd 4:0:0:0: [sdb] tag#0 Sense Key : Illegal Request [current]
sd 4:0:0:0: [sdb] tag#0 Add. Sense: Logical block address out of range
sd 4:0:0:0: [sdb] tag#0 CDB: Read(10) 28 0 0 0f b7 f8 0 0 1 0
blk_update_request: critical target error, dev sdb, sector 1030136 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
buffer_io_error: 1 callbacks suppressed
Buffer I/O error on dev sdb, logical block 128767 async page read

В логе USB, захваченным Wireshark:

запрос USBMS 64 GET MAX LUN - отдаёт 7 (LUN нумеруются с 0 и отдаётся максимально возможный номер), а LUN 2 и остальные - игнорируются

ответы на запросы SCSI: Data In LUN: (Mode Sense(6) - говорят что получены неправильные данные от устройства, а это данные о параметров каждого LUN, в частности, делающие их readonly

не знает команду USBMS 95 SCSI Command: 0xa1 LUN:0x00 - команда ATA Command Pass-Through, после которой идёт переинициализация устройства по шине c продолжением работы:

386 4.538519  1.10.1  host  USBMS 77  SCSI: Response LUN: 0x00 (Read Capacity(10)) (Good)
387 4.538572  host  1.10.1  USBMS 95  SCSI Command: 0xa1 LUN:0x00
388 4.538641  1.10.1  host  USB 64  URB_BULK out
389 4.538657  host  1.10.1  USB 64  URB_BULK in
390 4.538711  1.10.1  host  USB 64  URB_BULK in
391 4.538726  host  1.10.0  USB 64  CLEAR FEATURE Request
392 4.538810  1.10.0  host  USB 64  CLEAR FEATURE Response
393 4.538824  host  1.10.1  USB 64  URB_BULK in
394 4.538925  1.10.1  host  USB 64  URB_BULK in
395 4.538937  host  1.10.0  USB 64  CLEAR FEATURE Request
396 4.539014  1.10.0  host  USB 64  CLEAR FEATURE Response
397 4.539067  host  1.10.1  USB 64  URB_BULK in
398 4.539125  1.10.1  host  USB 64  URB_BULK in
399 4.539169  host  1.10.0  USB 64  CLEAR FEATURE Request
400 4.539254  1.10.0  host  USB 64  CLEAR FEATURE Response
415 4.815078  host  1.10.0  USB 64  GET DESCRIPTOR Request DEVICE
416 4.815289  1.10.0  host  USB 82  GET DESCRIPTOR Response DEVICE
417 4.815371  host  1.10.0  USB 64  GET DESCRIPTOR Request BOS
418 4.815507  1.10.0  host  USB 69  GET DESCRIPTOR Response BOS
419 4.815584  host  1.10.0  USB 64  GET DESCRIPTOR Request BOS
420 4.815802  1.10.0  host  USB 76  GET DESCRIPTOR Response BOS
421 4.815898  host  1.10.0  USB 64  GET DESCRIPTOR Request CONFIGURATION
422 4.816161  1.10.0  host  USB 96  GET DESCRIPTOR Response CONFIGURATION
423 4.816257  host  1.10.0  USB 64  GET DESCRIPTOR Request CONFIGURATION
424 4.816527  1.10.0  host  USB 96  GET DESCRIPTOR Response CONFIGURATION
425 4.816616  host  1.10.0  USB 64  GET DESCRIPTOR Request CONFIGURATION
426 4.816874  1.10.0  host  USB 96  GET DESCRIPTOR Response CONFIGURATION
427 4.816959  host  1.10.0  USB 64  GET DESCRIPTOR Request CONFIGURATION
428 4.817224  1.10.0  host  USB 96  GET DESCRIPTOR Response CONFIGURATION
429 4.817309  host  1.10.0  USB 64  GET DESCRIPTOR Request STRING
430 4.817470  1.10.0  host  USB 90  GET DESCRIPTOR Response STRING
431 4.818177  host  1.10.0  USB 64  SET CONFIGURATION Request
432 4.818338  1.10.0  host  USB 64  SET CONFIGURATION Response
433 4.818507  host  1.10.1  USBMS 95  SCSI: Read(10) LUN: 0x03 (LBA: 0x00000008, Len: 8)

В итоге, библиотека не работает с несколькими LUN, разве что при одном условии у нас только 2 LUN и их размеры равны. Обнаруженные проблемы:

  1. Независимо от указанного нами количество LUN в ответе на call back функцию int8_t STORAGE_GetMaxLun_FS(void) - отдаёт правильное количесво LUN, но LUN больше 1 - игнорируются

  2. Если LUNы разного размера - возможно корректно работать только с меньшим из них, иначе, судя по логам - недопустимый для чтения номер блока

  3. Постоянный сброс устройства по шине из-за отсутствия ответа на команду SCSI 0xa1 ATA Command Pass-Through

Для лучшего понимания, что мы будем дальше делать, кратко расмотрим работу Mass Storage с интерфейсом BOT

Описание работы USB Mass Storage BOT

Протокол BOT расшифровывается как Bulk Only Transfer, который ещё также называют BBB, так как все 3 фазы обмена (команд/данных/статуса) используют конечные точки. Существует ещё протокол CBI - Control Buck Interrupt, использующийся, в основном, для full-speed floppy дисководов.

На рисунке ниже изображена передача команд, данных и статуса по протоколу BOT. Контейнер командного блока CBW представляет из себя короткий пакет, длиной 31 байт. CBW и все последующие данные с контейнером статуса команды CSW представлют из себя пакет. Ещё одна особенность, это кодировка CBW - little-endian с LSB (0 байт идёт первым).

Передача команд/данных/статуса через BOT интерфейс
Передача команд/данных/статуса через BOT интерфейс

В интерфейс BOT завернут транспортный протокол SCSI (Small Computer System Interface), разработанный ещё в 1978 году настолько удачным, что используется до сих пор для взаимодействия с блочными носителями данных. Работа по SCSI выглядит следующим образом:

  1. Устройству хост отправляет команду с параметрами: SCSI: [команда + параметры]

  2. Устройство отдаёт хосту данные: SCSI Payload (Inquiry Response Data)

  3. Устройство отдаёт хосту статус: SCSI: Response (Inquiry) [статус]

    Чтение данных
    Чтение данных
Запись данных
Запись данных

Рассмотрим минимальных набор команд для определения нашего устройство системой. Команды взаимодействия с нашим устройством по USB выглядят следующим образом:

Пртокол

Направление

Команда

Данные

USB

->

Запрос дескрипторов устройства

Тип дескрипторов

USB

<-

DESCRIPTOR Request

Дескрипторы

USBMS

->

Запрос максимального номера LUN

USBMS

<-

GET MAX LUN Response

Максимальный LUN

SCSI

->

Запрос структуры LUN

номер LUN

SCSI

<-

SCSI: Data In LUN: 0xyy (Inquiry Response Data)

Структура LUN

SCSI

->

Юнит тест LUN

Номер LUN

SCSI

<-

SCSI: Response LUN: 0xyy (Test Unit Ready)

статус LUN

SCSI

->

Запрос ёмкости LUN: размер и количество блоков

номер LUN

SCSI

<-

SCSI: Data In LUN: 0x01 (Read Capacity(10) Response Data)

размер и количество блоков LUN

SCSI

->

Запрос режимов

номер LUN

SCSI

<-

SCSI: Data In LUN: 0x01 (Mode Sense(6) Response Data)

Режимы LUN, в том числе read-only

SCSI

->

Чтение блока

номер LUN, номер блоков, количество блоков

SCSI

<-

SCSI: Read(10) LUN: 0x03 (LBA: 0x00000000, Len: 8)

Прочитанные данные

Таким образом, после запроса дискрипторов, запроса готовности LUN и запроса ёмкости, драйвером операционной системы производится чтение блоков: вычитывается таблица разделов (MBR или GPT), затем сами разделы для определения их параметров и файловой системы, а затем последние блоки из заявленной ёмкости.

Перейдём теперь к структуре библиотек ST:

Файл

Назначение

USB_DEVICE->App->usb_device.c

Функции инициализации USB, здесь можно описать композитные устройства или переключение устройств

USB_DEVICE->App->usbd_desk.c

Дескриптор устройства DEVICE DESCRIPTOR (VID/PID), информация о производителе. Структура USBD_FS_DeviceDescUSBD_FS_DeviceDesc

Middlewares->ST->STM32_USB_Device_Library->Class->MSC->Src->usbd_msc.c

Дескрипторы конфигурации, интерфейса и конечных точек MassStorage и функции инициализации USBD_MSC_CfgFSDesc

Middlewares->ST->STM32_USB_Device_Library->Class->MSC->Src->usbd_msc_bot.c

Функции интерфейса BOT

Middlewares->ST->STM32_USB_Device_Library->Class->MSC->Src->usbd_msc_data.c

Структуры ответов на некоторые команды SCSI, в частности на MODE_SENSE6 и MSC_Mode_Sense10

Middlewares->ST->STM32_USB_Device_Library->Class->MSC->Src->usbd_msc_scsi.c

Функции отправки и обработки SCSI команд интерфейса

USB_DEVICE->App->usbd_storage_if.с

Здесь мы описываем структуру LUN и функции взаимодействия с ними и с источниками данных

После того, как разобрались как всё работает и с чем будем иметь дело приступаем к починке.

1. Включаем больше 2 LUN

Исходя из специфики интерфейса BOT, максимальное количество поддерживаемых LUN равно 15 или 0x0f, видимо, больше бит жалко было, да и задач себе не представляю для микроконтроллера с 15-ю дисками, хотя... если очень хочется, можно сделать устройство композитным и навесить ещё 1 интерфейс со своими функциями обработки.

Драйверами операционных систем что Linux, что Windows, увидеть больше 8 LUN не получалось. Судя по анадизу трафика USB запрос GET MAX LUN больше 7 съедает, в логи драйвер не ругается, но 8-ое и более старшее устройство опросить даже не пытается...

Но библиотеки ST не идеальны и видимо не проходят должного тестирования функционала. Такое ощущение, что сидят студенты, проверят базовые функции и на этом заканчивают, убедившись, что раз работает - значит сойдет. Так и в нашем случае, протестировали с 1 LUN и успокоились на этом, при этом с 2-мя работает очень криво при равных размерах, а большем - вообще никак. Ну что же делать, остаётся нам править имеющееся, чтобы можно было пользоваться.

Тк у нас отсутствует отбработка SCSI команд для LUN, начиная с 2 и более, ищем функцию

static void  MSC_BOT_CBW_Decode(USBD_HandleTypeDef *pdev)

формирования SCSI команд Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_bot.c и видим ограничение номера LUN константой 1U! Правим, на максимальное, заданное нами количество LUN hmsc->max_lun:

@@ -255,7 +255,7 @@ static void  MSC_BOT_CBW_Decode(USBD_HandleTypeDef *pdev)
  
if ((USBD_LL_GetRxDataSize(pdev, MSC_EPOUT_ADDR) != USBD_BOT_CBW_LENGTH) ||
       (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE) ||
-      (hmsc->cbw.bLUN > 1U) || (hmsc->cbw.bCBLength < 1U) ||
+      (hmsc->cbw.bLUN > hmsc->max_lun) || (hmsc->cbw.bCBLength < 1U) ||
       (hmsc->cbw.bCBLength > 16U))
   {
  SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);

Но интерфейсом у нас ограничено максимальное количество 0x0f, поэтому ограничем максимально задаваемое количество LUN этим числом, добавив константу в файл Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h:

@@ -55,6 +55,7 @@ extern "C" {
 #define BOT_RESET                    0xFF
 #define USB_MSC_CONFIG_DESC_SIZ      32
 
+#define MSC_BOT_MAX_LUN              0x0F
 
 #define MSC_EPIN_ADDR                0x81U
 #define MSC_EPOUT_ADDR               0x01U
@@ -82,25 +83,31 @@ typedef struct _USBD_STORAGE

Ограничивать будем hmsc->max_lun, получаемое из CALLBACK

int8_t STORAGE_GetMaxLun_FS(void)
{
  /* USER CODE BEGIN 8 */
  return (STORAGE_LUNS - 1);
  /* USER CODE END 8 */
}

файла USB_DEVICE->App->usbd_storage_if.c

Ограничиваем результат вызова CALLBACK в файле Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc.c

@@ -390,6 +390,7 @@ uint8_t USBD_MSC_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
               ((req->bmRequest & 0x80U) == 0x80U))
           {
             hmsc->max_lun = (uint32_t)((USBD_StorageTypeDef *)pdev->pUserData)->GetMaxLun();
+            hmsc->max_lun = (hmsc->max_lun > MSC_BOT_MAX_LUN) ? MSC_BOT_MAX_LUN : hmsc->max_lun;
             (void)USBD_CtlSendData(pdev, (uint8_t *)&hmsc->max_lun, 1U);
           }
           else

После этого на хост стали приходить данне от всех 8 LUN, но радовться ещё рано, так как если размер LUN разный - блок больший минимального не вычитывается при перекрёстном опросе LUN.

2. Чиним использование нескольких LUN c разными размерами блоков и их количеством

Ошибка о вылете из адресного пространства номера блока исходит из функции проверки диапазона адресов

static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
                                     uint32_t blk_offset, uint32_t blk_nbr)
{
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;

  if (hmsc == NULL)
  {
    return -1;
  }

  if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr)
  {
    SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
    return -1;
  }

  return 0;
}

файла Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c. Внимательно присмотревшись, видим, что номер текущего блока сравнивается со считанным до этого количеством блоков hmsc->scsi_blk_nbr. Учитывая специфику протокола SCSI, хост не обязан перед каждой операцией запрашивать размер и количество блоков читаемого/записываемого LUN и, соответственно, там могут остаться параметры другого LUN, что мы и видим. Вот как считывается количество и размер блоков LUN на примере SCSI_ReadCapacity16, для SCSI_ReadCapacity10 аналогично:

static int8_t SCSI_ReadCapacity16(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
{
  UNUSED(params);
  uint8_t idx;
  int8_t ret;
  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;

  if (hmsc == NULL)
  {
    return -1;
  }

  ret = ((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size);

  if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED))
  {
    SCSI_SenseCode(pdev, lun, NOT_READY, MEDIUM_NOT_PRESENT);
    return -1;
  }

  hmsc->bot_data_length = ((uint32_t)params[10] << 24) |
                          ((uint32_t)params[11] << 16) |
                          ((uint32_t)params[12] <<  8) |
                          (uint32_t)params[13];

  for (idx = 0U; idx < hmsc->bot_data_length; idx++)
  {
    hmsc->bot_data[idx] = 0U;
  }

  hmsc->bot_data[4] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 24);
  hmsc->bot_data[5] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 16);
  hmsc->bot_data[6] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >>  8);
  hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_nbr - 1U);

  hmsc->bot_data[8] = (uint8_t)(hmsc->scsi_blk_size >>  24);
  hmsc->bot_data[9] = (uint8_t)(hmsc->scsi_blk_size >>  16);
  hmsc->bot_data[10] = (uint8_t)(hmsc->scsi_blk_size >>  8);
  hmsc->bot_data[11] = (uint8_t)(hmsc->scsi_blk_size);

  hmsc->bot_data_length = ((uint32_t)params[10] << 24) |
                          ((uint32_t)params[11] << 16) |
                          ((uint32_t)params[12] <<  8) |
                          (uint32_t)params[13];

  return 0;
}

Те видим, что проверка адресов будет проходить только по последнему результату! Как не трудно догадаться, для исправления нам необходимо, чтобы для каждого LUN все параметры сохранялись индивидуально, те массив. PS: Оптимальнее всего было-бы вообще выкинуть CALLBACK STORAGE_GetMaxLun_FS и сразу заполнить структуру параметрами всех LUN, но учитывая, неоптимальность всего остального, это капля в море, тк оптимизировать там надо многое...

Для быстрого испавления в файле Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc.h создадим вспомогательную струтуру USBD_LUN_BLK_HandleTypeDef и исправим существующую USBD_LUN_BLK_HandleTypeDef:

typedef struct
{
  uint32_t                 max_lun;
  uint32_t                 interface;
  uint8_t                  bot_state;
  uint8_t                  bot_status;
  uint32_t                 bot_data_length;
  uint8_t                  bot_data[MSC_MEDIA_PACKET];
  USBD_MSC_BOT_CBWTypeDef  cbw;
  USBD_MSC_BOT_CSWTypeDef  csw;

  USBD_SCSI_SenseTypeDef   scsi_sense [SENSE_LIST_DEEPTH];
  uint8_t                  scsi_sense_head;
  uint8_t                  scsi_sense_tail;
  uint8_t                  scsi_medium_state;

  uint16_t                 scsi_blk_size;
  uint32_t                 scsi_blk_nbr;

  uint32_t                 scsi_blk_addr;
  uint32_t                 scsi_blk_len;
}
USBD_MSC_BOT_HandleTypeDef;

Следующим образом:

typedef struct
{
	uint16_t	size;
	uint32_t	nbr;
	uint32_t	addr;
	uint32_t	len;
}
USBD_LUN_BLK_HandleTypeDef;

typedef struct
{
  uint32_t                    max_lun;
  uint32_t                    interface;
  uint8_t                     bot_state;
  uint8_t                     bot_status;
  uint32_t                    bot_data_length;
  uint8_t                     bot_data[MSC_MEDIA_PACKET];
  USBD_MSC_BOT_CBWTypeDef     cbw;
  USBD_MSC_BOT_CSWTypeDef     csw;

  USBD_SCSI_SenseTypeDef      scsi_sense [SENSE_LIST_DEEPTH];
  uint8_t                     scsi_sense_head;
  uint8_t                     scsi_sense_tail;
  uint8_t                     scsi_medium_state;

  USBD_LUN_BLK_HandleTypeDef  scsi_blk[MSC_BOT_MAX_LUN];

}
USBD_MSC_BOT_HandleTypeDef;

Затем, нам необходимо исправить обраработчики команд SCSI в файле Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c:

@@ -317,13 +317,14 @@ static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t
   UNUSED(params);
   int8_t ret;
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
 
   if (hmsc == NULL)
   {
     return -1;
   }
 
-  ret = ((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size);
+  ret = ((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hlun->nbr, &hlun->size);
 
   if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED))
   {
@@ -331,15 +332,15 @@ static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t
     return -1;
   }
 
-  hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 24);
-  hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 16);
-  hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >>  8);
-  hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1U);
+  hmsc->bot_data[0] = (uint8_t)((hlun->nbr - 1U) >> 24);
+  hmsc->bot_data[1] = (uint8_t)((hlun->nbr - 1U) >> 16);
+  hmsc->bot_data[2] = (uint8_t)((hlun->nbr - 1U) >>  8);
+  hmsc->bot_data[3] = (uint8_t)(hlun->nbr - 1U);
 
-  hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >>  24);
-  hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >>  16);
-  hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >>  8);
-  hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);
+  hmsc->bot_data[4] = (uint8_t)(hlun->size >>  24);
+  hmsc->bot_data[5] = (uint8_t)(hlun->size >>  16);
+  hmsc->bot_data[6] = (uint8_t)(hlun->size >>  8);
+  hmsc->bot_data[7] = (uint8_t)(hlun->size);
 
   hmsc->bot_data_length = 8U;
 
@@ -361,13 +362,14 @@ static int8_t SCSI_ReadCapacity16(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t
   uint8_t idx;
   int8_t ret;
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
 
   if (hmsc == NULL)
   {
     return -1;
   }
 
-  ret = ((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size);
+  ret = ((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hlun->nbr, &hlun->size);
 
   if ((ret != 0) || (hmsc->scsi_medium_state == SCSI_MEDIUM_EJECTED))
   {
@@ -385,15 +387,15 @@ static int8_t SCSI_ReadCapacity16(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t
     hmsc->bot_data[idx] = 0U;
   }
 
-  hmsc->bot_data[4] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 24);
-  hmsc->bot_data[5] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >> 16);
-  hmsc->bot_data[6] = (uint8_t)((hmsc->scsi_blk_nbr - 1U) >>  8);
-  hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_nbr - 1U);
+  hmsc->bot_data[4] = (uint8_t)((hlun->nbr - 1U) >> 24);
+  hmsc->bot_data[5] = (uint8_t)((hlun->nbr - 1U) >> 16);
+  hmsc->bot_data[6] = (uint8_t)((hlun->nbr - 1U) >>  8);
+  hmsc->bot_data[7] = (uint8_t)(hlun->nbr - 1U);
 
-  hmsc->bot_data[8] = (uint8_t)(hmsc->scsi_blk_size >>  24);
-  hmsc->bot_data[9] = (uint8_t)(hmsc->scsi_blk_size >>  16);
-  hmsc->bot_data[10] = (uint8_t)(hmsc->scsi_blk_size >>  8);
-  hmsc->bot_data[11] = (uint8_t)(hmsc->scsi_blk_size);
+  hmsc->bot_data[8] = (uint8_t)(hlun->size >>  24);
+  hmsc->bot_data[9] = (uint8_t)(hlun->size >>  16);
+  hmsc->bot_data[10] = (uint8_t)(hlun->size >>  8);
+  hmsc->bot_data[11] = (uint8_t)(hlun->size);
 
   hmsc->bot_data_length = ((uint32_t)params[10] << 24) |
                           ((uint32_t)params[11] << 16) |
@@ -472,6 +474,12 @@ static int8_t SCSI_ModeSense6(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *pa
   {
     return -1;
   }
+  
+  /* Check If media is write-protected */
+  if (((USBD_StorageTypeDef *)pdev->pUserData)->IsWriteProtected(lun) == 1)
+  {
+    MSC_Mode_Sense6_data[2] |= 0x80;
+  }
 
   if (params[4] <= len)
   {
@@ -502,6 +510,12 @@ static int8_t SCSI_ModeSense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *p
     return -1;
   }
 
+  /* Check If media is write-protected */
+  if (((USBD_StorageTypeDef *)pdev->pUserData)->IsWriteProtected(lun) == 1)
+  {
+    MSC_Mode_Sense6_data[2] |= 0x80;
+  }
+
   if (params[8] <= len)
   {
     len = params[8];
@@ -688,6 +702,7 @@ static int8_t SCSI_AllowPreventRemovable(USBD_HandleTypeDef *pdev, uint8_t lun,
 static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
 
   if (hmsc == NULL)
   {
@@ -716,21 +731,20 @@ static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params
       return -1;
     }
 
-    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
-                          ((uint32_t)params[3] << 16) |
-                          ((uint32_t)params[4] <<  8) |
-                          (uint32_t)params[5];
+    hlun->addr = ((uint32_t)params[2] << 24) |
+                 ((uint32_t)params[3] << 16) |
+                 ((uint32_t)params[4] <<  8) |
+                  (uint32_t)params[5];
 
-    hmsc->scsi_blk_len = ((uint32_t)params[7] <<  8) | (uint32_t)params[8];
+    hlun->len = ((uint32_t)params[7] <<  8) | (uint32_t)params[8];
 
-    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
-                               hmsc->scsi_blk_len) < 0)
+    if (SCSI_CheckAddressRange(pdev, lun, hlun->addr, hlun->len) < 0)
     {
       return -1; /* error */
     }
 
     /* cases 4,5 : Hi <> Dn */
-    if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size))
+    if (hmsc->cbw.dDataLength != (hlun->len * hlun->size))
     {
       SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
       return -1;
@@ -754,6 +768,7 @@ static int8_t SCSI_Read10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params
 static int8_t SCSI_Read12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
 
   if (hmsc == NULL)
   {
@@ -781,24 +796,23 @@ static int8_t SCSI_Read12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params
       return -1;
     }
 
-    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
-                          ((uint32_t)params[3] << 16) |
-                          ((uint32_t)params[4] <<  8) |
-                          (uint32_t)params[5];
+    hlun->addr = ((uint32_t)params[2] << 24) |
+                 ((uint32_t)params[3] << 16) |
+                 ((uint32_t)params[4] <<  8) |
+                  (uint32_t)params[5];
 
-    hmsc->scsi_blk_len = ((uint32_t)params[6] << 24) |
-                         ((uint32_t)params[7] << 16) |
-                         ((uint32_t)params[8] << 8) |
-                         (uint32_t)params[9];
+    hlun->len = ((uint32_t)params[6] << 24) |
+                ((uint32_t)params[7] << 16) |
+                ((uint32_t)params[8] << 8) |
+                 (uint32_t)params[9];
 
-    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
-                               hmsc->scsi_blk_len) < 0)
+    if (SCSI_CheckAddressRange(pdev, lun, hlun->addr, hlun->len) < 0)
     {
       return -1; /* error */
     }
 
     /* cases 4,5 : Hi <> Dn */
-    if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size))
+    if (hmsc->cbw.dDataLength != (hlun->len * hlun->size))
     {
       SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB);
       return -1;
@@ -822,6 +836,7 @@ static int8_t SCSI_Read12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params
 static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
   uint32_t len;
 
   if (hmsc == NULL)
@@ -858,22 +873,21 @@ static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *param
       return -1;
     }
 
-    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
-                          ((uint32_t)params[3] << 16) |
-                          ((uint32_t)params[4] << 8) |
-                          (uint32_t)params[5];
+    hlun->addr = ((uint32_t)params[2] << 24) |
+                 ((uint32_t)params[3] << 16) |
+                 ((uint32_t)params[4] << 8) |
+                  (uint32_t)params[5];
 
-    hmsc->scsi_blk_len = ((uint32_t)params[7] << 8) |
-                         (uint32_t)params[8];
+    hlun->len = ((uint32_t)params[7] << 8) |
+                 (uint32_t)params[8];
 
     /* check if LBA address is in the right range */
-    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
-                               hmsc->scsi_blk_len) < 0)
+    if (SCSI_CheckAddressRange(pdev, lun, hlun->addr, hlun->len) < 0)
     {
       return -1; /* error */
     }
 
-    len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
+    len = hlun->len * hlun->size;
 
     /* cases 3,11,13 : Hn,Ho <> D0 */
     if (hmsc->cbw.dDataLength != len)
@@ -907,6 +921,7 @@ static int8_t SCSI_Write10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *param
 static int8_t SCSI_Write12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
   uint32_t len;
 
   if (hmsc == NULL)
@@ -945,24 +960,23 @@ static int8_t SCSI_Write12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *param
       return -1;
     }
 
-    hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) |
-                          ((uint32_t)params[3] << 16) |
-                          ((uint32_t)params[4] << 8) |
-                          (uint32_t)params[5];
+    hlun->addr = ((uint32_t)params[2] << 24) |
+                 ((uint32_t)params[3] << 16) |
+                 ((uint32_t)params[4] << 8) |
+                  (uint32_t)params[5];
 
-    hmsc->scsi_blk_len = ((uint32_t)params[6] << 24) |
-                         ((uint32_t)params[7] << 16) |
-                         ((uint32_t)params[8] << 8) |
-                         (uint32_t)params[9];
+    hlun->len = ((uint32_t)params[6] << 24) |
+                ((uint32_t)params[7] << 16) |
+                ((uint32_t)params[8] << 8) |
+                 (uint32_t)params[9];
 
     /* check if LBA address is in the right range */
-    if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr,
-                               hmsc->scsi_blk_len) < 0)
+    if (SCSI_CheckAddressRange(pdev, lun, hlun->addr, hlun->len) < 0)
     {
       return -1; /* error */
     }
 
-    len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
+    len = hlun->len * hlun->size;
 
     /* cases 3,11,13 : Hn,Ho <> D0 */
     if (hmsc->cbw.dDataLength != len)
@@ -996,6 +1010,7 @@ static int8_t SCSI_Write12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *param
 static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
 
   if (hmsc == NULL)
   {
@@ -1008,7 +1023,7 @@ static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *para
     return -1; /* Error, Verify Mode Not supported*/
   }
 
-  if (SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr, hmsc->scsi_blk_len) < 0)
+  if (SCSI_CheckAddressRange(pdev, lun, hlun->addr, hlun->len) < 0)
   {
     return -1; /* error */
   }
@@ -1026,22 +1041,23 @@ static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *para
   * @param  blk_nbr: number of block to be processed
   * @retval status
   */
-static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
+__attribute__((optimize(0))) static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
                                      uint32_t blk_offset, uint32_t blk_nbr)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
-
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];

   if (hmsc == NULL)
   {
     return -1;
   }
 
-  if ((blk_offset + blk_nbr) > hmsc->scsi_blk_nbr)
+  if ((blk_offset + blk_nbr) > hlun->nbr)
   {
     SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
     return -1;
   }


   return 0;
 }
 
@@ -1054,7 +1070,8 @@ static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
 static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
-  uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
+  uint32_t len = hlun->len * hlun->size;
 
   if (hmsc == NULL)
   {
@@ -1064,8 +1081,8 @@ static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun)
   len = MIN(len, MSC_MEDIA_PACKET);
 
   if (((USBD_StorageTypeDef *)pdev->pUserData)->Read(lun, hmsc->bot_data,
-                                                     hmsc->scsi_blk_addr,
-                                                     (len / hmsc->scsi_blk_size)) < 0)
+		                                             hlun->addr,
+                                                     (len / hlun->size)) < 0)
   {
     SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR);
     return -1;
@@ -1073,13 +1090,13 @@ static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun)
 
   (void)USBD_LL_Transmit(pdev, MSC_EPIN_ADDR, hmsc->bot_data, len);
 
-  hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
-  hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
+  hlun->addr += (len / hlun->size);
+  hlun->len -= (len / hlun->size);
 
   /* case 6 : Hi = Di */
   hmsc->csw.dDataResidue -= len;
 
-  if (hmsc->scsi_blk_len == 0U)
+  if (hlun->len == 0U)
   {
     hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
   }
@@ -1096,7 +1113,8 @@ static int8_t SCSI_ProcessRead(USBD_HandleTypeDef *pdev, uint8_t lun)
 static int8_t SCSI_ProcessWrite(USBD_HandleTypeDef *pdev, uint8_t lun)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
-  uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
+  USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
+  uint32_t len = hlun->len * hlun->size;
 
   if (hmsc == NULL)
   {
@@ -1106,26 +1124,26 @@ static int8_t SCSI_ProcessWrite(USBD_HandleTypeDef *pdev, uint8_t lun)
   len = MIN(len, MSC_MEDIA_PACKET);
 
   if (((USBD_StorageTypeDef *)pdev->pUserData)->Write(lun, hmsc->bot_data,
-                                                      hmsc->scsi_blk_addr,
-                                                      (len / hmsc->scsi_blk_size)) < 0)
+		                                              hlun->addr,
+                                                      (len / hlun->size)) < 0)
   {
     SCSI_SenseCode(pdev, lun, HARDWARE_ERROR, WRITE_FAULT);
     return -1;
   }
 
-  hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
-  hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
+  hlun->addr += (len / hlun->size);
+  hlun->len -= (len / hlun->size);
 
   /* case 12 : Ho = Do */
   hmsc->csw.dDataResidue -= len;
 
-  if (hmsc->scsi_blk_len == 0U)
+  if (hlun->len == 0U)
   {
     MSC_BOT_SendCSW(pdev, USBD_CSW_CMD_PASSED);
   }
   else
   {
-    len = MIN((hmsc->scsi_blk_len * hmsc->scsi_blk_size), MSC_MEDIA_PACKET);
+    len = MIN((hlun->len * hlun->size), MSC_MEDIA_PACKET);
 
     /* Prepare EP to Receive next packet */
     (void)USBD_LL_PrepareReceive(pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);

3. Чиним SCSI Mode Sense и добавляем режим Read Only (Write Protect)

При первом знакомстве с ST библиотекой меня очень обрадовало наличие в USB_DEVICE->App->usbd_storage_if.с CALLBACK

int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);

Но по изучению кода оказалось, что он разве что пригоден для временного отключения записи возвратом USBD_FAIL, а запись включена USBD_OK, тк реализован проверкой результата на момент вызова SCSI Write. Хотелось бы видеть реализацию постоянного запрета на запись при инициализации устройства, о чём сообщает ядро следующим образом (при разрешённой записи):

sd 4:0:0:2: [sdd] Write Protect is off
sd 4:0:0:2: [sdd] Mode Sense: 22 0 0 0

За включение Write Protect отвечает SCSI запрос Mode Sense, возвращающий 4 байта в ответе по спецификации команд SCSI. Но писавшие библиотеку в ST явно чем-то мягким напрыгали на аж 23 байта, ибо 0x22 это длина пакета и это 34! На это пакет WireShark орёт благим матом, только и в лог ядра попадает часть этого безобразия. Ну что же, приводим это недоразумение в файле Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_data.c в соответствии со спецификацией:

/* USB Mass storage sense 6 Data */
uint8_t MSC_Mode_Sense6_data[MODE_SENSE6_LEN] =
{
  0x03,     /* MODE DATA LENGTH. The number of bytes that follow. */
  0x00,     /* MEDIUM TYPE. 00h for SBC devices. */
  0x00,     /* DEVICE-SPECIFIC PARAMETER. For SBC devices: 
             *   bit 7: WP. Set to 1 if the media is write-protected.
             *   bits 6..4: reserved
             *   bit 4: DPOFUA. Set to 1 if the device supports the DPO and FUA bits (used in caching)
             *   bits 3..0: reserved*/
  0x00      /* Put Product Serial number */
};


/* USB Mass storage sense 10  Data */
uint8_t MSC_Mode_Sense10_data[MODE_SENSE10_LEN] =
{
  0x07,     /* MODE DATA LENGTH. The number of bytes that follow. */
  0x00,     /* MEDIUM TYPE. 00h for SBC devices. */
  0x00,     /* DEVICE-SPECIFIC PARAMETER. For SBC devices: 
             *   bit 7: WP. Set to 1 if the media is write-protected.
             *   bits 6..4: reserved
             *   bit 4: DPOFUA. Set to 1 if the device supports the DPO and FUA bits (used in caching)
             *   bits 3..0: reserved*/
  0x00,     /* Reserved */
  0x00,     /* Reserved */
  0x00,     /* Reserved */
  0x00,     /* Reserved */
  0x00      /* BLOCK DESCRIPTOR LENGTH. The length in bytes of all block descriptors in the
             *   mode parameter list. */
};

Не забывая при этом исправить длину ответа в файле Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_data.h

@@ -40,8 +40,8 @@ extern "C" {
 /** @defgroup USB_INFO_Exported_Defines
   * @{
   */
-#define MODE_SENSE6_LEN                    0x17U
-#define MODE_SENSE10_LEN                   0x1BU
+#define MODE_SENSE6_LEN                    0x04U
+#define MODE_SENSE10_LEN                   0x08U
 #define LENGTH_INQUIRY_PAGE00              0x06U
 #define LENGTH_INQUIRY_PAGE80              0x08U

Этим мы успокоили WireShak, но мы же хотим сделать ReadOnly. Самый простой вариант и для всех дисков - задать по умочанию прямо в структуре, но он будет сразу для всех LUN. Для выбора задействуем рассмотренный выше CALLBACK STORAGE_IsWriteProtected_FS(uint8_t lun); , расширив его функциональность. Пусть теперь при возврате USBD_BUSY он делает диск WriteProtect на этапе инициализации. Для этого в файле Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c правим функции обработки SCSI команды SCSI_ModeSense 6 и 10:

@@ -472,6 +472,12 @@ static int8_t SCSI_ModeSense6(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *pa
   {
     return -1;
   }
+  
+  /* Check If media is write-protected */
+  if (((USBD_StorageTypeDef *)pdev->pUserData)->IsWriteProtected(lun) == 1)
+  {
+    MSC_Mode_Sense6_data[2] |= 0x80;
+  }
 
   if (params[4] <= len)
   {
@@ -502,6 +508,12 @@ static int8_t SCSI_ModeSense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *p
     return -1;
   }
 
+  /* Check If media is write-protected */
+  if (((USBD_StorageTypeDef *)pdev->pUserData)->IsWriteProtected(lun) == 1)
+  {
+    MSC_Mode_Sense6_data[2] |= 0x80;
+  }
+
   if (params[8] <= len)
   {
     len = params[8];

Теперь, при возрате CALLBACK

int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
  /* USER CODE BEGIN 5 */
  switch(lun){
  	  case LUN_NUM_MICROSD:
  		return (USBD_OK);
	  case LUN_NUM_EEPROM:
		return (USBD_BUSY);
		break;
	  case LUN_NUM_SYSTEM:
  	  	return (USBD_BUSY);
  	  	break;
  	  case LUN_NUM_TEST:
  	  	return (USBD_BUSY);
  	  	break;
  	  default:
		return (USBD_FAIL);
  }  
  /* USER CODE END 5 */
}

Поллучаем для:

LUN_NUM_MICROSD - Запись разрешена

LUN_NUM_EEPROM, LUN_NUM_SYSTEM, LUN_NUM_TEST - Запрещена полностью при инициализации диска системой

Для остальных - Запрещена проверкой в команде SCSI Write

В логе linux выглядит это следующим образом:

sd 4:0:0:0: [sdb] Write Protect is off
sd 4:0:0:0: [sdb] Mode Sense: 03 00 00 00

sd 4:0:0:1: [sdc] Write Protect is on
sd 4:0:0:1: [sdc] Mode Sense: 03 00 80 00

sd 4:0:0:2: [sdd] Write Protect is on
sd 4:0:0:2: [sdd] Mode Sense: 03 00 80 00

sd 4:0:0:3: [sde] Write Protect is on
sd 4:0:0:3: [sde] Mode Sense: 03 00 80 00

sd 4:0:0:4: [sdf] Write Protect is off
sd 4:0:0:4: [sdf] Mode Sense: 03 00 00 00

sd 4:0:0:5: [sdg] Write Protect is off
sd 4:0:0:5: [sdg] Mode Sense: 03 00 00 00

sd 4:0:0:7: [sdi] Write Protect is off
sd 4:0:0:7: [sdi] Mode Sense: 03 00 00 00

sd 4:0:0:6: [sdh] Write Protect is off
sd 4:0:0:6: [sdh] Mode Sense: 03 00 00 00

4. Чиним сброс устройства, добавлением недостающих SCSI команд

После всех предыдущих исправлений осталось единственное. Устройство вроде работает, но в логе сообщений ядра linux проскакивает строчка о сбросе устройства:

usb 1-1: reset full-speed USB device number 10 using xhci_hcd

А в WireShark виден сброс с перезапросом дескрипторов. Этому всегда предшествует некорректный ответ на неизвестные устройству команды. Для исправления этого добавим пустые, синтаксически правильные ответы на следующие команды: SCSI_REPORT_LUNS12, SCSI_LOG_SENSE10, SCSI_RECEIVE_DIAGNOSTIC8, SCSI_ATA_PASSTHROUGH12

Для SCSI_REPORT_LUNS12 добавим номер команды в файл Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_scsi.h:

@ -74,6 +74,8 @@ extern "C" {
 #define SCSI_SEND_DIAGNOSTIC                        0x1DU
 #define SCSI_READ_FORMAT_CAPACITIES                 0x23U
 
+#define SCSI_REPORT_LUNS12                          0xA0U
+

И её реализацию в файл Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c:

@@ -100,6 +100,9 @@ static int8_t SCSI_ProcessWrite(USBD_HandleTypeDef *pdev, uint8_t lun);
 
 static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc,
                                  uint8_t *pBuff, uint16_t length);
+
+static int8_t SCSI_ReportLuns12(USBD_HandleTypeDef *pdev, uint8_t lun,
+                                 uint8_t *params);
 /**
   * @}
   */
@@ -190,6 +193,10 @@ int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *cmd)
       ret = SCSI_Verify10(pdev, lun, cmd);
       break;
 
+    case SCSI_REPORT_LUNS12:
+      ret = SCSI_ReportLuns12(pdev, lun, cmd);
+      break;
+
     default:
       SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_CDB);
       hmsc->bot_status = USBD_BOT_STATUS_ERROR;
@@ -1041,12 +1048,12 @@ static int8_t SCSI_Verify10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *para
   * @param  blk_nbr: number of block to be processed
   * @retval status
   */
-__attribute__((optimize(0))) static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
+static int8_t SCSI_CheckAddressRange(USBD_HandleTypeDef *pdev, uint8_t lun,
                                      uint32_t blk_offset, uint32_t blk_nbr)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
   USBD_LUN_BLK_HandleTypeDef *hlun = &hmsc->scsi_blk[lun];
-/*
+
   if (hmsc == NULL)
   {
     return -1;
@@ -1057,7 +1064,7 @@ __attribute__((optimize(0))) static int8_t SCSI_CheckAddressRange(USBD_HandleTyp
     SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
     return -1;
   }
-*/
+
   return 0;
 }
 
@@ -1181,6 +1188,41 @@ static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc,
 
   return 0;
 }
+
+
+/**
+  * @brief  SCSI_Write12
+  *         Process Write12 command
+  * @param  lun: Logical unit number
+  * @param  params: Command parameters
+  * @retval status
+  */
+__attribute__((optimize(0))) static int8_t SCSI_ReportLuns12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+  USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
+
+  uint16_t lun_i;
+
+  static uint64_t report_luns[MSC_BOT_MAX_LUN + 1];
+
+  if (hmsc == NULL)
+  {
+    return -1;
+  }
+
+
+  report_luns[0] = 0;
+  ((uint8_t *)report_luns)[3] = sizeof(uint64_t)*(hmsc->max_lun + 1);
+
+  for (lun_i = 0; lun_i <= hmsc->max_lun; lun_i++){
+  	report_luns[lun_i + 1] = lun_i << 8;
+  }
+
+  (void)SCSI_UpdateBotData(hmsc, (uint8_t *)report_luns, sizeof(uint64_t)*(hmsc->max_lun + 2) );
+
+  return 0;
+}
+
 /**@@ -75,6 +75,7 @@ extern "C" {
 #define SCSI_READ_FORMAT_CAPACITIES                 0x23U
 
 #define SCSI_REPORT_LUNS12                          0xA0U
+#define SCSI_LOG_SENSE10                            0x4DU

Для SCSI_LOG_SENSE10 добавим номер команды в файл Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_scsi.h:

@@ -75,6 +75,7 @@ extern "C" {
 #define SCSI_READ_FORMAT_CAPACITIES                 0x23U
 
 #define SCSI_REPORT_LUNS12                          0xA0U
+#define SCSI_LOG_SENSE10                            0x4DU

И её реализацию в файл Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c:

@@ -103,6 +103,8 @@ static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc,
 
 static int8_t SCSI_ReportLuns12(USBD_HandleTypeDef *pdev, uint8_t lun,
                                  uint8_t *params);
+static int8_t SCSI_Log_Sense10(USBD_HandleTypeDef *pdev, uint8_t lun,
+								uint8_t *params);
 /**
   * @}
   */
@@ -197,6 +199,10 @@ int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *cmd)
       ret = SCSI_ReportLuns12(pdev, lun, cmd);
       break;
 
+    case SCSI_LOG_SENSE10:
+      ret = SCSI_Log_Sense10(pdev, lun, cmd);
SCSI_RECEIVE_DIAGNOSTIC8+      break;
+
     default:
       SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_CDB);
       hmsc->bot_status = USBD_BOT_STATUS_ERROR;
@@ -1197,7 +1203,7 @@ static int8_t SCSI_UpdateBotData(USBD_MSC_BOT_HandleTypeDef *hmsc,
   * @param  params: Command parameters
   * @retval status
   */
-__attribute__((optimize(0))) static int8_t SCSI_ReportLuns12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+static int8_t SCSI_ReportLuns12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
 
@@ -1223,6 +1229,31 @@ __attribute__((optimize(0))) static int8_t SCSI_ReportLuns12(USBD_HandleTypeDef
   return 0;
 }
 
+

Для SCSI_RECEIVE_DIAGNOSTIC8, SCSI_ATA_PASSTHROUGH12 добавим номер команды в файл Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Inc/usbd_msc_scsi.h:

@@ -76,6 +76,8 @@ extern "C" {
 
 #define SCSI_REPORT_LUNS12                          0xA0U
 #define SCSI_LOG_SENSE10                            0x4DU
+#define SCSI_RECEIVE_DIAGNOSTIC8                    0x1CU
+#define SCSI_ATA_PASSTHROUGH12                      0xA1U

И их реализацию в файл Middlewares/ST/STM32_USB_Device_Library/Class/MSC/Src/usbd_msc_scsi.c:

@@ -105,6 +105,11 @@ static int8_t SCSI_ReportLuns12(USBD_HandleTypeDef *pdev, uint8_t lun,
                                  uint8_t *params);
 static int8_t SCSI_Log_Sense10(USBD_HandleTypeDef *pdev, uint8_t lun,
 								uint8_t *params);
+static int8_t SCSI_Recive_Diagnostic8(USBD_HandleTypeDef *pdev, uint8_t lun,
+								uint8_t *params);
+static int8_t SCSI_Ata_PassThrough12(USBD_HandleTypeDef *pdev, uint8_t lun,
+								uint8_t *params);
+
 /**
   * @}
   */
@@ -203,6 +208,14 @@ int8_t SCSI_ProcessCmd(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *cmd)
       ret = SCSI_Log_Sense10(pdev, lun, cmd);
       break;
 
+    case SCSI_RECEIVE_DIAGNOSTIC8:
+      ret = SCSI_Recive_Diagnostic8(pdev, lun, cmd);
+      break;
+
+    case SCSI_ATA_PASSTHROUGH12:
+      ret = SCSI_Ata_PassThrough12(pdev, lun, cmd);
+      break;
+
     default:
       SCSI_SenseCode(pdev, lun, ILLEGAL_REQUEST, INVALID_CDB);
       hmsc->bot_status = USBD_BOT_STATUS_ERROR;
@@ -1238,7 +1251,7 @@ static int8_t SCSI_ReportLuns12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *
   * @param  params: Command parameters
   * @retval status
   */
-__attribute__((optimize(0))) static int8_t SCSI_Log_Sense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+static int8_t SCSI_Log_Sense10(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
 {
   USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef *)pdev->pClassData;
 
@@ -1254,6 +1267,37 @@ __attribute__((optimize(0))) static int8_t SCSI_Log_Sense10(USBD_HandleTypeDef *
   return 0;
 }
 
+
+
+/**
+  * @brief  SCSI_Write12
+  *         Process Write12 command
+  * @param  lun: Logical unit number
+  * @param  params: Command parameters
+  * @retval status
+  */
+static int8_t SCSI_Recive_Diagnostic8(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+
+  return SCSI_Log_Sense10(pdev, lun, params);
+}
+
+
+
+/**
+  * @brief  SCSI_Write12
+  *         Process Write12 command
+  * @param  lun: Logical unit number
+  * @param  params: Command parameters
+  * @retval status
+  */
+static int8_t SCSI_Ata_PassThrough12(USBD_HandleTypeDef *pdev, uint8_t lun, uint8_t *params)
+{
+
+  return SCSI_Log_Sense10(pdev, lun, params);
+}
+
+
 /**

После всего проделанного видим красивый лог и радуемся корректно работающему устройству:

Log ядра
kernel: [15712.126112] usb 1-1: new full-speed USB device number 73 using xhci_hcd     
kernel: [15712.277413] usb 1-1: New USB device found, idVendor=0483, idProduct=572a, bcdDevice= 2.00     
kernel: [15712.277419] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3      
kernel: [15712.277420] usb 1-1: Product: Test MASS Storage         
kernel: [15712.277421] usb 1-1: Manufacturer: Developer           
kernel: [15712.277422] usb 1-1: SerialNumber: 2062369C5950           
kernel: [15712.279576] usb-storage 1-1:1.0: USB Mass Storage device detected        
kernel: [15712.279965] scsi host4: usb-storage 1-1:1.0           
mtp-probe: checking bus 1 device 73:00:00 /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1          
mtp-probe: bus: 1 device: 73 was not an MTP device       
mtp-probe: checking bus 1 device 73:00:00 /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1          
mtp-probe: bus: 1 device: 73 was not an MTP device       
kernel: [15713.287207] scsi 4:0:0:0: Direct-Access STM MicroSD Device 0.01 PQ: 0 ANSI: 2    
kernel: [15713.287882] scsi 4:0:0:1: Direct-Access STM EEPROM 0.01 PQ: 0 ANSI: 2     
kernel: [15713.288253] scsi 4:0:0:2: Direct-Access STM System 0.01 PQ: 0 ANSI: 2     
kernel: [15713.288611] scsi 4:0:0:3: Direct-Access STM Test 0.01 PQ: 0 ANSI: 2     
kernel: [15713.288991] scsi 4:0:0:4: Direct-Access STM MicroSD2Device 0.01 PQ: 0 ANSI: 2     
kernel: [15713.289293] scsi 4:0:0:5: Direct-Access STM EEPROM2 0.01 PQ: 0 ANSI: 2     
kernel: [15713.289593] scsi 4:0:0:6: Direct-Access STM System2 0.01 PQ: 0 ANSI: 2     
kernel: [15713.290194] scsi 4:0:0:7: Direct-Access STM Test2 0.01 PQ: 0 ANSI: 2     
kernel: [15713.290496] sd 4:0:0:0: Attached scsi generic sg1 type 0       
kernel: [15713.290708] sd 4:0:0:1: Attached scsi generic sg2 type 0       
kernel: [15713.290748] sd 4:0:0:0: [sdb] 1030144 512-byte logical blocks: (527 MB/503 MiB)     
kernel: [15713.290937] sd 4:0:0:0: [sdb] Write Protect is on        
kernel: [15713.290939] sd 4:0:0:2: Attached scsi generic sg3 type 0       
kernel: [15713.290939] sd 4:0:0:0: [sdb] Mode Sense: 3 0 80 0      
kernel: [15713.291048] sd 4:0:0:3: Attached scsi generic sg4 type 0       
kernel: [15713.291117] scsi 4:0:0:4: Attached scsi generic sg5 type 0       
kernel: [15713.291147] sd 4:0:0:0: [sdb] No Caching mode page found       
kernel: [15713.291149] sd 4:0:0:0: [sdb] Assuming drive cache: write through       
kernel: [15713.291194] sd 4:0:0:5: Attached scsi generic sg6kernel: [15712.126112] usb 1-1: new full-speed USB device number 73 using xhci_hcd     
kernel: [15712.277413] usb 1-1: New USB device found, idVendor=0483, idProduct=572a, bcdDevice= 2.00     
kernel: [15712.277419] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3      
kernel: [15712.277420] usb 1-1: Product: Test MASS Storage         
kernel: [15712.277421] usb 1-1: Manufacturer: Developer           
kernel: [15712.277422] usb 1-1: SerialNumber: 2062369C5950           
kernel: [15712.279576] usb-storage 1-1:1.0: USB Mass Storage device detected        
kernel: [15712.279965] scsi host4: usb-storage 1-1:1.0           
mtp-probe: checking bus 1 device 73:00:00 /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1          
mtp-probe: bus: 1 device: 73 was not an MTP device       
mtp-probe: checking bus 1 device 73:00:00 /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1          
mtp-probe: bus: 1 device: 73 was not an MTP device       
kernel: [15713.287207] scsi 4:0:0:0: Direct-Access STM MicroSD Device 0.01 PQ: 0 ANSI: 2    
kernel: [15713.287882] scsi 4:0:0:1: Direct-Access STM EEPROM 0.01 PQ: 0 ANSI: 2     
kernel: [15713.288253] scsi 4:0:0:2: Direct-Access STM System 0.01 PQ: 0 ANSI: 2     
kernel: [15713.288611] scsi 4:0:0:3: Direct-Access STM Test 0.01 PQ: 0 ANSI: 2     
kernel: [15713.288991] scsi 4:0:0:4: Direct-Access STM MicroSD2Device 0.01 PQ: 0 ANSI: 2     
kernel: [15713.289293] scsi 4:0:0:5: Direct-Access STM EEPROM2 0.01 PQ: 0 ANSI: 2     
kernel: [15713.289593] scsi 4:0:0:6: Direct-Access STM System2 0.01 PQ: 0 ANSI: 2     
kernel: [15713.290194] scsi 4:0:0:7: Direct-Access STM Test2 0.01 PQ: 0 ANSI: 2     
kernel: [15713.290496] sd 4:0:0:0: Attached scsi generic sg1 type 0       
kernel: [15713.290708] sd 4:0:0:1: Attached scsi generic sg2 type 0       
kernel: [15713.290748] sd 4:0:0:0: [sdb] 1030144 512-byte logical blocks: (527 MB/503 MiB)     
kernel: [15713.290937] sd 4:0:0:0: [sdb] Write Protect is on        
kernel: [15713.290939] sd 4:0:0:2: Attached scsi generic sg3 type 0       
kernel: [15713.290939] sd 4:0:0:0: [sdb] Mode Sense: 3 0 80 0      
kernel: [15713.291048] sd 4:0:0:3: Attached scsi generic sg4 type 0       
kernel: [15713.291117] scsi 4:0:0:4: Attached scsi generic sg5 type 0       
kernel: [15713.291147] sd 4:0:0:0: [sdb] No Caching mode page found       
kernel: [15713.291149] sd 4:0:0:0: [sdb] Assuming drive cache: write through       
kernel: [15713.291194] sd 4:0:0:5: Attached scsi generic sg6 type 0       
kernel: [15713.291274] sd 4:0:0:6: Attached scsi generic sg7 type 0       
kernel: [15713.291334] scsi 4:0:0:7: Attached scsi generic sg8 type 0       
kernel: [15713.291486] sd 4:0:0:1: [sdc] 64 512-byte logical blocks: (32.8 kB/32.0 KiB)     
kernel: [15713.291777] sd 4:0:0:2: [sdd] 256 512-byte logical blocks: (131 kB/128 KiB)     
kernel: [15713.291913] sd 4:0:0:1: [sdc] Write Protect is on        
kernel: [15713.291915] sd 4:0:0:1: [sdc] Mode Sense: 3 0 80 0      
kernel: [15713.292154] sd 4:0:0:3: [sde] 1024 512-byte logical blocks: (524 kB/512 KiB)     
kernel: [15713.292299] sd 4:0:0:2: [sdd] Write Protect is on        
kernel: [15713.292302] sd 4:0:0:2: [sdd] Mode Sense: 3 0 80 0      
kernel: [15713.292444] sd 4:0:0:1: [sdc] No Caching mode page found       
kernel: [15713.292446] sd 4:0:0:1: [sdc] Assuming drive cache: write through       
kernel: [15713.292792] sd 4:0:0:4: [sdf] 2048 512-byte logical blocks: (1.05 MB/1.00 MiB)     
kernel: [15713.292934] sd 4:0:0:3: [sde] Write Protect is on        
kernel: [15713.292936] sd 4:0:0:3: [sde] Mode Sense: 3 0 80 0      
kernel: [15713.293081] sd 4:0:0:2: [sdd] No Caching mode page found       
kernel: [15713.293084] sd 4:0:0:2: [sdd] Assuming drive cache: write through       
kernel: [15713.293338] sd 4:0:0:5: [sdg] 4096 512-byte logical blocks: (2.10 MB/2.00 MiB)     
kernel: [15713.293483] sd 4:0:0:4: [sdf] Write Protect is on        
kernel: [15713.293486] sd 4:0:0:4: [sdf] Mode Sense: 3 0 80 0      
kernel: [15713.293642] sd 4:0:0:4: [sdf] No Caching mode page found       
kernel: [15713.293644] sd 4:0:0:4: [sdf] Assuming drive cache: write through       
kernel: [15713.293794] sd 4:0:0:3: [sde] No Caching mode page found       
kernel: [15713.293796] sd 4:0:0:3: [sde] Assuming drive cache: write through       
kernel: [15713.294146] sd 4:0:0:6: [sdh] 8192 512-byte logical blocks: (4.19 MB/4.00 MiB)     
kernel: [15713.294482] sd 4:0:0:5: [sdg] Write Protect is on        
kernel: [15713.294485] sd 4:0:0:5: [sdg] Mode Sense: 3 0 80 0      
kernel: [15713.297058] sd 4:0:0:7: [sdi] 16384 512-byte logical blocks: (8.39 MB/8.00 MiB)     
kernel: [15713.297215] sd 4:0:0:7: [sdi] Write Protect is on        
kernel: [15713.297218] sd 4:0:0:7: [sdi] Mode Sense: 3 0 80 0      
kernel: [15713.297374] sd 4:0:0:7: [sdi] No Caching mode page found       
kernel: [15713.297376] sd 4:0:0:7: [sdi] Assuming drive cache: write through       
kernel: [15713.297550] sd 4:0:0:5: [sdg] No Caching mode page found       
kernel: [15713.297553] sd 4:0:0:5: [sdg] Assuming drive cache: write through       
kernel: [15713.297788] sd 4:0:0:6: [sdh] Write Protect is on        
kernel: [15713.297790] sd 4:0:0:6: [sdh] Mode Sense: 3 0 80 0      
kernel: [15713.297972] sd 4:0:0:6: [sdh] No Caching mode page found       
kernel: [15713.297974] sd 4:0:0:6: [sdh] Assuming drive cache: write through       
kernel: [15713.318373] sdb: sdb1 sdb2 sdb3           
kernel: [15713.400473] sd 4:0:0:0: [sdb] Attached SCSI disk         
kernel: [15713.461585] sd 4:0:0:2: [sdd] Attached SCSI disk         
kernel: [15713.462133] sd 4:0:0:6: [sdh] Attached SCSI disk         
kernel: [15713.463092] sd 4:0:0:7: [sdi] Attached SCSI disk         
kernel: [15713.486541] sd 4:0:0:3: [sde] Attached SCSI disk         
kernel: [15713.494895] sd 4:0:0:4: [sdf] Attached SCSI disk         
kernel: [15713.501634] sd 4:0:0:1: [sdc] Attached SCSI disk         
kernel: [15713.537123] sd 4:0:0:5: [sdg] Attached SCSI disk         
systemd[1]: Finished Clean the /media/user/REC_ROM mount point.          
udisksd[1611]: Mounted /dev/sdb2 at /media/user/REC_ROM on behalf of uid 1001       
systemd[1788]: Starting Tracker metadata database store and lookup manager... 
dbus-daemon[1810]: [session uid=1001 pid=1810] Successfully activated service 'org.freedesktop.Tracker1' 
systemd[1788]: Started Tracker metadata database store and lookup manager. 
systemd[1]: Finished Clean the /media/user/LAST_ROMS mount point. 
udisksd[1611]: Mounted /dev/sdb3 at /media/user/LAST_ROMS on behalf of uid 1001  type 0       
kernel: [15713.291274] sd 4:0:0:6: Attached scsi generic sg7 type 0       
kernel: [15713.291334] scsi 4:0:0:7: Attached scsi generic sg8 type 0       
kernel: [15713.291486] sd 4:0:0:1: [sdc] 64 512-byte logical blocks: (32.8 kB/32.0 KiB)     
kernel: [15713.291777] sd 4:0:0:2: [sdd] 256 512-byte logical blocks: (131 kB/128 KiB)     
kernel: [15713.291913] sd 4:0:0:1: [sdc] Write Protect is on        
kernel: [15713.291915] sd 4:0:0:1: [sdc] Mode Sense: 3 0 80 0      
kernel: [15713.292154] sd 4:0:0:3: [sde] 1024 512-byte logical blocks: (524 kB/512 KiB)     
kernel: [15713.292299] sd 4:0:0:2: [sdd] Write Protect is on        
kernel: [15713.292302] sd 4:0:0:2: [sdd] Mode Sense: 3 0 80 0      
kernel: [15713.292444] sd 4:0:0:1: [sdc] No Caching mode page found       
kernel: [15713.292446] sd 4:0:0:1: [sdc] Assuming drive cache: write through       
kernel: [15713.292792] sd 4:0:0:4: [sdf] 2048 512-byte logical blocks: (1.05 MB/1.00 MiB)     
kernel: [15713.292934] sd 4:0:0:3: [sde] Write Protect is on        
kernel: [15713.292936] sd 4:0:0:3: [sde] Mode Sense: 3 0 80 0      
kernel: [15713.293081] sd 4:0:0:2: [sdd] No Caching mode page found       
kernel: [15713.293084] sd 4:0:0:2: [sdd] Assuming drive cache: write through       
kernel: [15713.293338] sd 4:0:0:5: [sdg] 4096 512-byte logical blocks: (2.10 MB/2.00 MiB)     
kernel: [15713.293483] sd 4:0:0:4: [sdf] Write Protect is on        
kernel: [15713.293486] sd 4:0:0:4: [sdf] Mode Sense: 3 0 80 0      
kernel: [15713.293642] sd 4:0:0:4: [sdf] No Caching mode page found       
kernel: [15713.293644] sd 4:0:0:4: [sdf] Assuming drive cache: write through       
kernel: [15713.293794] sd 4:0:0:3: [sde] No Caching mode page found       
kernel: [15713.293796] sd 4:0:0:3: [sde] Assuming drive cache: write through       
kernel: [15713.294146] sd 4:0:0:6: [sdh] 8192 512-byte logical blocks: (4.19 MB/4.00 MiB)     
kernel: [15713.294482] sd 4:0:0:5: [sdg] Write Protect is on        
kernel: [15713.294485] sd 4:0:0:5: [sdg] Mode Sense: 3 0 80 0      
kernel: [15713.297058] sd 4:0:0:7: [sdi] 16384 512-byte logical blocks: (8.39 MB/8.00 MiB)     
kernel: [15713.297215] sd 4:0:0:7: [sdi] Write Protect is on        
kernel: [15713.297218] sd 4:0:0:7: [sdi] Mode Sense: 3 0 80 0      
kernel: [15713.297374] sd 4:0:0:7: [sdi] No Caching mode page found       
kernel: [15713.297376] sd 4:0:0:7: [sdi] Assuming drive cache: write through       
kernel: [15713.297550] sd 4:0:0:5: [sdg] No Caching mode page found       
kernel: [15713.297553] sd 4:0:0:5: [sdg] Assuming drive cache: write through       
kernel: [15713.297788] sd 4:0:0:6: [sdh] Write Protect is on        
kernel: [15713.297790] sd 4:0:0:6: [sdh] Mode Sense: 3 0 80 0      
kernel: [15713.297972] sd 4:0:0:6: [sdh] No Caching mode page found       
kernel: [15713.297974] sd 4:0:0:6: [sdh] Assuming drive cache: write through       
kernel: [15713.318373] sdb: sdb1 sdb2 sdb3           
kernel: [15713.400473] sd 4:0:0:0: [sdb] Attached SCSI disk         
kernel: [15713.461585] sd 4:0:0:2: [sdd] Attached SCSI disk         
kernel: [15713.462133] sd 4:0:0:6: [sdh] Attached SCSI disk         
kernel: [15713.463092] sd 4:0:0:7: [sdi] Attached SCSI disk         
kernel: [15713.486541] sd 4:0:0:3: [sde] Attached SCSI disk         
kernel: [15713.494895] sd 4:0:0:4: [sdf] Attached SCSI disk         
kernel: [15713.501634] sd 4:0:0:1: [sdc] Attached SCSI disk         
kernel: [15713.537123] sd 4:0:0:5: [sdg] Attached SCSI disk         
systemd[1]: Finished Clean the /media/user/REC_ROM mount point.          
udisksd[1611]: Mounted /dev/sdb2 at /media/user/REC_ROM on behalf of uid 1001       
systemd[1788]: Starting Tracker metadata database store and lookup manager... 
dbus-daemon[1810]: [session uid=1001 pid=1810] Successfully activated service 'org.freedesktop.Tracker1' 
systemd[1788]: Started Tracker metadata database store and lookup manager. 
systemd[1]: Finished Clean the /media/user/LAST_ROMS mount point. 
udisksd[1611]: Mounted /dev/sdb3 at /media/user/LAST_ROMS on behalf of uid 1001 
Позапрашиваем информацию о LUN

Выведем все SCSI устройства:

# sg_map -x
/dev/sg0  0 0 0 0  0  /dev/sda
/dev/sg1  4 0 0 0  0  /dev/sdb
/dev/sg2  4 0 0 1  0  /dev/sdc
/dev/sg3  4 0 0 2  0  /dev/sdd
/dev/sg4  4 0 0 3  0  /dev/sde
/dev/sg5  4 0 0 4  0  /dev/sdf
/dev/sg6  4 0 0 5  0  /dev/sdg
/dev/sg7  4 0 0 6  0  /dev/sdh
/dev/sg8  4 0 0 7  0  /dev/sdi

Запросим ёмкость:

# sg_readcap /dev/sg1
Read Capacity results:
   Last LBA=1030143 (0xfb7ff), Number of logical blocks=1030144
   Logical block length=512 bytes
Hence:
   Device size: 527433728 bytes, 503.0 MiB, 0.53 GB

# sg_readcap /dev/sg2
Read Capacity results:
   Last LBA=63 (0x3f), Number of logical blocks=64
   Logical block length=512 bytes
Hence:
   Device size: 32768 bytes, 0.0 MiB, 0.00 GB

# sg_readcap /dev/sg3
Read Capacity results:
   Last LBA=255 (0xff), Number of logical blocks=256
   Logical block length=512 bytes
Hence:
   Device size: 131072 bytes, 0.1 MiB, 0.00 GB

# sg_readcap /dev/sg4
Read Capacity results:
   Last LBA=1023 (0x3ff), Number of logical blocks=1024
   Logical block length=512 bytes
Hence:
   Device size: 524288 bytes, 0.5 MiB, 0.00 GB

# sg_readcap /dev/sg5
Read Capacity results:
   Last LBA=2047 (0x7ff), Number of logical blocks=2048
   Logical block length=512 bytes
Hence:
   Device size: 1048576 bytes, 1.0 MiB, 0.00 GB

# sg_readcap /dev/sg6
Read Capacity results:
   Last LBA=4095 (0xfff), Number of logical blocks=4096
   Logical block length=512 bytes
Hence:
   Device size: 2097152 bytes, 2.0 MiB, 0.00 GB

# sg_readcap /dev/sg7
Read Capacity results:
   Last LBA=8191 (0x1fff), Number of logical blocks=8192
   Logical block length=512 bytes
Hence:
   Device size: 4194304 bytes, 4.0 MiB, 0.00 GB

# sg_readcap /dev/sg8
Read Capacity results:
   Last LBA=16383 (0x3fff), Number of logical blocks=16384
   Logical block length=512 bytes
Hence:
   Device size: 8388608 bytes, 8.0 MiB, 0.01 GB

Прочитаем метки:

# sg_raw -r 1k /dev/sg1 12 00 00 00 60 00
SCSI Status: Good

Received 36 bytes of data:
 00     00 00 02 02 1f 00 00 00  53 54 4d 20 20 20 20 20    ........STM
 10     4d 69 63 72 6f 53 44 20  44 65 76 69 63 65 20 20    MicroSD Device
 20     30 2e 30 31                                         0.01

# sg_raw -r 1k /dev/sg2 12 00 00 00 60 00
SCSI Status: Good

Received 36 bytes of data:
 00     00 00 02 02 1f 00 00 00  53 54 4d 20 20 20 20 20    ........STM
 10     45 45 50 52 4f 4d 20 20  20 20 20 20 20 20 20 20    EEPROM
 20     30 2e 30 31                                         0.01

# sg_raw -r 1k /dev/sg3 12 00 00 00 60 00
SCSI Status: Good

Received 36 bytes of data:
 00     00 00 02 02 1f 00 00 00  53 54 4d 20 20 20 20 20    ........STM
 10     53 79 73 74 65 6d 20 20  20 20 20 20 20 20 20 20    System
 20     30 2e 30 31                                         0.01

# sg_raw -r 1k /dev/sg4 12 00 00 00 60 00
SCSI Status: Good

Received 36 bytes of data:
 00     00 00 02 02 1f 00 00 00  53 54 4d 20 20 20 20 20    ........STM
 10     54 65 73 74 20 20 20 20  20 20 20 20 20 20 20 20    Test
 20     30 2e 30 31

Выведем списком все LUN в узле:

# sg_luns /dev/sg3
Lun list length = 64 which imples 8 lun entries
Report luns [select_report=0x0]:
    0000000000000000
    0001000000000000
    0002000000000000
    0003000000000000
    0004000000000000
    0005000000000000
    0006000000000000
    0007000000000000

Запросим логи LUN:

# sg_logs /dev/sg1
    STM       MicroSD Device    0.01

# sg_logs /dev/sg2
    STM       EEPROM            0.01

# sg_logs /dev/sg3
    STM       System            0.01

# sg_logs /dev/sg4
    STM       Test              0.01

# sg_logs /dev/sg5
    STM       MicroSD2Device    0.01

# sg_logs /dev/sg6
    STM       EEPROM2           0.01

# sg_logs /dev/sg7
    STM       System2           0.01

# sg_logs /dev/sg8
    STM       Test2             0.01

Почитаем данные:

#xxd -l   0x200  -s 0x200  /dev/sdb
00000200: ebfe 904d 5344 4f53 352e 3000 0201 0100  ...MSDOS5.0.....
00000210: 0140 0010 02f8 0200 3f00 ff00 0100 0000  .@......?.......
00000220: 0000 0000 8001 29ba 97e1 524e 4f20 4e41  ......)...RNO NA
00000230: 4d45 2020 2020 4641 5420 2020 2020 0000  ME    FAT     ..
00000240: 0000 0000 0000 0000 0000 0000 0000 0000  ................
...................................................................
000003e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000003f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.


#xxd -l   0x100  -s 0x800  /dev/sdc
00000800: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f  ................
00000810: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f  ................
00000820: 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f   !"#$%&'()*+,-./
00000830: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f  0123456789:;<=>?
00000840: 4041 4243 4445 4647 4849 4a4b 4c4d 4e4f  @ABCDEFGHIJKLMNO
00000850: 5051 5253 5455 5657 5859 5a5b 5c5d 5e5f  PQRSTUVWXYZ[]^_
00000860: 6061 6263 6465 6667 6869 6a6b 6c6d 6e6f  `abcdefghijklmno
00000870: 7071 7273 7475 7677 7879 7a7b 7c7d 7e7f  pqrstuvwxyz{|}~.
00000880: 8081 8283 8485 8687 8889 8a8b 8c8d 8e8f  ................
00000890: 9091 9293 9495 9697 9899 9a9b 9c9d 9e9f  ................
000008a0: a0a1 a2a3 a4a5 a6a7 a8a9 aaab acad aeaf  ................
000008b0: b0b1 b2b3 b4b5 b6b7 b8b9 babb bcbd bebf  ................
000008c0: c0c1 c2c3 c4c5 c6c7 c8c9 cacb cccd cecf  ................
000008d0: d0d1 d2d3 d4d5 d6d7 d8d9 dadb dcdd dedf  ................
000008e0: e0e1 e2e3 e4e5 e6e7 e8e9 eaeb eced eeef  ................
000008f0: f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff  ................

# xxd -l   0x20  -s 0x800  /dev/sdd
00000800: 0404 0404 0404 0404 0404 0404 0404 0404  ................
00000810: 0404 0404 0404 0404 0404 0404 0404 0404  ................

Интеграция с CubeMX / CubeIDE

Если после всех исправлений, попытаться перегенерировать проек кубом, то все правки, за исключением USB_DEVICE->*** будут откатаны к оригинальной библиотеке. Чтобы этого не происходило и при создании новых проектов брались уже испавленные версии, необходимо заменить файлы не только в локальной копии, но и в репозитории библиотек, откуда их берёт Cube. В Linux это папка ~/STM32Cube/Repository/STM32Cube_FW_L4_V1.17.0/Middlewares/ST/STM32_USB_Device_Library/Class/MSC.

И на последок исправленная библиотека на GitHub: https://github.com/Igorbunow/STM32CubeL4/tree/testing ветка testing!!!

По обнаруженным ошибкам сделан Pull Request в официальный репозиторий ST, надеюсь через какое-то время они поправят у себя для всех веток контроллера, а не только L4. Для остальных семейств не смотрел, но отличия в правках должны быть минимальны

Используемые материалы:

[1] Jan Axelson USB Mass Storage Designing and Programming Devices and Embedded Hosts

[2] Microchip AN2554 https://www.microchip.com/content/dam/mchp/documents/OTH/ApplicationNotes/ApplicationNotes/00002554A.pdf

[3] Microchip AN1169 http://www.t-es-t.hu/download/microchip/an1169a.pdf

[4] ST UM1717, UM0424, UM1021, UM1720

[5] Universal Serial Bus Mass Storage Class Bulk-Only Transport https://www.usb.org/sites/default/files/usbmassbulk_10.pdf

[6] SCSI Commands Reference Manual Seagate https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf

[7] https://habr.com/ru/post/549016/

[8] https://habr.com/ru/post/335018/

[9] https://habr.com/ru/post/336968/

Автор: Игорь

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js