‮Сдвиг по фазе (kincajou) wrote,
‮Сдвиг по фазе
kincajou

Categories:

worklog: двигатель как настоящий, только не работает

В общем, проблема с поддержкой Logical Unit Number остаётся загадкой.
Во-первых, отметаю возражения: поддержка нескольких LUN - стандартная фича SCSI и она реализована во всех версиях драйвера usbstor.sys, начиная с Windows 2000 SP3 и далее везде.

Стандартом предусмотрен 4-битный номер, то есть на одном канале может быть до 16 устройств. Стандартный запрос USB UFI, позволяющий узнать старший номер (но он не обязательно равен количеству!) LUN - GetMaxLun - подразумевает, что будет возвращён байт с этим самым номером. Т.е. если ЛУНов один, то будет возвращён нуль (отсчёт ведётся с нуля), если их два - возвращается 1 и так далее. При этом, если какие-то из ЛУНов не связаны с устройством (скажем, это многодисковый рэк и один из дисков из него вынут), то это можно узнать при помощи стандартной команды INQUIRY.

Процесс конфигурирования выглядит так:
1) энумерация и запрос дескрипторов по стандартной для любого USB-устройства схеме
2) установка конфигурации
3) включение интерфейса
4) стандартные запросы, соответствующие указанному в конфиге классу/подклассу/протоколу (это уже задача драйвера)
5) GetMaxLun
6) INQUIRY page00/LUN0, в ответ возвращается список поддерживаемых страниц, среди которых есть обязательные - mandatory - и опциональные
7) INQUIRY page80/LUN0 - возвращает серийный номер устройства
8) теоретически, на этом этапе виндовс добавляет в список устройств очередную запись, составленную из...

и вот тут начинается веселуха, природу которой я понять пока не могу.

Для кардридера винда составляет список из записей по схеме ВЕНДОР/ПРОДУКТ/СЕРИЙНЫЙ_НОМЕР/LUN0, ВЕНДОР/ПРОДУКТ/СЕРИЙНЫЙ_НОМЕР/LUN1, ВЕНДОР/ПРОДУКТ/СЕРИЙНЫЙ_НОМЕР/LUN2, ВЕНДОР/ПРОДУКТ/СЕРИЙНЫЙ_НОМЕР/LUN3 (потому что кардридер говорит, что у него MaxLun равен 3, т.е. у нго может быть 4 накопителя на одном канале). При этом, в случае кардридера, ВЕНДОР, ПРОДУКТ и СЕРИЙНЫЙ_НОМЕР она берёт из USB-дескриптора устройства (это стандартные поля, обязательные к реализации). Я сделал аналогично, выполнив даже требование по длине серийного номера - не менее 12 символов UTF16, кодирующих цифры (дополненный нулями ASCII). При помощи USBTreeView и Wireshark/USBpcap я вижу, что дескрипторы возвращаются правильные. VID/PID я взял из примера реализации MSC (VID принадлежит STmicro, PID какой-то там... пробовал их менять - ничего не улучшилось).

Но для моего дивайса, после запроса GetMaxLun (на который я отвечаю "2", потому что у меня три накопителя) и page00/page80 винда создаёт запись по той же схеме, за один махоньким исключением: ВЕНДОР и ПРОДУКТ она берёт почему-то из данных page00, а СЕРИЙНЫЙ_НОМЕР, казалось бы, логично взять из page80 - но нет, она берёт его из page00, где он по стандарту строго 4-байтовый и никак иначе. И после этого даже не пытается опрашивать иные LUNы, вообще совсем ничего у них не спрашивает.

Ещё я вычитал, что винда не запрашивает ЛУНы с номером, отличным от нуля, когда она получает серийный номер неправильного формата в дескрипторе устройства. Мол, он должен быть именно что 12 (и более) 16-битных символов. Но у того же кардридера в дескрипторе всего 9 символов и это ему ничуть не мешает! Я повторил так же (только номер, ессно, другой), даже скопировав VID/PID - ничего не изменилось, виден всё так же 1 ЛУН.

Записать же в page00 более длинный номер, чтобы скормить винде заветные 12 циферок, я не могу. Вернее, могу, но если так сделать (ессно, откорректировав так же и длину сообщения) тогда винда шлёт какие-то ещё запросы, что-то там с секьюрностью (т.е. лишние байты воспринимаются совсем не как длинный серийный номер) и всё равно не пытается слать запросы к прочим ЛУНам.

Однако же, под линуксом процедура запуска устройства выглядит так, как я её и представлял: опрашиваются все ЛУНы, в /dev/ появляется три новых устройства, их можно отформатировать и смонтировать, файлы на них записываются-читаются и всё работает как должно, без ошибок, без лишних запросов.

Ответа нет ни на форуме ST (была надежда, что там кто-то сталкивался с аналогичной проблемой), ни на форуме Microsoft. Пока больше нигде не спрашивал.

Так же я пробовал возвращать признак несъёмного диска (non-removable) в page00 - единственное, что изменилось, это иконка устройства в линуксе: если для removable нарисована условная USB-флешка, то для Non-removable нарисован условный хард-драйв. Винда разницу демонстрирует в том, где именно нарисует этот накопитель в "Моём компьютере" - среди хардов или среди сменных носителей (и всё так же видит только первый накопитель), отличия видны так же в Wireshark: для removable устройства периодически идут запросы готовности, а для fixed таких запросов нет, что логично.

Пока отлаживался, нашёл ошибку в формате возвращаемых данных по запросу READ_FORMAT_CAPACITIES, который, во-первых, всё равно не должен влиять на количество ЛУНов; во-вторых, из-за неправильных данных, по-идее, должен был случиться какой-то глюк с отображением томов на обнаруженном накопителе, НО ЭТОГО НЕ ПРОИСХОДИТ!, потому что винда после этого запроса шлёт ещё один, стандартный READ CAPACITY(10), который и возвращает "геометрию" накопителя. И теперь формат данных точно такой же, как у кардридера, но ничего не изменилось.

Было ещё подозрение на собственно содержимое page00. Сделал его таким же, как у кардридера (только текстовые данные мои) -- ничего не изменилось.

Драйвер точно тот же, как у кардридера - стандартный. Но там работает, а тут нет. Дескрипторы корректные, насколько я могу судить. Единственное существенное различие: там HS, а у меня FS, но я нигде не вижу указаний на то, что FS "не поддерживает" мульти-ЛУНы. Mass Storage-то поддерживает, а вложенному туда протоколу SCSI вообще насрать на транспорт: он может работать хоть поверх I2C, хоть по COM-порту, хоть по голубиной почте...


UPD ПОБЕДИЛ!! Но способом таким, что это обосраться можно что за способ.
Короче, на этапе энумерации винда (или не винда, или это так и надо? но в линуксе же работало) спрашивает, среди прочего, какой-то кривой дескриптор строки нулевой длины. Т.е. дескриптор-то она запрашивает реальный, но хочет нулевую длину. Я думал, что это какой-то глюк и подготовил на этот случай именно что дескриптор со строкой нулевой длины, высылал его и ничего не работало. Будучи уже в приподнято-ебанутом состоянии после очередной бессонной ночи, я закомментил этот фрагмент кода - мол, ладно, хочешь malformed строку, будет тебе malformed строка! И ВСЁ ЗАРАБОТАЛО!!!1111........

Три диска - это те три тестовых рамдрайва внутри Awesome Board. Четыре пустышки - это уже кардридер.
Tags: слава великому мне
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 16 comments