185Scth /* 285Scth * CDDL HEADER START 385Scth * 485Scth * The contents of this file are subject to the terms of the 585Scth * Common Development and Distribution License, Version 1.0 only 685Scth * (the "License"). You may not use this file except in compliance 785Scth * with the License. 885Scth * 985Scth * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 1085Scth * or http://www.opensolaris.org/os/licensing. 1185Scth * See the License for the specific language governing permissions 1285Scth * and limitations under the License. 1385Scth * 1485Scth * When distributing Covered Code, include this CDDL HEADER in each 1585Scth * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1685Scth * If applicable, add the following below this CDDL HEADER, with the 1785Scth * fields enclosed by brackets "[]" replaced with your own identifying 1885Scth * information: Portions Copyright [yyyy] [name of copyright owner] 1985Scth * 2085Scth * CDDL HEADER END 2185Scth */ 2285Scth /* 2385Scth * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 2485Scth * Use is subject to license terms. 2585Scth */ 2685Scth 2785Scth #ifndef _SYS_SCSI_ADAPTERS_EMUL64VAR_H 2885Scth #define _SYS_SCSI_ADAPTERS_EMUL64VAR_H 2985Scth 3085Scth #pragma ident "%Z%%M% %I% %E% SMI" 3185Scth 3285Scth #include <sys/avl.h> 3385Scth #include <sys/note.h> 3485Scth #include <sys/emul64.h> 3585Scth 3685Scth #ifdef __cplusplus 3785Scth extern "C" { 3885Scth #endif 3985Scth 4085Scth /* 4185Scth * Convenient short hand defines 4285Scth */ 4385Scth #define TRUE 1 4485Scth #define FALSE 0 4585Scth #define UNDEFINED -1 4685Scth 4785Scth #define CNUM(emul64) (ddi_get_instance(emul64->emul64_tran.tran_dev)) 4885Scth 4985Scth #define EMUL64_RETRY_DELAY 5 5085Scth #define EMUL64_RETRIES 0 /* retry of selections */ 5185Scth #define EMUL64_INITIAL_SOFT_SPACE 5 /* Used for the softstate_init func */ 5285Scth 5385Scth #define MSW(x) (int16_t)(((int32_t)x >> 16) & 0xFFFF) 5485Scth #define LSW(x) (int16_t)((int32_t)x & 0xFFFF) 5585Scth 5685Scth #define TGT(sp) (CMD2PKT(sp)->pkt_address.a_target) 5785Scth #define LUN(sp) (CMD2PKT(sp)->pkt_address.a_lun) 5885Scth 5985Scth #define HW_REV(val) (((val) >>8) & 0xff) 6085Scth #define FW_REV(val) ((val) & 0xff) 6185Scth 6285Scth /* 6385Scth * max number of LUNs per target 6485Scth */ 6585Scth #define EMUL64_NLUNS_PER_TARGET 32 6685Scth 6785Scth /* 6885Scth * Default emul64 scsi-options 6985Scth */ 7085Scth #define EMUL64_DEFAULT_SCSI_OPTIONS \ 7185Scth SCSI_OPTIONS_PARITY | \ 7285Scth SCSI_OPTIONS_DR | \ 7385Scth SCSI_OPTIONS_SYNC | \ 7485Scth SCSI_OPTIONS_TAG | \ 7585Scth SCSI_OPTIONS_FAST | \ 7685Scth SCSI_OPTIONS_WIDE 7785Scth 7885Scth /* 7985Scth * Tag reject 8085Scth */ 8185Scth #define TAG_REJECT 28 8285Scth /* 8385Scth * Interrupt actions returned by emul64_i_flag_event() 8485Scth */ 8585Scth #define ACTION_CONTINUE 0 /* Continue */ 8685Scth #define ACTION_RETURN 1 /* Exit */ 8785Scth #define ACTION_IGNORE 2 /* Ignore */ 8885Scth 8985Scth /* 9085Scth * Reset actions for emul64_i_reset_interface() 9185Scth */ 9285Scth #define EMUL64_RESET_BUS_IF_BUSY 0x01 /* reset scsi bus if it is busy */ 9385Scth #define EMUL64_FORCE_RESET_BUS 0x02 /* reset scsi bus on error reco */ 9485Scth 9585Scth 9685Scth /* 9785Scth * extracting period and offset from emul64_synch 9885Scth */ 9985Scth #define PERIOD_MASK(val) ((val) & 0xff) 10085Scth #define OFFSET_MASK(val) (((val) >>8) & 0xff) 10185Scth 10285Scth /* 10385Scth * timeout values 10485Scth */ 10585Scth #define EMUL64_GRACE 10 /* Timeout margin (sec.) */ 10685Scth #define EMUL64_TIMEOUT_DELAY(secs, delay) (secs * (1000000 / delay)) 10785Scth 10885Scth /* 10985Scth * delay time for polling loops 11085Scth */ 11185Scth #define EMUL64_NOINTR_POLL_DELAY_TIME 1000 /* usecs */ 11285Scth 11385Scth /* 11485Scth * busy wait delay time after chip reset 11585Scth */ 11685Scth #define EMUL64_CHIP_RESET_BUSY_WAIT_TIME 100 /* usecs */ 11785Scth 11885Scth /* 11985Scth * timeout for EMUL64 coming out of reset 12085Scth */ 12185Scth #define EMUL64_RESET_WAIT 1000 /* ms */ 12285Scth #define EMUL64_SOFT_RESET_TIME 1 /* second */ 12385Scth 12485Scth /* 12585Scth * emul64_softstate flags for introducing hot plug 12685Scth */ 12785Scth #define EMUL64_SS_OPEN 0x01 12885Scth #define EMUL64_SS_DRAINING 0x02 12985Scth #define EMUL64_SS_QUIESCED 0x04 13085Scth #define EMUL64_SS_DRAIN_ERROR 0x08 13185Scth 13285Scth /* 13385Scth * ioctl command definitions 13485Scth */ 13585Scth #ifndef EMUL64_RESET_TARGET 13685Scth #define EMUL64_RESET_TARGET (('i' << 8) | 0x03) 13785Scth #endif 13885Scth 13985Scth 14085Scth /* 14185Scth * Debugging macros 14285Scth */ 14385Scth #define EMUL64_DEBUG if (emul64debug) emul64_i_log 14485Scth #define EMUL64_DEBUG2 if (emul64debug > 1) emul64_i_log 14585Scth 14685Scth 14785Scth #define REQ_TGT_LUN(tgt, lun) (((tgt) << 8) | (lun)) 14885Scth 14985Scth 15085Scth #define RESP_CQ_FLAGS(resp) ((resp->resp_header.cq_flags_seq) & 0xff) 15185Scth 15285Scth 15385Scth #define EMUL64_NDATASEGS 4 15485Scth 15585Scth 15685Scth /* 15785Scth * translate scsi_pkt flags into EMUL64 request packet flags 15885Scth * It would be illegal if two flags are set; the driver does not 15985Scth * check for this. Setting NODISCON and a tag flag is harmless. 16085Scth */ 16185Scth #define EMUL64_SET_PKT_FLAGS(scsa_flags, emul64_flags) { \ 16285Scth emul64_flags = (scsa_flags >> 11) & 0xe; /* tags */ \ 16385Scth emul64_flags |= (scsa_flags >> 1) & 0x1; /* no disconnect */ \ 16485Scth } 16585Scth 16685Scth /* 16785Scth * throttle values for EMUL64 request queue 16885Scth */ 16985Scth #define SHUTDOWN_THROTTLE -1 /* do not submit any requests */ 17085Scth #define CLEAR_THROTTLE (EMUL64_MAX_REQUESTS -1) 17185Scth 17285Scth 17385Scth #define EMUL64_GET_PKT_STATE(state) ((uint32_t)(state >> 8)) 17485Scth #define EMUL64_GET_PKT_STATS(stats) ((uint32_t)(stats)) 17585Scth 17685Scth #define EMUL64_STAT_NEGOTIATE 0x0080 17785Scth 17885Scth #define EMUL64_SET_REASON(sp, reason) { \ 17985Scth if ((sp) && CMD2PKT(sp)->pkt_reason == CMD_CMPLT) \ 18085Scth CMD2PKT(sp)->pkt_reason = (reason); \ 18185Scth } 18285Scth 18385Scth /* 18485Scth * mutex short hands 18585Scth */ 18685Scth #define EMUL64_REQ_MUTEX(emul64) (&emul64->emul64_request_mutex) 18785Scth #define EMUL64_RESP_MUTEX(emul64) (&emul64->emul64_response_mutex) 18885Scth #define EMUL64_HOTPLUG_MUTEX(emul64) (&emul64->emul64_hotplug_mutex) 18985Scth 19085Scth 19185Scth #define EMUL64_MUTEX_ENTER(emul64) mutex_enter(EMUL64_RESP_MUTEX(emul64)), \ 19285Scth mutex_enter(EMUL64_REQ_MUTEX(emul64)) 19385Scth #define EMUL64_MUTEX_EXIT(emul64) mutex_exit(EMUL64_RESP_MUTEX(emul64)), \ 19485Scth mutex_exit(EMUL64_REQ_MUTEX(emul64)) 19585Scth 19685Scth #define EMUL64_CV(emul64) (&(emul64)->emul64_cv) 19785Scth 19885Scth /* 19985Scth * HBA interface macros 20085Scth */ 20185Scth #define SDEV2TRAN(sd) ((sd)->sd_address.a_hba_tran) 20285Scth #define SDEV2ADDR(sd) (&((sd)->sd_address)) 20385Scth #define PKT2TRAN(pkt) ((pkt)->pkt_address.a_hba_tran) 20485Scth #define ADDR2TRAN(ap) ((ap)->a_hba_tran) 20585Scth 20685Scth #define TRAN2EMUL64(tran) ((struct emul64 *)(tran)->tran_hba_private) 20785Scth #define SDEV2EMUL64(sd) (TRAN2EMUL64(SDEV2TRAN(sd))) 20885Scth #define PKT2EMUL64(pkt) (TRAN2EMUL64(PKT2TRAN(pkt))) 20985Scth #define ADDR2EMUL64(ap) (TRAN2EMUL64(ADDR2TRAN(ap))) 21085Scth 21185Scth #define CMD2ADDR(cmd) (&CMD2PKT(cmd)->pkt_address) 21285Scth #define CMD2TRAN(cmd) (CMD2PKT(cmd)->pkt_address.a_hba_tran) 21385Scth #define CMD2EMUL64(cmd) (TRAN2EMUL64(CMD2TRAN(cmd))) 21485Scth 21585Scth /* 21685Scth * Results of checking for range overlap. 21785Scth */ 21885Scth typedef enum emul64_rng_overlap { 21985Scth O_NONE, /* No overlap */ 22085Scth O_SAME, /* Ranges are identical */ 22185Scth O_SUBSET, /* Blocks are contained in range */ 22285Scth O_OVERLAP /* Ranges overlap. */ 22385Scth } emul64_rng_overlap_t; 22485Scth 22585Scth /* 22685Scth * Rather than keep the entire image of the disk, we only keep 22785Scth * the blocks which have been written with non-zeros. As the 22885Scth * purpose of this driver is to exercise format and perhaps other 22985Scth * large-disk management tools, only recording the label for 23085Scth * i/o is sufficient 23185Scth */ 23285Scth typedef struct blklist { 23385Scth diskaddr_t bl_blkno; /* Disk address of the data */ 23485Scth uchar_t *bl_data; /* Pointer to the data */ 23585Scth avl_node_t bl_node; /* Our linkage in AVL tree */ 23685Scth } blklist_t; 23785Scth 23885Scth /* 23985Scth * Structure to track a range of blocks where writes are to be ignored. 24085Scth */ 24185Scth typedef struct emul64_nowrite { 24285Scth struct emul64_nowrite *emul64_nwnext; /* next item in list */ 24385Scth emul64_range_t emul64_blocked; /* range to ignore writes */ 24485Scth } emul64_nowrite_t; 24585Scth 24685Scth typedef struct emul64_tgt { 24785Scth struct scsi_address emul64_tgt_saddr; 24885Scth struct emul64_tgt *emul64_tgt_next; /* Next tgt on ctlr */ 24985Scth emul64_nowrite_t *emul64_tgt_nowrite; /* List of regions to */ 25085Scth /* skip writes */ 25185Scth diskaddr_t emul64_tgt_sectors; /* # sectors in dev */ 25285Scth char emul64_tgt_inq[8+16]; 25385Scth uint_t emul64_tgt_dtype; 25485Scth uint_t emul64_tgt_ncyls; /* # cylinders in dev */ 25585Scth uint_t emul64_tgt_nheads; /* # disk heads */ 25685Scth uint_t emul64_tgt_nsect; /* # sectors */ 25785Scth uint64_t emul64_list_length; /* # data blks */ 25885Scth avl_tree_t emul64_tgt_data; /* Tree of data blks */ 25985Scth kmutex_t emul64_tgt_blk_lock; /* Protect data blks */ 26085Scth krwlock_t emul64_tgt_nw_lock; /* Guard tgt_nowrite */ 261*1144Spd144616 /* Fields for error injection */ 262*1144Spd144616 ushort_t emul64_einj_state; 263*1144Spd144616 ushort_t emul64_einj_sense_length; 264*1144Spd144616 uint_t emul64_einj_pkt_state; 265*1144Spd144616 uint_t emul64_einj_pkt_reason; 266*1144Spd144616 struct scsi_status emul64_einj_scsi_status; 267*1144Spd144616 uint8_t *emul64_einj_sense_data; 26885Scth } emul64_tgt_t; 26985Scth 27085Scth /* 27185Scth * emul64 softstate structure 27285Scth */ 27385Scth 27485Scth /* 27585Scth * deadline slot structure for timeout handling 27685Scth */ 27785Scth struct emul64_slot { 27885Scth struct emul64_cmd *slot_cmd; 27985Scth clock_t slot_deadline; 28085Scth }; 28185Scth 28285Scth 28385Scth /* 28485Scth * Record the reset notification requests from target drivers. 28585Scth */ 28685Scth struct emul64_reset_notify_entry { 28785Scth struct scsi_address *ap; 28885Scth void (*callback)(caddr_t); 28985Scth caddr_t arg; 29085Scth struct emul64_reset_notify_entry *next; 29185Scth }; 29285Scth 29385Scth 29485Scth struct emul64 { 29585Scth 29685Scth /* 29785Scth * Transport structure for this instance of the hba 29885Scth */ 29985Scth scsi_hba_tran_t *emul64_tran; 30085Scth 30185Scth /* 30285Scth * dev_info_t reference can be found in the transport structure 30385Scth */ 30485Scth dev_info_t *emul64_dip; 30585Scth 30685Scth /* 30785Scth * Interrupt block cookie 30885Scth */ 30985Scth ddi_iblock_cookie_t emul64_iblock; 31085Scth 31185Scth /* 31285Scth * Firmware revision number 31385Scth */ 31485Scth uint16_t emul64_major_rev; 31585Scth uint16_t emul64_minor_rev; 31685Scth 31785Scth /* 31885Scth * timeout id 31985Scth */ 32085Scth timeout_id_t emul64_timeout_id; 32185Scth 32285Scth /* 32385Scth * scsi options, scsi_tag_age_limit per emul64 32485Scth */ 32585Scth int emul64_scsi_options; 32685Scth int emul64_target_scsi_options[NTARGETS_WIDE]; 32785Scth int emul64_scsi_tag_age_limit; 32885Scth 32985Scth /* 33085Scth * scsi_reset_delay per emul64 33185Scth */ 33285Scth clock_t emul64_scsi_reset_delay; 33385Scth 33485Scth /* 33585Scth * current host ID 33685Scth */ 33785Scth uint8_t emul64_initiator_id; 33885Scth 33985Scth /* 34085Scth * suspended flag for power management 34185Scth */ 34285Scth uint8_t emul64_suspended; 34385Scth 34485Scth /* 34585Scth * Host adapter capabilities and offset/period values per target 34685Scth */ 34785Scth uint16_t emul64_cap[NTARGETS_WIDE]; 34885Scth int16_t emul64_synch[NTARGETS_WIDE]; 34985Scth 35085Scth /* 35185Scth * EMUL64 Hardware register pointer. 35285Scth */ 35385Scth struct emul64regs *emul64_reg; 35485Scth 35585Scth 35685Scth kmutex_t emul64_request_mutex; 35785Scth kmutex_t emul64_response_mutex; 35885Scth 35985Scth /* 36085Scth * for keeping track of the max LUNs per target on this bus 36185Scth */ 36285Scth uchar_t emul64_max_lun[NTARGETS_WIDE]; 36385Scth 36485Scth /* 36585Scth * for keeping track of each target/lun 36685Scth */ 36785Scth int nt_total_sectors[NTARGETS_WIDE][EMUL64_NLUNS_PER_TARGET]; 36885Scth 36985Scth struct emul64_reset_notify_entry *emul64_reset_notify_listf; 37085Scth 37185Scth ushort_t emul64_backoff; 37285Scth uint_t emul64_softstate; /* flags for hotplug */ 37385Scth int emul64_hotplug_waiting; 37485Scth kcondvar_t emul64_cv; /* cv for bus quiesce/unquiesce */ 37585Scth kmutex_t emul64_hotplug_mutex; /* Mutex for hotplug */ 37685Scth taskq_t *emul64_taskq; 37785Scth emul64_tgt_t *emul64_tgt; 37885Scth }; 37985Scth 38085Scth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 38185Scth emul64::emul64_queue_space)) 38285Scth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 38385Scth emul64::emul64_request_in)) 38485Scth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 38585Scth emul64::emul64_request_out)) 38685Scth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 38785Scth emul64::emul64_request_ptr)) 38885Scth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 38985Scth emul64::emul64_mbox)) 39085Scth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 39185Scth emul64::emul64_slots)) 39285Scth 39385Scth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_response_mutex, 39485Scth emul64::emul64_response_in)) 39585Scth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_response_mutex, 39685Scth emul64::emul64_response_out)) 39785Scth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_response_mutex, 39885Scth emul64::emul64_response_ptr)) 39985Scth 40085Scth extern void emul64_bsd_init(); 40185Scth extern void emul64_bsd_fini(); 40285Scth extern void emul64_bsd_get_props(dev_info_t *); 40385Scth 40485Scth extern emul64_rng_overlap_t emul64_overlap(emul64_range_t *, 40585Scth diskaddr_t, size_t); 40685Scth extern int emul64_bsd_blkcompare(const void *, const void *); 40785Scth extern int emul64debug; 40885Scth extern long emul64_nowrite_count; 40985Scth extern kmutex_t emul64_stats_mutex; 41085Scth extern int emul64_collect_stats; 41185Scth extern uint64_t emul64_taskq_max; 41285Scth extern int emul64_max_task; 41385Scth extern int emul64_task_nthreads; 41485Scth 41585Scth #ifdef __cplusplus 41685Scth } 41785Scth #endif 41885Scth 41985Scth #endif /* _SYS_SCSI_ADAPTERS_EMUL64VAR_H */ 420