/* * Copyright 2002/03, Thomas Kurschel. All rights reserved. * Distributed under the terms of the MIT License. */ #ifndef __SCSI_INTERNAL_H__ #define __SCSI_INTERNAL_H__ /* Part of Open SCSI bus manager Internal structures/definitions */ #include #include #include #include #include #define debug_level_error 2 #define debug_level_info 1 #define debug_level_flow 0 #define DEBUG_MSG_PREFIX "SCSI -- " #include "wrapper.h" //#define USE_FAST_LOG #ifdef USE_FAST_LOG #define FAST_LOG0( handle, event ) fast_log->log_0( handle, event ) #define FAST_LOG1( handle, event, param ) fast_log->log_1( handle, event, param ) #define FAST_LOG2( handle, event, param1, param2 ) fast_log->log_2( handle, event, param1, param2 ) #define FAST_LOG3( handle, event, param1, param2, param3 ) fast_log->log_3( handle, event, param1, param2, param3 ) #define FAST_LOGN( handle, event, num_params... ) fast_log->log_n( handle, event, num_params ) #else #define FAST_LOG0( handle, event ) #define FAST_LOG1( handle, event, param ) #define FAST_LOG2( handle, event, param1, param2 ) #define FAST_LOG3( handle, event, param1, param2, param3 ) #define FAST_LOGN( handle, event, num_params... ) #endif #include "scsi_lock.h" #define MAX_PATH_ID 255 #define MAX_TARGET_ID 31 #define MAX_LUN_ID 7 // maximum number of fragments for temporary S/G lists // for real SCSI controllers, there's no limit to transmission length // but we need a limit - ATA transmits up to 128K, so we allow that // (for massive data transmission, peripheral drivers should provide own // SG list anyway) // add one extra entry in case data is not page aligned #define MAX_TEMP_SG_FRAGMENTS (128*1024 / B_PAGE_SIZE + 1) // maximum number of temporary S/G lists #define MAX_TEMP_SG_LISTS 32 // delay in µs before DMA buffer is cleaned up #define SCSI_DMA_BUFFER_CLEANUP_DELAY 10*1000000 // buffer size for emulated SCSI commands that ATAPI cannot handle; // for MODE SELECT 6, maximum size is 255 + header, // for MODE SENSE 6, we use MODE SENSE 10 which can return 64 K, // but as the caller has to live with the 255 + header restriction, // we hope that this buffer is large enough #define SCSI_ATAPI_BUFFER_SIZE 512 // name of pnp generator of path ids #define SCSI_PATHID_GENERATOR "scsi/path_id" // true, if SCSI device needs ATAPI emulation (ui8) #define SCSI_DEVICE_IS_ATAPI_ITEM "scsi/is_atapi" // true, if device requires auto-sense emulation (ui8) #define SCSI_DEVICE_MANUAL_AUTOSENSE_ITEM "scsi/manual_autosense" // name of internal scsi_bus_raw device driver #define SCSI_BUS_RAW_MODULE_NAME "bus_managers/scsi/bus/raw" // info about DPC typedef struct scsi_dpc_info { struct scsi_dpc_info *next; bool registered; // true, if already/still in dpc list void (*func)( void * ); void *arg; } scsi_dpc_info; // controller restrictions (see blkman.h) typedef struct dma_params { uint32 alignment; uint32 max_blocks; uint32 dma_boundary; uint32 max_sg_block_size; uint32 max_sg_blocks; } dma_params; // SCSI bus typedef struct scsi_bus_info { int lock_count; // sum of blocked[0..1] and sim_overflow int blocked[2]; // depth of nested locks by bus manager (0) and SIM (1) int left_slots; // left command queuing slots on HBA bool sim_overflow; // 1, if SIM refused req because of bus queue overflow uchar path_id; // SCSI path id thread_id service_thread; // service thread sem_id start_service; // released whenever service thread has work to do bool shutting_down; // set to true to tell service thread to shut down benaphore mutex; // used to synchronize changes in queueing and blocking sem_id scan_lun_lock; // allocated whenever a lun is scanned scsi_sim_interface *interface; // SIM interface scsi_sim_cookie sim_cookie; // internal SIM cookie spinlock_irq dpc_lock; // synchronizer for dpc list scsi_dpc_info *dpc_list; // list of dpcs to execute struct scsi_device_info *waiting_devices; // devices ready to receive requests locked_pool_cookie ccb_pool; // ccb pool (one per bus) device_node_handle node; // pnp node of bus dma_params dma_params; // dma restrictions of controller scsi_path_inquiry inquiry_data; // inquiry data as read on init } scsi_bus_info; // DMA buffer typedef struct dma_buffer { area_id area; // area of DMA buffer uchar *address; // address of DMA buffer uint32 size; // size of DMA buffer area_id sg_list_area; // area of S/G list physical_entry *sg_list; // address of S/G list uint32 sg_cnt; // number of entries in S/G list bool inuse; // true, if in use bigtime_t last_use; // timestamp of last usage area_id sg_orig; // area of S/G list to original data physical_entry *sg_list_orig; // S/G list to original data uint32 sg_cnt_max_orig; // maximum size (in entries) uint32 sg_cnt_orig; // current size (in entries) uchar *orig_data; // pointer to original data const physical_entry *orig_sg_list; // original S/G list uint32 orig_sg_cnt; // size of original S/G list } dma_buffer; // SCSI device typedef struct scsi_device_info { struct scsi_device_info *waiting_next; struct scsi_device_info *waiting_prev; bool manual_autosense : 1; // no autosense support bool is_atapi : 1; // ATAPI device - needs some commands emulated int lock_count; // sum of blocked[0..1] and sim_overflow int blocked[2]; // depth of nested locks by bus manager (0) and SIM (1) int sim_overflow; // 1, if SIM returned a request because of device queue overflow int left_slots; // left command queuing slots for device int total_slots; // total number of command queuing slots for device scsi_ccb *queued_reqs; // queued requests, circularly doubly linked // (scsi_insert_new_request depends on circular) int64 last_sort; // last sort value (for elevator sort) int32 valid; // access must be atomic! scsi_bus_info *bus; uchar target_id; uchar target_lun; scsi_ccb *auto_sense_request; // auto-sense request scsi_ccb *auto_sense_originator; // request that auto-sense is // currently requested for area_id auto_sense_area; // area of auto-sense data and S/G list uint8 emulation_map[256/8]; // bit field with index being command code: // 1 indicates that this command is not supported // and thus must be emulated scsi_res_inquiry inquiry_data; device_node_handle node; // device node benaphore dma_buffer_lock; // lock between DMA buffer user and clean-up daemon sem_id dma_buffer_owner; // to be acquired before using DMA buffer dma_buffer dma_buffer; // DMA buffer #ifdef USE_FAST_LOG fast_log_handle log; // fast log connection #endif char name[30]; // name for fast log entries // buffer used for emulating SCSI commands char *buffer; physical_entry *buffer_sg_list; size_t buffer_sg_cnt; size_t buffer_size; area_id buffer_area; sem_id buffer_sem; } scsi_device_info; enum { ev_scsi_requeue_request = 1, ev_scsi_resubmit_request, ev_scsi_submit_autosense, ev_scsi_finish_autosense, ev_scsi_device_queue_overflow, ev_scsi_request_finished, ev_scsi_async_io, ev_scsi_do_resend_request, ev_copy_sg_data }; // check whether device is in bus's wait queue // we use the fact the queue is circular, so we don't need an explicit flag #define DEVICE_IN_WAIT_QUEUE( device ) ((device)->waiting_next != NULL) // state of ccb enum { SCSI_STATE_FREE = 0, SCSI_STATE_INWORK = 1, SCSI_STATE_QUEUED = 2, SCSI_STATE_SENT = 3, SCSI_STATE_FINISHED = 5, } scsi_state; extern locked_pool_interface *locked_pool; extern device_manager_info *pnp; extern fast_log_info *fast_log; extern scsi_for_sim_interface scsi_for_sim_module; extern scsi_bus_interface scsi_bus_module; extern scsi_device_interface scsi_device_module; extern struct pnp_devfs_driver_info scsi_bus_raw_module; // bus_mgr.c uchar scsi_inquiry_path( scsi_bus bus, scsi_path_inquiry *inquiry_data ); // ccb_mgr.c scsi_ccb *scsi_alloc_ccb( scsi_device_info *device ); void scsi_free_ccb( scsi_ccb *ccb ); status_t scsi_init_ccb_alloc( scsi_bus_info *bus ); void scsi_uninit_ccb_alloc( scsi_bus_info *bus ); // device_mgr.c status_t scsi_force_get_device( scsi_bus_info *bus, uchar target_id, uchar target_lun, scsi_device_info **res_device ); void scsi_put_forced_device( scsi_device_info *device ); status_t scsi_register_device( scsi_bus_info *bus, uchar target_id, uchar target_lun, scsi_res_inquiry *inquiry_data ); // device_scan.c status_t scsi_scan_bus( scsi_bus_info *bus ); status_t scsi_scan_lun( scsi_bus_info *bus, uchar target_id, uchar target_lun ); // dpc.c status_t scsi_alloc_dpc( scsi_dpc_info **dpc ); status_t scsi_free_dpc( scsi_dpc_info *dpc ); bool scsi_check_exec_dpc( scsi_bus_info *bus ); status_t scsi_schedule_dpc( scsi_bus_info *bus, scsi_dpc_info *dpc, /*int flags,*/ void (*func)( void *arg ), void *arg ); // scsi_io.c void scsi_async_io( scsi_ccb *request ); void scsi_sync_io( scsi_ccb *request ); uchar scsi_term_io( scsi_ccb *ccb_to_terminate ); uchar scsi_abort( scsi_ccb *ccb_to_abort ); bool scsi_check_exec_service( scsi_bus_info *bus ); void scsi_done_io( scsi_ccb *ccb ); void scsi_requeue_request( scsi_ccb *request, bool bus_overflow ); void scsi_resubmit_request( scsi_ccb *request ); void scsi_request_finished( scsi_ccb *request, uint num_requests ); // sg_mgr.c bool create_temp_sg( scsi_ccb *ccb ); void cleanup_tmp_sg( scsi_ccb *ccb ); int init_temp_sg( void ); void uninit_temp_sg( void ); // dma_buffer.c void scsi_dma_buffer_daemon( void *dev, int counter ); void scsi_release_dma_buffer( scsi_ccb *request ); bool scsi_get_dma_buffer( scsi_ccb *request ); void scsi_dma_buffer_free( dma_buffer *buffer ); void scsi_dma_buffer_init( dma_buffer *buffer ); // queuing.c // emulation.c bool scsi_start_emulation( scsi_ccb *request ); void scsi_finish_emulation( scsi_ccb *request ); void scsi_free_emulation_buffer( scsi_device_info *device ); status_t scsi_init_emulation_buffer( scsi_device_info *device, size_t buffer_size ); #endif