Отключение объединения завершения команд (CCC) в SATA AHCI

Я работаю над версией ядра Linux 2.6.35.9 и пытаюсь отключить объединение завершения команд.

Вывод lspci показан ниже:

00:00.0 Host bridge: Intel Corporation 82P965/G965 Memory Controller Hub (rev 02)
00:01.0 PCI bridge: Intel Corporation 82P965/G965 PCI Express Root Port (rev 02)
00:19.0 Ethernet controller: Intel Corporation 82566DC Gigabit Network Connection (rev 02)
00:1a.0 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #4 (rev 02)
00:1a.1 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #5 (rev 02)
00:1a.7 USB Controller: Intel Corporation 82801H (ICH8 Family) USB2 EHCI Controller #2 (rev 02)
00:1c.0 PCI bridge: Intel Corporation 82801H (ICH8 Family) PCI Express Port 1 (rev 02)
00:1c.4 PCI bridge: Intel Corporation 82801H (ICH8 Family) PCI Express Port 5 (rev 02)
00:1d.0 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #1 (rev 02)
00:1d.1 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #2 (rev 02)
00:1d.2 USB Controller: Intel Corporation 82801H (ICH8 Family) USB UHCI Controller #3 (rev 02)
00:1d.7 USB Controller: Intel Corporation 82801H (ICH8 Family) USB2 EHCI Controller #1 (rev 02)
00:1e.0 PCI bridge: Intel Corporation 82801 PCI Bridge (rev f2)
00:1f.0 ISA bridge: Intel Corporation 82801HH (ICH8DH) LPC Interface Controller (rev 02)
00:1f.2 RAID bus controller: Intel Corporation 82801 SATA RAID Controller (rev 02)
00:1f.3 SMBus: Intel Corporation 82801H (ICH8 Family) SMBus Controller (rev 02)
01:00.0 VGA compatible controller: nVidia Corporation G72 [GeForce 7300 LE] (rev a1)
04:03.0 Mass storage controller: Promise Technology, Inc. PDC20268 (Ultra100 TX2) (rev 02)

На моих дисках включена собственная очередь команд.

Я просматривал спецификацию Serial ATA AHCI 1.3 и нашел ее на странице 115. что -

Функция CCC используется только в том случае, если для CCC_CTL.EN установлено значение «1». Если для CCC_CTL.EN установлено значение «0», прерывания CCC не генерируются.

Затем я просмотрел соответствующий код (а именно, файлы, касающиеся AHCI) для этой версии ядра, но не смог добиться никакого прогресса. Я нашел следующее перечисление macro HOST_CAP_CCC = (1 << 7) в drivers/ata/ahci.h, но я не уверен, как его следует изменить, чтобы отключить объединение команд.

Может ли кто-нибудь помочь мне определить, как можно отключить CCC? Благодарю вас!


В ответ на комментарий gby:

Я провел эксперимент, в котором выдавал запросы размером 64 КБ из кода моего драйвера. 64 КБ соответствуют 128 секторам (каждый сектор = 512 байт).

Когда я смотрю на разницу временных меток ответа, вот что я нахожу:

Timestamp  | Timestamp  |  Difference 
   at      |     at     |  in microsecs
Sector 255 - Sector 127 =  510
Sector 383 - Sector 255 =  3068
Sector 511 - Sector 383 =  22
Sector 639 - Sector 511 =  22
Sector 767 - Sector 639 =  12
Sector 895 - Sector 767 =  19
Sector 1023 - Sector 895 =  13
Sector 1151 - Sector 1023 =  402

Как видите, различия в отметке времени отклика позволяют предположить, что прерывания завершения записи группируются в одно, а затем инициируется одно единственное прерывание, что может объяснить очень низкие значения в десятки микросекунд.

Кроме того, при проведении этого эксперимента кеш записи на диск был отключен с помощью hdparm.

Очевидно, здесь задействована некоторая пакетная обработка прерываний, которую мне нужно отключить, чтобы прерывание возникало для каждого запроса на запись.


ОБНОВЛЕНИЕ: Вот еще один эксперимент, который я провел.

Создайте структуру bio в моем драйвере и вызовите функцию __make_request() драйвера более низкого уровня. От моего драйвера отправляется только один запрос на запись 2560 байт.

Как только эта запись обслужена, генерируется прерывание, которое перехватывается do_IRQ(). Наконец, вызывается функция blk_complete_request(). Имейте в виду, что мы все еще находимся в верхней половине обработчика прерывания (т. е. в контексте прерывания, не в контексте ядра). Теперь составим еще один struct bio в blk_complete_request() и вызовем функцию __make_request() драйвера нижнего уровня. В этот момент мы записываем метку времени (скажем, T_0). Когда получен обратный вызов завершения запроса, мы записываем еще одну метку времени (назовем ее T_1). Разница - T_1 - T_0 - всегда превышает 1 миллисекунду. Этот эксперимент повторялся множество раз, и каждый раз на эту разницу влиял сектор назначения - T_1 - T_0. Было замечено, что если секторы назначения разделены примерно 350 секторами, разница во времени составляет около 1,2 мс для запросов размером 2560 байт.

Каждый раз следующий запрос на запись отправляется только тогда, когда предыдущий запрос был обслужен. Итак, все эти запросы связаны, и диск должен обслуживать только один запрос за раз.

Насколько я понимаю, поскольку целевые сектора последовательных запросов были разделены довольно большим количеством, к моменту выдачи следующего запроса запрошенный сектор будет почти ниже головки диска, и поэтому запись должна произойти немедленно, а T_1 - T_0 должно быть небольшой (не менее ‹ 1 миллисекунды).

Спецификация Serial ATA AHCI 1.3 (стр. 114) гласит:

Когда количество команд, указанное программным обеспечением, завершено или тайм-аут, указанный программным обеспечением, истек, аппаратное прерывание генерируется, чтобы позволить программному обеспечению обработать завершенные команды.

Я предполагаю, что этот таймер может быть причиной того, что задержка каждого запроса превышает 1 миллисекунду. Вот почему мне нужно отключить CCC.

Я написал автору — Джеффу Гарзику — но пока ничего от него не слышал. Является ли он зарегистрированным пользователем stackoverflow? Если да, я мог бы написать ему в личку...

Используемый нами жесткий диск: WD Caviar Black (номер модели — WD1001FALS).

Кто угодно? :-(


person user745878    schedule 09.05.2011    source источник
comment
Вы уверены, что CCC вообще включен? не похоже, что код драйвера делает что-либо, чтобы включить или проверить его где-либо.   -  person gby    schedule 10.05.2011
comment
@gby - я отредактировал свой пост в ответ на ваш комментарий.   -  person user745878    schedule 10.05.2011
comment
Добавил еще один экспериментальный результат в мой исходный пост. Надеюсь, поможет!   -  person user745878    schedule 11.05.2011
comment
Не объясняются ли некоторые особенности тайминга тем, что накопитель пытается заполнить часть своего 64-мегабайтного буфера? Предположительно, запрос на чтение одного сектора фактически удовлетворяется за счет того, что накопитель считывает дополнительные близлежащие сектора в свой буфер. Это возмущает время первого чтения, но улучшает все кешированные чтения.   -  person wallyk    schedule 11.05.2011
comment
Вы имеете в виду кеш записи? Я отключил его (и некоторые другие кеши тоже): hdparm -a0 -W0 /dev/sdd; hdparm -m0 --yes-i-know-what-i-am-doing /dev/sdd; hdparm -A0 /dev/sdd;   -  person user745878    schedule 12.05.2011
comment
Кроме того, все запросы являются запросами на запись; те сектора, которые читаются, будут использоваться для обновления метаданных. Эту информацию можно легко получить от iostat.   -  person user745878    schedule 12.05.2011


Ответы (1)


Насколько я знаю, HBA capabilities bit7(CCC supported) это RO, и вы можете сначала проверить его, чтобы узнать, поддерживается ли CCC. Затем по спецификации вы можете отключить CCC, установив CCC_CTL.EN, потому что это RW

Вы пытаетесь очистить его, а затем проводите свой эксперимент?

person liaoo    schedule 16.08.2012