1*b1dd958fScth /* 2*b1dd958fScth * CDDL HEADER START 3*b1dd958fScth * 4*b1dd958fScth * The contents of this file are subject to the terms of the 5*b1dd958fScth * Common Development and Distribution License, Version 1.0 only 6*b1dd958fScth * (the "License"). You may not use this file except in compliance 7*b1dd958fScth * with the License. 8*b1dd958fScth * 9*b1dd958fScth * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*b1dd958fScth * or http://www.opensolaris.org/os/licensing. 11*b1dd958fScth * See the License for the specific language governing permissions 12*b1dd958fScth * and limitations under the License. 13*b1dd958fScth * 14*b1dd958fScth * When distributing Covered Code, include this CDDL HEADER in each 15*b1dd958fScth * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*b1dd958fScth * If applicable, add the following below this CDDL HEADER, with the 17*b1dd958fScth * fields enclosed by brackets "[]" replaced with your own identifying 18*b1dd958fScth * information: Portions Copyright [yyyy] [name of copyright owner] 19*b1dd958fScth * 20*b1dd958fScth * CDDL HEADER END 21*b1dd958fScth */ 22*b1dd958fScth /* 23*b1dd958fScth * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*b1dd958fScth * Use is subject to license terms. 25*b1dd958fScth */ 26*b1dd958fScth 27*b1dd958fScth #ifndef _SYS_SCSI_ADAPTERS_EMUL64VAR_H 28*b1dd958fScth #define _SYS_SCSI_ADAPTERS_EMUL64VAR_H 29*b1dd958fScth 30*b1dd958fScth #pragma ident "%Z%%M% %I% %E% SMI" 31*b1dd958fScth 32*b1dd958fScth #include <sys/avl.h> 33*b1dd958fScth #include <sys/note.h> 34*b1dd958fScth #include <sys/emul64.h> 35*b1dd958fScth 36*b1dd958fScth #ifdef __cplusplus 37*b1dd958fScth extern "C" { 38*b1dd958fScth #endif 39*b1dd958fScth 40*b1dd958fScth /* 41*b1dd958fScth * Convenient short hand defines 42*b1dd958fScth */ 43*b1dd958fScth #define TRUE 1 44*b1dd958fScth #define FALSE 0 45*b1dd958fScth #define UNDEFINED -1 46*b1dd958fScth 47*b1dd958fScth #define CNUM(emul64) (ddi_get_instance(emul64->emul64_tran.tran_dev)) 48*b1dd958fScth 49*b1dd958fScth #define EMUL64_RETRY_DELAY 5 50*b1dd958fScth #define EMUL64_RETRIES 0 /* retry of selections */ 51*b1dd958fScth #define EMUL64_INITIAL_SOFT_SPACE 5 /* Used for the softstate_init func */ 52*b1dd958fScth 53*b1dd958fScth #define MSW(x) (int16_t)(((int32_t)x >> 16) & 0xFFFF) 54*b1dd958fScth #define LSW(x) (int16_t)((int32_t)x & 0xFFFF) 55*b1dd958fScth 56*b1dd958fScth #define TGT(sp) (CMD2PKT(sp)->pkt_address.a_target) 57*b1dd958fScth #define LUN(sp) (CMD2PKT(sp)->pkt_address.a_lun) 58*b1dd958fScth 59*b1dd958fScth #define HW_REV(val) (((val) >>8) & 0xff) 60*b1dd958fScth #define FW_REV(val) ((val) & 0xff) 61*b1dd958fScth 62*b1dd958fScth /* 63*b1dd958fScth * max number of LUNs per target 64*b1dd958fScth */ 65*b1dd958fScth #define EMUL64_NLUNS_PER_TARGET 32 66*b1dd958fScth 67*b1dd958fScth /* 68*b1dd958fScth * Default emul64 scsi-options 69*b1dd958fScth */ 70*b1dd958fScth #define EMUL64_DEFAULT_SCSI_OPTIONS \ 71*b1dd958fScth SCSI_OPTIONS_PARITY | \ 72*b1dd958fScth SCSI_OPTIONS_DR | \ 73*b1dd958fScth SCSI_OPTIONS_SYNC | \ 74*b1dd958fScth SCSI_OPTIONS_TAG | \ 75*b1dd958fScth SCSI_OPTIONS_FAST | \ 76*b1dd958fScth SCSI_OPTIONS_WIDE 77*b1dd958fScth 78*b1dd958fScth /* 79*b1dd958fScth * Tag reject 80*b1dd958fScth */ 81*b1dd958fScth #define TAG_REJECT 28 82*b1dd958fScth /* 83*b1dd958fScth * Interrupt actions returned by emul64_i_flag_event() 84*b1dd958fScth */ 85*b1dd958fScth #define ACTION_CONTINUE 0 /* Continue */ 86*b1dd958fScth #define ACTION_RETURN 1 /* Exit */ 87*b1dd958fScth #define ACTION_IGNORE 2 /* Ignore */ 88*b1dd958fScth 89*b1dd958fScth /* 90*b1dd958fScth * Reset actions for emul64_i_reset_interface() 91*b1dd958fScth */ 92*b1dd958fScth #define EMUL64_RESET_BUS_IF_BUSY 0x01 /* reset scsi bus if it is busy */ 93*b1dd958fScth #define EMUL64_FORCE_RESET_BUS 0x02 /* reset scsi bus on error reco */ 94*b1dd958fScth 95*b1dd958fScth 96*b1dd958fScth /* 97*b1dd958fScth * extracting period and offset from emul64_synch 98*b1dd958fScth */ 99*b1dd958fScth #define PERIOD_MASK(val) ((val) & 0xff) 100*b1dd958fScth #define OFFSET_MASK(val) (((val) >>8) & 0xff) 101*b1dd958fScth 102*b1dd958fScth /* 103*b1dd958fScth * timeout values 104*b1dd958fScth */ 105*b1dd958fScth #define EMUL64_GRACE 10 /* Timeout margin (sec.) */ 106*b1dd958fScth #define EMUL64_TIMEOUT_DELAY(secs, delay) (secs * (1000000 / delay)) 107*b1dd958fScth 108*b1dd958fScth /* 109*b1dd958fScth * delay time for polling loops 110*b1dd958fScth */ 111*b1dd958fScth #define EMUL64_NOINTR_POLL_DELAY_TIME 1000 /* usecs */ 112*b1dd958fScth 113*b1dd958fScth /* 114*b1dd958fScth * busy wait delay time after chip reset 115*b1dd958fScth */ 116*b1dd958fScth #define EMUL64_CHIP_RESET_BUSY_WAIT_TIME 100 /* usecs */ 117*b1dd958fScth 118*b1dd958fScth /* 119*b1dd958fScth * timeout for EMUL64 coming out of reset 120*b1dd958fScth */ 121*b1dd958fScth #define EMUL64_RESET_WAIT 1000 /* ms */ 122*b1dd958fScth #define EMUL64_SOFT_RESET_TIME 1 /* second */ 123*b1dd958fScth 124*b1dd958fScth /* 125*b1dd958fScth * emul64_softstate flags for introducing hot plug 126*b1dd958fScth */ 127*b1dd958fScth #define EMUL64_SS_OPEN 0x01 128*b1dd958fScth #define EMUL64_SS_DRAINING 0x02 129*b1dd958fScth #define EMUL64_SS_QUIESCED 0x04 130*b1dd958fScth #define EMUL64_SS_DRAIN_ERROR 0x08 131*b1dd958fScth 132*b1dd958fScth /* 133*b1dd958fScth * ioctl command definitions 134*b1dd958fScth */ 135*b1dd958fScth #ifndef EMUL64_RESET_TARGET 136*b1dd958fScth #define EMUL64_RESET_TARGET (('i' << 8) | 0x03) 137*b1dd958fScth #endif 138*b1dd958fScth 139*b1dd958fScth 140*b1dd958fScth /* 141*b1dd958fScth * Debugging macros 142*b1dd958fScth */ 143*b1dd958fScth #define EMUL64_DEBUG if (emul64debug) emul64_i_log 144*b1dd958fScth #define EMUL64_DEBUG2 if (emul64debug > 1) emul64_i_log 145*b1dd958fScth 146*b1dd958fScth 147*b1dd958fScth #define REQ_TGT_LUN(tgt, lun) (((tgt) << 8) | (lun)) 148*b1dd958fScth 149*b1dd958fScth 150*b1dd958fScth #define RESP_CQ_FLAGS(resp) ((resp->resp_header.cq_flags_seq) & 0xff) 151*b1dd958fScth 152*b1dd958fScth 153*b1dd958fScth #define EMUL64_NDATASEGS 4 154*b1dd958fScth 155*b1dd958fScth 156*b1dd958fScth /* 157*b1dd958fScth * translate scsi_pkt flags into EMUL64 request packet flags 158*b1dd958fScth * It would be illegal if two flags are set; the driver does not 159*b1dd958fScth * check for this. Setting NODISCON and a tag flag is harmless. 160*b1dd958fScth */ 161*b1dd958fScth #define EMUL64_SET_PKT_FLAGS(scsa_flags, emul64_flags) { \ 162*b1dd958fScth emul64_flags = (scsa_flags >> 11) & 0xe; /* tags */ \ 163*b1dd958fScth emul64_flags |= (scsa_flags >> 1) & 0x1; /* no disconnect */ \ 164*b1dd958fScth } 165*b1dd958fScth 166*b1dd958fScth /* 167*b1dd958fScth * throttle values for EMUL64 request queue 168*b1dd958fScth */ 169*b1dd958fScth #define SHUTDOWN_THROTTLE -1 /* do not submit any requests */ 170*b1dd958fScth #define CLEAR_THROTTLE (EMUL64_MAX_REQUESTS -1) 171*b1dd958fScth 172*b1dd958fScth 173*b1dd958fScth #define EMUL64_GET_PKT_STATE(state) ((uint32_t)(state >> 8)) 174*b1dd958fScth #define EMUL64_GET_PKT_STATS(stats) ((uint32_t)(stats)) 175*b1dd958fScth 176*b1dd958fScth #define EMUL64_STAT_NEGOTIATE 0x0080 177*b1dd958fScth 178*b1dd958fScth #define EMUL64_SET_REASON(sp, reason) { \ 179*b1dd958fScth if ((sp) && CMD2PKT(sp)->pkt_reason == CMD_CMPLT) \ 180*b1dd958fScth CMD2PKT(sp)->pkt_reason = (reason); \ 181*b1dd958fScth } 182*b1dd958fScth 183*b1dd958fScth /* 184*b1dd958fScth * mutex short hands 185*b1dd958fScth */ 186*b1dd958fScth #define EMUL64_REQ_MUTEX(emul64) (&emul64->emul64_request_mutex) 187*b1dd958fScth #define EMUL64_RESP_MUTEX(emul64) (&emul64->emul64_response_mutex) 188*b1dd958fScth #define EMUL64_HOTPLUG_MUTEX(emul64) (&emul64->emul64_hotplug_mutex) 189*b1dd958fScth 190*b1dd958fScth 191*b1dd958fScth #define EMUL64_MUTEX_ENTER(emul64) mutex_enter(EMUL64_RESP_MUTEX(emul64)), \ 192*b1dd958fScth mutex_enter(EMUL64_REQ_MUTEX(emul64)) 193*b1dd958fScth #define EMUL64_MUTEX_EXIT(emul64) mutex_exit(EMUL64_RESP_MUTEX(emul64)), \ 194*b1dd958fScth mutex_exit(EMUL64_REQ_MUTEX(emul64)) 195*b1dd958fScth 196*b1dd958fScth #define EMUL64_CV(emul64) (&(emul64)->emul64_cv) 197*b1dd958fScth 198*b1dd958fScth /* 199*b1dd958fScth * HBA interface macros 200*b1dd958fScth */ 201*b1dd958fScth #define SDEV2TRAN(sd) ((sd)->sd_address.a_hba_tran) 202*b1dd958fScth #define SDEV2ADDR(sd) (&((sd)->sd_address)) 203*b1dd958fScth #define PKT2TRAN(pkt) ((pkt)->pkt_address.a_hba_tran) 204*b1dd958fScth #define ADDR2TRAN(ap) ((ap)->a_hba_tran) 205*b1dd958fScth 206*b1dd958fScth #define TRAN2EMUL64(tran) ((struct emul64 *)(tran)->tran_hba_private) 207*b1dd958fScth #define SDEV2EMUL64(sd) (TRAN2EMUL64(SDEV2TRAN(sd))) 208*b1dd958fScth #define PKT2EMUL64(pkt) (TRAN2EMUL64(PKT2TRAN(pkt))) 209*b1dd958fScth #define ADDR2EMUL64(ap) (TRAN2EMUL64(ADDR2TRAN(ap))) 210*b1dd958fScth 211*b1dd958fScth #define CMD2ADDR(cmd) (&CMD2PKT(cmd)->pkt_address) 212*b1dd958fScth #define CMD2TRAN(cmd) (CMD2PKT(cmd)->pkt_address.a_hba_tran) 213*b1dd958fScth #define CMD2EMUL64(cmd) (TRAN2EMUL64(CMD2TRAN(cmd))) 214*b1dd958fScth 215*b1dd958fScth /* 216*b1dd958fScth * Results of checking for range overlap. 217*b1dd958fScth */ 218*b1dd958fScth typedef enum emul64_rng_overlap { 219*b1dd958fScth O_NONE, /* No overlap */ 220*b1dd958fScth O_SAME, /* Ranges are identical */ 221*b1dd958fScth O_SUBSET, /* Blocks are contained in range */ 222*b1dd958fScth O_OVERLAP /* Ranges overlap. */ 223*b1dd958fScth } emul64_rng_overlap_t; 224*b1dd958fScth 225*b1dd958fScth /* 226*b1dd958fScth * Rather than keep the entire image of the disk, we only keep 227*b1dd958fScth * the blocks which have been written with non-zeros. As the 228*b1dd958fScth * purpose of this driver is to exercise format and perhaps other 229*b1dd958fScth * large-disk management tools, only recording the label for 230*b1dd958fScth * i/o is sufficient 231*b1dd958fScth */ 232*b1dd958fScth typedef struct blklist { 233*b1dd958fScth diskaddr_t bl_blkno; /* Disk address of the data */ 234*b1dd958fScth uchar_t *bl_data; /* Pointer to the data */ 235*b1dd958fScth avl_node_t bl_node; /* Our linkage in AVL tree */ 236*b1dd958fScth } blklist_t; 237*b1dd958fScth 238*b1dd958fScth /* 239*b1dd958fScth * Structure to track a range of blocks where writes are to be ignored. 240*b1dd958fScth */ 241*b1dd958fScth typedef struct emul64_nowrite { 242*b1dd958fScth struct emul64_nowrite *emul64_nwnext; /* next item in list */ 243*b1dd958fScth emul64_range_t emul64_blocked; /* range to ignore writes */ 244*b1dd958fScth } emul64_nowrite_t; 245*b1dd958fScth 246*b1dd958fScth typedef struct emul64_tgt { 247*b1dd958fScth struct scsi_address emul64_tgt_saddr; 248*b1dd958fScth struct emul64_tgt *emul64_tgt_next; /* Next tgt on ctlr */ 249*b1dd958fScth emul64_nowrite_t *emul64_tgt_nowrite; /* List of regions to */ 250*b1dd958fScth /* skip writes */ 251*b1dd958fScth diskaddr_t emul64_tgt_sectors; /* # sectors in dev */ 252*b1dd958fScth char emul64_tgt_inq[8+16]; 253*b1dd958fScth uint_t emul64_tgt_dtype; 254*b1dd958fScth uint_t emul64_tgt_ncyls; /* # cylinders in dev */ 255*b1dd958fScth uint_t emul64_tgt_nheads; /* # disk heads */ 256*b1dd958fScth uint_t emul64_tgt_nsect; /* # sectors */ 257*b1dd958fScth uint64_t emul64_list_length; /* # data blks */ 258*b1dd958fScth avl_tree_t emul64_tgt_data; /* Tree of data blks */ 259*b1dd958fScth kmutex_t emul64_tgt_blk_lock; /* Protect data blks */ 260*b1dd958fScth krwlock_t emul64_tgt_nw_lock; /* Guard tgt_nowrite */ 261*b1dd958fScth } emul64_tgt_t; 262*b1dd958fScth 263*b1dd958fScth /* 264*b1dd958fScth * emul64 softstate structure 265*b1dd958fScth */ 266*b1dd958fScth 267*b1dd958fScth /* 268*b1dd958fScth * deadline slot structure for timeout handling 269*b1dd958fScth */ 270*b1dd958fScth struct emul64_slot { 271*b1dd958fScth struct emul64_cmd *slot_cmd; 272*b1dd958fScth clock_t slot_deadline; 273*b1dd958fScth }; 274*b1dd958fScth 275*b1dd958fScth 276*b1dd958fScth /* 277*b1dd958fScth * Record the reset notification requests from target drivers. 278*b1dd958fScth */ 279*b1dd958fScth struct emul64_reset_notify_entry { 280*b1dd958fScth struct scsi_address *ap; 281*b1dd958fScth void (*callback)(caddr_t); 282*b1dd958fScth caddr_t arg; 283*b1dd958fScth struct emul64_reset_notify_entry *next; 284*b1dd958fScth }; 285*b1dd958fScth 286*b1dd958fScth 287*b1dd958fScth struct emul64 { 288*b1dd958fScth 289*b1dd958fScth /* 290*b1dd958fScth * Transport structure for this instance of the hba 291*b1dd958fScth */ 292*b1dd958fScth scsi_hba_tran_t *emul64_tran; 293*b1dd958fScth 294*b1dd958fScth /* 295*b1dd958fScth * dev_info_t reference can be found in the transport structure 296*b1dd958fScth */ 297*b1dd958fScth dev_info_t *emul64_dip; 298*b1dd958fScth 299*b1dd958fScth /* 300*b1dd958fScth * Interrupt block cookie 301*b1dd958fScth */ 302*b1dd958fScth ddi_iblock_cookie_t emul64_iblock; 303*b1dd958fScth 304*b1dd958fScth /* 305*b1dd958fScth * Firmware revision number 306*b1dd958fScth */ 307*b1dd958fScth uint16_t emul64_major_rev; 308*b1dd958fScth uint16_t emul64_minor_rev; 309*b1dd958fScth 310*b1dd958fScth /* 311*b1dd958fScth * timeout id 312*b1dd958fScth */ 313*b1dd958fScth timeout_id_t emul64_timeout_id; 314*b1dd958fScth 315*b1dd958fScth /* 316*b1dd958fScth * scsi options, scsi_tag_age_limit per emul64 317*b1dd958fScth */ 318*b1dd958fScth int emul64_scsi_options; 319*b1dd958fScth int emul64_target_scsi_options[NTARGETS_WIDE]; 320*b1dd958fScth int emul64_scsi_tag_age_limit; 321*b1dd958fScth 322*b1dd958fScth /* 323*b1dd958fScth * scsi_reset_delay per emul64 324*b1dd958fScth */ 325*b1dd958fScth clock_t emul64_scsi_reset_delay; 326*b1dd958fScth 327*b1dd958fScth /* 328*b1dd958fScth * current host ID 329*b1dd958fScth */ 330*b1dd958fScth uint8_t emul64_initiator_id; 331*b1dd958fScth 332*b1dd958fScth /* 333*b1dd958fScth * suspended flag for power management 334*b1dd958fScth */ 335*b1dd958fScth uint8_t emul64_suspended; 336*b1dd958fScth 337*b1dd958fScth /* 338*b1dd958fScth * Host adapter capabilities and offset/period values per target 339*b1dd958fScth */ 340*b1dd958fScth uint16_t emul64_cap[NTARGETS_WIDE]; 341*b1dd958fScth int16_t emul64_synch[NTARGETS_WIDE]; 342*b1dd958fScth 343*b1dd958fScth /* 344*b1dd958fScth * EMUL64 Hardware register pointer. 345*b1dd958fScth */ 346*b1dd958fScth struct emul64regs *emul64_reg; 347*b1dd958fScth 348*b1dd958fScth 349*b1dd958fScth kmutex_t emul64_request_mutex; 350*b1dd958fScth kmutex_t emul64_response_mutex; 351*b1dd958fScth 352*b1dd958fScth /* 353*b1dd958fScth * for keeping track of the max LUNs per target on this bus 354*b1dd958fScth */ 355*b1dd958fScth uchar_t emul64_max_lun[NTARGETS_WIDE]; 356*b1dd958fScth 357*b1dd958fScth /* 358*b1dd958fScth * for keeping track of each target/lun 359*b1dd958fScth */ 360*b1dd958fScth int nt_total_sectors[NTARGETS_WIDE][EMUL64_NLUNS_PER_TARGET]; 361*b1dd958fScth 362*b1dd958fScth struct emul64_reset_notify_entry *emul64_reset_notify_listf; 363*b1dd958fScth 364*b1dd958fScth ushort_t emul64_backoff; 365*b1dd958fScth uint_t emul64_softstate; /* flags for hotplug */ 366*b1dd958fScth int emul64_hotplug_waiting; 367*b1dd958fScth kcondvar_t emul64_cv; /* cv for bus quiesce/unquiesce */ 368*b1dd958fScth kmutex_t emul64_hotplug_mutex; /* Mutex for hotplug */ 369*b1dd958fScth taskq_t *emul64_taskq; 370*b1dd958fScth emul64_tgt_t *emul64_tgt; 371*b1dd958fScth }; 372*b1dd958fScth 373*b1dd958fScth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 374*b1dd958fScth emul64::emul64_queue_space)) 375*b1dd958fScth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 376*b1dd958fScth emul64::emul64_request_in)) 377*b1dd958fScth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 378*b1dd958fScth emul64::emul64_request_out)) 379*b1dd958fScth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 380*b1dd958fScth emul64::emul64_request_ptr)) 381*b1dd958fScth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 382*b1dd958fScth emul64::emul64_mbox)) 383*b1dd958fScth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex, 384*b1dd958fScth emul64::emul64_slots)) 385*b1dd958fScth 386*b1dd958fScth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_response_mutex, 387*b1dd958fScth emul64::emul64_response_in)) 388*b1dd958fScth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_response_mutex, 389*b1dd958fScth emul64::emul64_response_out)) 390*b1dd958fScth _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_response_mutex, 391*b1dd958fScth emul64::emul64_response_ptr)) 392*b1dd958fScth 393*b1dd958fScth extern void emul64_bsd_init(); 394*b1dd958fScth extern void emul64_bsd_fini(); 395*b1dd958fScth extern void emul64_bsd_get_props(dev_info_t *); 396*b1dd958fScth 397*b1dd958fScth extern emul64_rng_overlap_t emul64_overlap(emul64_range_t *, 398*b1dd958fScth diskaddr_t, size_t); 399*b1dd958fScth extern int emul64_bsd_blkcompare(const void *, const void *); 400*b1dd958fScth extern int emul64debug; 401*b1dd958fScth extern long emul64_nowrite_count; 402*b1dd958fScth extern kmutex_t emul64_stats_mutex; 403*b1dd958fScth extern int emul64_collect_stats; 404*b1dd958fScth extern uint64_t emul64_taskq_max; 405*b1dd958fScth extern int emul64_max_task; 406*b1dd958fScth extern int emul64_task_nthreads; 407*b1dd958fScth 408*b1dd958fScth #ifdef __cplusplus 409*b1dd958fScth } 410*b1dd958fScth #endif 411*b1dd958fScth 412*b1dd958fScth #endif /* _SYS_SCSI_ADAPTERS_EMUL64VAR_H */ 413