81.3.1.4. ДРАЙВЕРА STORAGE CONTROLLERS



Практически типовые запросы к SCSI controllers сводяться к:
	- Инициализация адаптера (ну и поиск тоже)
	- Сброс Шины
	- Выполнение SCSI команды
	остальное это практически support для работы с оборудованием

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

Просто подавляюшее большенство storage controllers - Bus Master и им нужны
Физические, а не виртуальные адреса буферов.
Также есть вариант когда передаются виртуальные, а драйвер контроллера с помощью
системных RTL их транслирует в физические, что удобно для Scater/Gather, потому что
уменьшается буферизация.

Но самая большая засада, когда Storage controller расчитан на предидущую архитектуру.
Например ISA Bus Master SCSI - не может адресовать более 16MB памяти,
32-bit PCI Bus Master SCSI - не может вылезти за границу 4GB.
В таких случаях приходиться идти на ухищрения типа выделения памяти в младшей зоне
и переброска через нее. Или дополнительная поддержка чипсетом верхних DMA страниц для
конкретного PCI слота, ну и OSю конечно.


SCSI







SCSI Miniport Driver (Windows)

Внизу список функций которые экспортирут SCSI Miniport:


HwScsiInitialize() инициализует HBA (по возможности следует воздержаться от сброса SCSI шины, так как ее и так сбросили RESETом).


HwScsiFindAdapter() Функция используется для определения подходит ли конфигурационная информация предоставленная системой для HBA, который обслуживает наш драйвер.


HwScsiResetBus() Сбрасывает указанную SCSI шину (У адаптера могут быть несколько шин)


HwScsiStartIo() Передает SCSI_REQUEST_BLOCK, который содержит SCSI команду для выполнения. Кроме команды SCSI_REQUEST_BLOCK содержит всю адрессную информацию о том какое именно устройство, а также место куда записываются результат выполнения команды, и SCSI Sense. typedef struct _SCSI_REQUEST_BLOCK { USHORT Length; UCHAR Function; UCHAR SrbStatus; UCHAR ScsiStatus; UCHAR PathId; UCHAR TargetId; UCHAR Lun; UCHAR QueueTag; UCHAR QueueAction; UCHAR CdbLength; UCHAR SenseInfoBufferLength; ULONG SrbFlags; ULONG DataTransferLength; ULONG TimeOutValue; PVOID DataBuffer; PVOID SenseInfoBuffer; struct _SCSI_REQUEST_BLOCK *NextSrb; PVOID OriginalRequest; PVOID SrbExtension; union { ULONG InternalStatus; ULONG QueueSortKey; }; UCHAR Cdb[16]; } SCSI_REQUEST_BLOCK, *PSCSI_REQUEST_BLOCK;


HwScsiAdapterControl() Осуществляет управление адаптером Возможные типы controls: ScsiQuerySupportedControlTypes ScsiStopAdapter ScsiRestartAdapter ScsiSetBiosConfig - востановка настроек которые нужны BIOS для Reboot ScsiSetRunningConfig


HwScsiAdapterState() Сохраняет или востанавливает состояние SCSI HBA (Надо если BIOS его уже проиницилизировал)


HwScsiInterrupt() Точка куда приходят аппаратные прерывания от адаптера HwScsiEnableInterruptsCallback() HwScsiDisabledInterruptsCallback() вспомогательные функции которые вызываются через систему из HwScsiInterrupt() с целью разбить обработку на top and bottom half.


HwScsiDmaStarted() Вызывается если HBA - Slave DMA, после того как OS настроит DMA Transfer.


HwScsiTimer() Приходят нотификации от таймера


остальные внешние функции связаны с WMI, и для нас непринципиальны.




Linux 2.6.27.9.

Собственно имеем то же самое - обязательные функции: - выполнить команду - сброс шины (device/target/bus/host) и куча optional функций для различных случаев (Linux - это базар, поэтому это обычная ситуация).


struct scsi_host_template { struct module *module; const char *name; int (* detect)(struct scsi_host_template *); // OBSOLETE int (* release)(struct Scsi_Host *); // OBSOLETE const char *(* info)(struct Scsi_Host *); // OPTIONAL int (* ioctl)(struct scsi_device *dev, int cmd, void __user *arg); // OPTIONAL int (* compat_ioctl)(struct scsi_device *dev, int cmd, void __user *arg); // OPTIONAL int (* queuecommand)(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *)); Основная функция с помощью которой дают команду. int (* transfer_response)(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *)); int (* eh_abort_handler)(struct scsi_cmnd *); int (* eh_device_reset_handler)(struct scsi_cmnd *); int (* eh_target_reset_handler)(struct scsi_cmnd *); int (* eh_bus_reset_handler)(struct scsi_cmnd *); int (* eh_host_reset_handler)(struct scsi_cmnd *); int (* slave_alloc)(struct scsi_device *); // OPTIONAL int (* slave_configure)(struct scsi_device *); // OPTIONAL void (* slave_destroy)(struct scsi_device *); // OPTIONAL int (* target_alloc)(struct scsi_target *); // OPTIONAL void (* target_destroy)(struct scsi_target *); // OPTIONAL int (* scan_finished)(struct Scsi_Host *, unsigned long); // OPTIONAL void (* scan_start)(struct Scsi_Host *); // OPTIONAL int (* change_queue_depth)(struct scsi_device *, int); // OPTIONAL int (* change_queue_type)(struct scsi_device *, int); // OPTIONAL int (* bios_param)(struct scsi_device *, struct block_device *, sector_t, int []); // OPTIONAL int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int); // OPTIONAL enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); // OPTIONAL const char *proc_name; // Name of proc directory struct proc_dir_entry *proc_dir; int can_queue; int this_id; unsigned short sg_tablesize; unsigned short max_sectors; unsigned long dma_boundary; short cmd_per_lun; unsigned char present; unsigned supported_mode:2; unsigned unchecked_isa_dma:1; unsigned use_clustering:1; unsigned emulated:1; // ATAPI for example unsigned skip_settle_delay:1; unsigned ordered_tag:1; unsigned int max_host_blocked; struct device_attribute **shost_attrs; struct device_attribute **sdev_attrs; struct list_head legacy_hosts; };


struct scsi_cmnd { struct scsi_device *device; struct list_head list; /* scsi_cmnd participates in queue lists */ struct list_head eh_entry; /* entry for the host eh_cmd_q */ int eh_eflags; /* Used by error handlr */ unsigned long serial_number; unsigned long jiffies_at_alloc; int retries; int allowed; int timeout_per_command; unsigned char prot_op; unsigned char prot_type; unsigned short cmd_len; enum dma_data_direction sc_data_direction; unsigned char *cmnd; struct timer_list eh_timeout; /* Used to time out the command. */ struct scsi_data_buffer sdb; struct scsi_data_buffer *prot_sdb; unsigned underflow; unsigned transfersize; struct request *request; /* The command we are working on */ unsigned char *sense_buffer; void (*scsi_done) (struct scsi_cmnd *); // Callback // -- Host specific fields struct scsi_pointer SCp; /* Scratchpad used by some host adapters */ unsigned char *host_scribble; int result; /* Status code from lower level driver */ unsigned char tag; /* SCSI-II queued command tag */ };


IDE






ATA Miniport Driver (Windows)

DriverEntry() Entry point для драйвера


AtaAdapterControl() Вызывается для PnP и Power management IdeStart IdeStop IdePowerUp IdePowerDown


AtaControllerChannelEnabled() Разрешает/запрещает канал


AtaControllerTransferModeSelect() Устанавливает режим передачи


AtaChannelInitialize() Инициализирует канал


AtaHwInitialize()


AtaHwBuildIo() передается IDE_REQUEST_BLOCK, в нем ставяться необходимые


AtaHwStartIo() передается IDE_REQUEST_BLOCK с командой которую надо выполнить typedef struct _IDE_REQUEST_BLOCK { USHORT Function; UCHAR IrbStatus; UCHAR AtaStatus; UCHAR AtaError; UCHAR Channel; UCHAR TargetId; UCHAR Lun; UCHAR CdbLength; UCHAR SenseInfoBufferLength; UCHAR SenseInfoBufferType; UCHAR QueueTag; ULONG ReservedAsUlong; USHORT IrbFlags; ULONG TimeOutValue; ULONG DataTransferLength; PVOID IrbExtension; PVOID DataBuffer; PVOID SenseInfoBuffer; PVOID NextIrb; PVOID Reserved; union { IDE_TASK_FILE IdeTaskFile; UCHAR Cdb[16]; POWER_CHANGE_INFO PowerChange; UCHAR AsUChar[16]; }; } IDE_REQUEST_BLOCK, *PIDE_REQUEST_BLOCK;


AtaHwInterrupt() вызывается при аппаратном прерывании


AtaHwReset() сброс шины


AtaHwChannelControl() управление Pnp и Power StartChannel StopChannel PowerUpChannel PowerDownChannel


Index Prev Next