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