Где находятся команды NVMe внутри P CIe BAR? - PullRequest
1 голос
/ 20 февраля 2020

Согласно спецификации NVMe, BAR имеет поля tail и head для каждой очереди. Например:

  • Очередь отправки y Хвостовой дверной звонок (SQyTDBL):
    • Начало: 1000h + (2y * (4 << CAP.DSTRD))
    • Окончание: 1003h + (2y * (4 << CAP.DSTRD))
  • Очередь отправки y Главный дверной звонок (SQyHDBL):
    • Начало: 1000h + ((2y + 1) * (4 << CAP.DSTRD))
    • Конец: 1003h + ((2y + 1) * (4 << CAP.DSTRD))

Есть ли сама очередь или просто указатели? Это правильно? Если это очередь, я бы предположил, что DSTRD указывает максимальную длину всех очередей.

Более того, в спецификации говорится о двух необязательные области: буфер памяти хоста (HMB) и буфер памяти контроллера (CMB).

  • HMB: область в DRAM хоста (P CIe root)
  • CMB: область в DRAM контроллера NVMe (внутри SSD)

Если оба являются необязательными, то где они расположены? С конечной точки P CIe работает только с BAR и PCI-заголовками, я не вижу другого места, где они могут быть, кроме BAR.

1 Ответ

0 голосов
/ 01 марта 2020

Извините, но я делаю это по памяти, но я внедрил хост с FPGA NVMe, так что, надеюсь, моей памяти будет достаточно, чтобы ответить на ваши вопросы и даже больше, если я пойму что-то не так, хотя, по крайней мере, вы знаете, почему. Я буду предоставлять справочные разделы из спецификации, которую вы можете найти здесь. https://nvmexpress.org/wp-content/uploads/NVM-Express-1_4-2019.06.10-Ratified.pdf Также, как примечание, прежде чем я действительно отвечу на ваш вопрос, я хочу прояснить некоторую путаницу, понимание понимания c занимает некоторое время, я искренне рекомендую прочитать его снизу вверх, последние несколько разделов помогают дать контекст для первых несколько странно, как это звучит.

  1. Это очереди отправки и завершения, в частности, хвост подзаголовка и заголовок очереди завершения соответственно ( РАЗДЕЛ 3.1 ). Более подробно об этом позже я просто хотел исправить ошибочное представление о том, что вы обращаетесь к главе очереди отправки в качестве хоста, а не только контроллер (традиционно диск). Простое напоминание - вы просите диск сделать что-то, а завершение - это диск, рассказывающий, как все прошло. Прочитайте РАЗДЕЛ 7.2 для получения дополнительной информации.

  2. Прежде чем вы сможете что-либо отправить в эти очереди, вы должны сначала настроить указанные очереди. Базовые показатели в системе этих очередей не существуют, вы должны использовать очередь администратора для их настройки.

28h 2Fh Базовый адрес очереди отправки администратора ASQ

30h 37h Базовый адрес очереди завершения администратора ACQ

Ваше утверждение о DSTRD является огромным недоразумением. Это поле из регистра возможностей (0x0) Рисунок 3.1.1 . В этом поле находится контроллер (диск), который сообщает вам «шаг дверного звонка», который говорит, сколько байт находится между каждым дверным звонком. Я никогда не видел, чтобы диск сообщал что-либо, кроме 0, для этого значения, так почему бы вы захотели оставить мертвое пространство? между регистрами дверного звонка.

Пожалуйста, будьте осторожны с размером ваших записей, по моему опыту, большинство накопителей NVMe требуют, чтобы вы отправляли записи по крайней мере на 2 слова (8 байт), даже если вы только намерены чтобы отправить 1 слово данных, просто заметку.

Чтобы помочь вам использовать эту вещь в качестве хоста, обратитесь к РАЗДЕЛу 7.6.1 , чтобы найти последовательность инициализации , Обратите внимание, как вы должны настроить несколько регистров, прочитать определенные параметры и другие подобные вещи.

Предполагая, что вы или кто-то еще сделал инициализацию, позвольте мне теперь ответить на суть вашего вопроса, как их использовать очереди. Дело в том, что этот ответ охватывает МНОГО разделов спецификации c и является ее ядром. Итак, с этим я собираюсь разбить его как можно лучше для простой команды записи. Обратите внимание, что вы НЕ МОЖЕТЕ писать, пока вы сначала не создадите очереди, используя очереди администратора, которые используют разные коды операций из другого раздела спецификации c, извините, я не могу выписать все это.

ШАГИ К ПИСАНИЮ ДАННЫХ НА ПРИВОД NVMe.

  1. При создании очереди отправки вы будете указывать размер этой указанной c очереди. Это количество команд, которые могут быть помещены в очередь за один раз для обработки. Наряду с этим вы укажете базовый адрес очереди. Итак, для этого примера давайте предположим, что вы установили базовый адрес 0x1000_0000 и размер 16 (0x10). Рисунок 105 . Позвольте нам знать, что каждая запись в очереди отправки имеет размер 64 байта (0x40), поэтому запись в очереди 0 имеет значение 0x1000_0000, а запись 1 - 0x1000_0040 2 0x1000_0080 и т. Д. Для наших 16 записей выполняется возврат в обратном направлении.

  2. Сначала вы сохраните данные для записи, скажем, вам дали 512 байт (0x200) данных для записи. Поэтому для простоты вы помещаете эти данные в 0x2000_0000 - 0x2000_0200.

  3. Вы создаете команду очереди отправки. Это не простой процесс. Я не собираюсь документировать все это для вас, но понимаю, что вы должны ссылаться на Рисунок 104, Рисунок 346 и Раздел 6.15 . Однако этого недостаточно. Вам также нужно будет понять, что такое PRP против SGL и какой вы используете (PRP легче начать с). NLB (число логических блоков), которые определяют ваш размер записи, с NVMe вы не указываете записи в байтах, но в терминах NLB, размер которых определяется контроллером (накопителем), он может реализовывать несколько размеров NLB, но это до диск, а не вы как хост, вы просто выбираете из того, что он поддерживает Раздел 5.15.2.1, Рисунок 245 Вы хотите взглянуть на идентификационное пространство имен, чтобы сообщить вам размер LBA (адрес логического блока), это проведет вас по кроличьей норе, чтобы определить фактический размер, но это нормально, информация есть.

  4. Хорошо, вы закончили этот беспорядок и создали команду отправки. Давайте предположим, что хост уже выполнил 2 команды в этой очереди (при запуске это будет 0, я выбираю 2, чтобы быть более понятным в моем примере). Теперь вам нужно поместить эту команду в 0x1000_0080.

  5. Теперь давайте предположим, что это очередь 1 (из уравнения, которое вы разместили, номер очереди равен y значение. Обратите внимание, что очередь 0 является очередью администратора). Что вам нужно сделать, это нажать на хвостовой дверной звонок очереди отправки контроллера, чтобы сказать, сколько команд теперь загружено (таким образом, вы можете поставить в очередь сразу несколько команд и сообщить накопителю только тогда, когда будете готовы). В этом случае число равно 2. Таким образом, вам нужно записать значение 2, чтобы зарегистрировать 0x1008.

  6. На этом этапе привод будет go. ага, хозяин сказал мне, что есть новые команды для загрузки. Таким образом, контроллер будет go ставить в очередь базовый адрес + размер команды * 2 и извлекать 64 байта данных, или команду 1 (адрес 0x1000_0080). Контроллер декодирует эту команду как запись, что означает, что контроллер (накопитель) должен прочитать данные с какого-либо адреса и поместить их в память, где им было сказано. Это означает, что ваша команда записи должна указать дисководу go адрес 0x2000_0000 и прочитать 512 байт данных, и это произойдет, если вы включите шину P CIe. В этот момент накопитель заполнит запись в очереди завершения (16 байтов, указанных в Раздел 4.6 ) и поместит ее в адрес очереди завершения, указанный вами при создании очереди (плюс 0x20, поскольку это второе завершение). Затем контроллер сгенерирует прерывание MSI-X.

  7. В этот момент вы должны go куда бы ни была помещена очередь завершения и прочитать ответ на проверку статуса, а также, если вы Многократные представления в очереди проверяют SQID, чтобы видеть, что закончено, так как задания могут завершиться sh из строя. Затем вы должны записать в заголовок очереди завершения (0x100 C), чтобы указать, что вы получили очередь завершения (успех или неудача). Обратите внимание, что здесь вы никогда не взаимодействуете с главой очереди отправки (это зависит от контроллера, поскольку только он знает, когда была обработана запись в очереди отправки), и только контроллер помещает вещи в хвост очереди завершения, поскольку только он может создавать новые записи.

Извините, это так долго и плохо отформатировано, но, надеюсь, теперь у вас есть немного лучшее понимание NVMe, сначала это немного беспорядок, но как только вы его получите, все это имеет смысл , Просто запомните мой пример, предполагая, что вы создали очередь, базовый уровень которой не существует. Сначала вам нужно настроить очереди отправки и завершения администратора (0x28 и 0x30) с идентификатором очереди 0, поэтому его дверной звонок в хвостовой / головной части имеет адрес 0x1000,0x1004 соответственно. Затем вы должны обратиться к Раздел 5 , чтобы найти коды операций, чтобы сделать что-то, но я верю, что вы можете понять это из того, что я вам дал. Если у вас есть еще вопросы, оставьте комментарий, и я посмотрю, что я могу сделать.

...