1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2004-07 Applied Micro Circuits Corporation. 5 * Copyright (c) 2004-05 Vinod Kashyap 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32/* 33 * AMCC'S 3ware driver for 9000 series storage controllers. 34 * 35 * Author: Vinod Kashyap 36 * Modifications by: Adam Radford 37 */ 38 39 40 41#ifndef TW_CL_H 42 43#define TW_CL_H 44 45 46/* 47 * Common Layer internal macros, structures and functions. 48 */ 49 50 51#define TW_CLI_SECTOR_SIZE 0x200 52#define TW_CLI_REQUEST_TIMEOUT_PERIOD 60 /* seconds */ 53#define TW_CLI_RESET_TIMEOUT_PERIOD 60 /* seconds */ 54#define TW_CLI_MAX_RESET_ATTEMPTS 2 55 56/* Possible values of ctlr->ioctl_lock.lock. */ 57#define TW_CLI_LOCK_FREE 0x0 /* lock is free */ 58#define TW_CLI_LOCK_HELD 0x1 /* lock is held */ 59 60/* Possible values of req->state. */ 61#define TW_CLI_REQ_STATE_INIT 0x0 /* being initialized */ 62#define TW_CLI_REQ_STATE_BUSY 0x1 /* submitted to controller */ 63#define TW_CLI_REQ_STATE_PENDING 0x2 /* in pending queue */ 64#define TW_CLI_REQ_STATE_COMPLETE 0x3 /* completed by controller */ 65 66/* Possible values of req->flags. */ 67#define TW_CLI_REQ_FLAGS_7K (1<<0) /* 7000 cmd pkt */ 68#define TW_CLI_REQ_FLAGS_9K (1<<1) /* 9000 cmd pkt */ 69#define TW_CLI_REQ_FLAGS_INTERNAL (1<<2) /* internal request */ 70#define TW_CLI_REQ_FLAGS_PASSTHRU (1<<3) /* passthru request */ 71#define TW_CLI_REQ_FLAGS_EXTERNAL (1<<4) /* external request */ 72 73#ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE 74/* Register offsets in PCI config space. */ 75#define TW_CLI_PCI_CONFIG_COMMAND_OFFSET 0x4 /* cmd register offset */ 76#define TW_CLI_PCI_CONFIG_STATUS_OFFSET 0x6 /* status register offset */ 77#endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */ 78 79 80#ifdef TW_OSL_DEBUG 81struct tw_cli_q_stats { 82 TW_UINT32 cur_len;/* current # of entries in q */ 83 TW_UINT32 max_len; /* max # of entries in q, ever reached */ 84}; 85#endif /* TW_OSL_DEBUG */ 86 87 88/* Queues of CL internal request context packets. */ 89#define TW_CLI_FREE_Q 0 /* free q */ 90#define TW_CLI_BUSY_Q 1 /* q of reqs submitted to fw */ 91#define TW_CLI_PENDING_Q 2 /* q of reqs deferred due to 'q full' */ 92#define TW_CLI_COMPLETE_Q 3 /* q of reqs completed by fw */ 93#define TW_CLI_RESET_Q 4 /* q of reqs reset by timeout */ 94#define TW_CLI_Q_COUNT 5 /* total number of queues */ 95 96 97/* CL's internal request context. */ 98struct tw_cli_req_context { 99 struct tw_cl_req_handle *req_handle;/* handle to track requests between 100 OSL & CL */ 101 struct tw_cli_ctlr_context *ctlr; /* ptr to CL's controller context */ 102 struct tw_cl_command_packet *cmd_pkt;/* ptr to ctlr cmd pkt */ 103 TW_UINT64 cmd_pkt_phys; /* cmd pkt physical address */ 104 TW_VOID *data; /* ptr to data being passed to fw */ 105 TW_UINT32 length; /* length of data being passed to fw */ 106 TW_UINT64 data_phys; /* physical address of data */ 107 108 TW_UINT32 state; /* request state */ 109 TW_UINT32 flags; /* request flags */ 110 111 TW_UINT32 error_code; /* error encountered before submission 112 of request to fw, if any */ 113 114 TW_VOID *orig_req; /* ptr to original request for use 115 during callback */ 116 TW_VOID (*tw_cli_callback)(struct tw_cli_req_context *req); 117 /* CL internal callback */ 118 TW_UINT32 request_id; /* request id for tracking with fw */ 119 struct tw_cl_link link; /* to link this request in a list */ 120}; 121 122 123/* CL's internal controller context. */ 124struct tw_cli_ctlr_context { 125 struct tw_cl_ctlr_handle *ctlr_handle; /* handle to track ctlr between 126 OSL & CL. */ 127 struct tw_cli_req_context *req_ctxt_buf;/* pointer to the array of CL's 128 internal request context pkts */ 129 struct tw_cl_command_packet *cmd_pkt_buf;/* ptr to array of cmd pkts */ 130 131 TW_UINT64 cmd_pkt_phys; /* phys addr of cmd_pkt_buf */ 132 133 TW_UINT32 device_id; /* controller device id */ 134 TW_UINT32 arch_id; /* controller architecture id */ 135 TW_UINT8 active; /* Initialization done, and controller is active. */ 136 TW_UINT8 interrupts_enabled; /* Interrupts on controller enabled. */ 137 TW_UINT8 internal_req_busy; /* Data buffer for internal requests in use. */ 138 TW_UINT8 get_more_aens; /* More AEN's need to be retrieved. */ 139 TW_UINT8 reset_needed; /* Controller needs a soft reset. */ 140 TW_UINT8 reset_in_progress; /* Controller is being reset. */ 141 TW_UINT8 reset_phase1_in_progress; /* In 'phase 1' of reset. */ 142 TW_UINT32 flags; /* controller settings */ 143 TW_UINT32 sg_size_factor; /* SG element size should be a 144 multiple of this */ 145 146 /* Request queues and arrays. */ 147 struct tw_cl_link req_q_head[TW_CLI_Q_COUNT]; 148 149 TW_UINT8 *internal_req_data;/* internal req data buf */ 150 TW_UINT64 internal_req_data_phys;/* phys addr of internal 151 req data buf */ 152 TW_UINT32 max_simult_reqs; /* max simultaneous requests 153 supported */ 154 TW_UINT32 max_aens_supported;/* max AEN's supported */ 155 /* AEN handler fields. */ 156 struct tw_cl_event_packet *aen_queue; /* circular queue of AENs from 157 firmware/CL/OSL */ 158 TW_UINT32 aen_head; /* AEN queue head */ 159 TW_UINT32 aen_tail; /* AEN queue tail */ 160 TW_UINT32 aen_cur_seq_id; /* index of the last event+1 */ 161 TW_UINT32 aen_q_overflow; /* indicates if unretrieved 162 events were overwritten */ 163 TW_UINT32 aen_q_wrapped; /* indicates if AEN queue ever 164 wrapped */ 165 166 TW_UINT16 working_srl; /* driver & firmware negotiated 167 srl */ 168 TW_UINT16 working_branch; /* branch # of the firmware 169 that the driver is compatible with */ 170 TW_UINT16 working_build; /* build # of the firmware 171 that the driver is compatible with */ 172 TW_UINT16 fw_on_ctlr_srl; /* srl of running firmware */ 173 TW_UINT16 fw_on_ctlr_branch;/* branch # of running 174 firmware */ 175 TW_UINT16 fw_on_ctlr_build;/* build # of running 176 firmware */ 177 TW_UINT32 operating_mode; /* base mode/current mode */ 178 179 TW_INT32 host_intr_pending;/* host intr processing 180 needed */ 181 TW_INT32 attn_intr_pending;/* attn intr processing 182 needed */ 183 TW_INT32 cmd_intr_pending;/* cmd intr processing 184 needed */ 185 TW_INT32 resp_intr_pending;/* resp intr processing 186 needed */ 187 188 TW_LOCK_HANDLE gen_lock_handle;/* general purpose lock */ 189 TW_LOCK_HANDLE *gen_lock;/* ptr to general purpose lock */ 190 TW_LOCK_HANDLE io_lock_handle; /* lock held during cmd 191 submission */ 192 TW_LOCK_HANDLE *io_lock;/* ptr to lock held during cmd 193 submission */ 194 195#ifdef TW_OSL_CAN_SLEEP 196 TW_SLEEP_HANDLE sleep_handle; /* handle to co-ordinate sleeps 197 & wakeups */ 198#endif /* TW_OSL_CAN_SLEEP */ 199 200 struct { 201 TW_UINT32 lock; /* lock state */ 202 TW_TIME timeout; /* time at which the lock will 203 become available, even if not 204 explicitly released */ 205 } ioctl_lock; /* lock for use by user applications, for 206 synchronization between ioctl calls */ 207#ifdef TW_OSL_DEBUG 208 struct tw_cli_q_stats q_stats[TW_CLI_Q_COUNT];/* queue statistics */ 209#endif /* TW_OSL_DEBUG */ 210}; 211 212 213 214/* 215 * Queue primitives 216 */ 217 218#ifdef TW_OSL_DEBUG 219 220#define TW_CLI_Q_INIT(ctlr, q_type) do { \ 221 (ctlr)->q_stats[q_type].cur_len = 0; \ 222 (ctlr)->q_stats[q_type].max_len = 0; \ 223} while (0) 224 225 226#define TW_CLI_Q_INSERT(ctlr, q_type) do { \ 227 struct tw_cli_q_stats *q_stats = &((ctlr)->q_stats[q_type]); \ 228 \ 229 if (++(q_stats->cur_len) > q_stats->max_len) \ 230 q_stats->max_len = q_stats->cur_len; \ 231} while (0) 232 233 234#define TW_CLI_Q_REMOVE(ctlr, q_type) \ 235 (ctlr)->q_stats[q_type].cur_len-- 236 237#else /* TW_OSL_DEBUG */ 238 239#define TW_CLI_Q_INIT(ctlr, q_index) 240#define TW_CLI_Q_INSERT(ctlr, q_index) 241#define TW_CLI_Q_REMOVE(ctlr, q_index) 242 243#endif /* TW_OSL_DEBUG */ 244 245 246/* Initialize a queue of requests. */ 247static __inline TW_VOID 248tw_cli_req_q_init(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type) 249{ 250 TW_CL_Q_INIT(&(ctlr->req_q_head[q_type])); 251 TW_CLI_Q_INIT(ctlr, q_type); 252} 253 254 255 256/* Insert the given request at the head of the given queue (q_type). */ 257static __inline TW_VOID 258tw_cli_req_q_insert_head(struct tw_cli_req_context *req, TW_UINT8 q_type) 259{ 260 struct tw_cli_ctlr_context *ctlr = req->ctlr; 261 262 tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock); 263 TW_CL_Q_INSERT_HEAD(&(ctlr->req_q_head[q_type]), &(req->link)); 264 TW_CLI_Q_INSERT(ctlr, q_type); 265 tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock); 266} 267 268 269 270/* Insert the given request at the tail of the given queue (q_type). */ 271static __inline TW_VOID 272tw_cli_req_q_insert_tail(struct tw_cli_req_context *req, TW_UINT8 q_type) 273{ 274 struct tw_cli_ctlr_context *ctlr = req->ctlr; 275 276 tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock); 277 TW_CL_Q_INSERT_TAIL(&(ctlr->req_q_head[q_type]), &(req->link)); 278 TW_CLI_Q_INSERT(ctlr, q_type); 279 tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock); 280} 281 282 283 284/* Remove and return the request at the head of the given queue (q_type). */ 285static __inline struct tw_cli_req_context * 286tw_cli_req_q_remove_head(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type) 287{ 288 struct tw_cli_req_context *req = TW_CL_NULL; 289 struct tw_cl_link *link; 290 291 tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock); 292 if ((link = TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[q_type]))) != 293 TW_CL_NULL) { 294 req = TW_CL_STRUCT_HEAD(link, 295 struct tw_cli_req_context, link); 296 TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link)); 297 TW_CLI_Q_REMOVE(ctlr, q_type); 298 } 299 tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock); 300 return(req); 301} 302 303 304 305/* Remove the given request from the given queue (q_type). */ 306static __inline TW_VOID 307tw_cli_req_q_remove_item(struct tw_cli_req_context *req, TW_UINT8 q_type) 308{ 309 struct tw_cli_ctlr_context *ctlr = req->ctlr; 310 311 tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock); 312 TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link)); 313 TW_CLI_Q_REMOVE(ctlr, q_type); 314 tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock); 315} 316 317 318 319/* Create an event packet for an event/error posted by the controller. */ 320#define tw_cli_create_ctlr_event(ctlr, event_src, cmd_hdr) do { \ 321 TW_UINT8 severity = \ 322 GET_SEVERITY((cmd_hdr)->status_block.res__severity); \ 323 \ 324 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_TRUE, event_src, \ 325 (cmd_hdr)->status_block.error, \ 326 severity, \ 327 tw_cli_severity_string_table[severity], \ 328 (cmd_hdr)->err_specific_desc + \ 329 tw_osl_strlen((cmd_hdr)->err_specific_desc) + 1, \ 330 (cmd_hdr)->err_specific_desc); \ 331 /* Print 18 bytes of sense information. */ \ 332 tw_cli_dbg_printf(2, ctlr->ctlr_handle, \ 333 tw_osl_cur_func(), \ 334 "sense info: %x %x %x %x %x %x %x %x %x " \ 335 "%x %x %x %x %x %x %x %x %x", \ 336 (cmd_hdr)->sense_data[0], (cmd_hdr)->sense_data[1], \ 337 (cmd_hdr)->sense_data[2], (cmd_hdr)->sense_data[3], \ 338 (cmd_hdr)->sense_data[4], (cmd_hdr)->sense_data[5], \ 339 (cmd_hdr)->sense_data[6], (cmd_hdr)->sense_data[7], \ 340 (cmd_hdr)->sense_data[8], (cmd_hdr)->sense_data[9], \ 341 (cmd_hdr)->sense_data[10], (cmd_hdr)->sense_data[11], \ 342 (cmd_hdr)->sense_data[12], (cmd_hdr)->sense_data[13], \ 343 (cmd_hdr)->sense_data[14], (cmd_hdr)->sense_data[15], \ 344 (cmd_hdr)->sense_data[16], (cmd_hdr)->sense_data[17]); \ 345} while (0) 346 347 348 349#endif /* TW_CL_H */ 350