Print this page
5253 kmem_alloc/kmem_zalloc won't fail with KM_SLEEP
5254 getrbuf won't fail with KM_SLEEP
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 25 * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
26 26 * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
27 27 */
28 28
29 29 /*
30 30 * Copyright (c) 2000 to 2010, LSI Corporation.
31 31 * All rights reserved.
32 32 *
33 33 * Redistribution and use in source and binary forms of all code within
34 34 * this file that is exclusively owned by LSI, with or without
35 35 * modification, is permitted provided that, in addition to the CDDL 1.0
36 36 * License requirements, the following conditions are met:
37 37 *
38 38 * Neither the name of the author nor the names of its contributors may be
39 39 * used to endorse or promote products derived from this software without
40 40 * specific prior written permission.
41 41 *
42 42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
45 45 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
46 46 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
47 47 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
48 48 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
49 49 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
50 50 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
51 51 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
52 52 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
53 53 * DAMAGE.
54 54 */
55 55
56 56 /*
57 57 * mptsas_impl - This file contains all the basic functions for communicating
58 58 * to MPT based hardware.
59 59 */
60 60
61 61 #if defined(lint) || defined(DEBUG)
62 62 #define MPTSAS_DEBUG
63 63 #endif
64 64
65 65 /*
66 66 * standard header files
67 67 */
68 68 #include <sys/note.h>
69 69 #include <sys/scsi/scsi.h>
70 70 #include <sys/pci.h>
71 71
72 72 #pragma pack(1)
73 73 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
74 74 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
75 75 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
76 76 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
77 77 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
78 78 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
79 79 #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
80 80 #pragma pack()
81 81
82 82 /*
83 83 * private header files.
84 84 */
85 85 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
86 86 #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
87 87
88 88 /*
89 89 * FMA header files.
90 90 */
91 91 #include <sys/fm/io/ddi.h>
92 92
93 93 /*
94 94 * prototypes
95 95 */
96 96 static void mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd);
97 97 static void mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd);
98 98 static m_event_struct_t *mptsas_ioc_event_find_by_cmd(mptsas_t *mpt,
99 99 struct mptsas_cmd *cmd);
100 100
101 101 /*
102 102 * add ioc evnet cmd into the queue
103 103 */
104 104 static void
105 105 mptsas_ioc_event_cmdq_add(mptsas_t *mpt, m_event_struct_t *cmd)
106 106 {
107 107 if ((cmd->m_event_linkp = mpt->m_ioc_event_cmdq) == NULL) {
108 108 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
109 109 mpt->m_ioc_event_cmdq = cmd;
110 110 } else {
111 111 cmd->m_event_linkp = NULL;
112 112 *(mpt->m_ioc_event_cmdtail) = cmd;
113 113 mpt->m_ioc_event_cmdtail = &cmd->m_event_linkp;
114 114 }
115 115 }
116 116
117 117 /*
118 118 * remove specified cmd from the ioc event queue
119 119 */
120 120 static void
121 121 mptsas_ioc_event_cmdq_delete(mptsas_t *mpt, m_event_struct_t *cmd)
122 122 {
123 123 m_event_struct_t *prev = mpt->m_ioc_event_cmdq;
124 124 if (prev == cmd) {
125 125 if ((mpt->m_ioc_event_cmdq = cmd->m_event_linkp) == NULL) {
126 126 mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
127 127 }
128 128 cmd->m_event_linkp = NULL;
129 129 return;
130 130 }
131 131 while (prev != NULL) {
132 132 if (prev->m_event_linkp == cmd) {
133 133 prev->m_event_linkp = cmd->m_event_linkp;
134 134 if (cmd->m_event_linkp == NULL) {
135 135 mpt->m_ioc_event_cmdtail = &prev->m_event_linkp;
136 136 }
137 137
138 138 cmd->m_event_linkp = NULL;
139 139 return;
140 140 }
141 141 prev = prev->m_event_linkp;
142 142 }
143 143 }
144 144
145 145 static m_event_struct_t *
146 146 mptsas_ioc_event_find_by_cmd(mptsas_t *mpt, struct mptsas_cmd *cmd)
147 147 {
148 148 m_event_struct_t *ioc_cmd = NULL;
149 149
150 150 ioc_cmd = mpt->m_ioc_event_cmdq;
151 151 while (ioc_cmd != NULL) {
152 152 if (&(ioc_cmd->m_event_cmd) == cmd) {
153 153 return (ioc_cmd);
154 154 }
155 155 ioc_cmd = ioc_cmd->m_event_linkp;
156 156 }
157 157 ioc_cmd = NULL;
158 158 return (ioc_cmd);
159 159 }
160 160
161 161 void
162 162 mptsas_destroy_ioc_event_cmd(mptsas_t *mpt)
163 163 {
164 164 m_event_struct_t *ioc_cmd = NULL;
165 165 m_event_struct_t *ioc_cmd_tmp = NULL;
166 166 ioc_cmd = mpt->m_ioc_event_cmdq;
167 167
168 168 /*
169 169 * because the IOC event queue is resource of per instance for driver,
170 170 * it's not only ACK event commands used it, but also some others used
171 171 * it. We need destroy all ACK event commands when IOC reset, but can't
172 172 * disturb others.So we use filter to clear the ACK event cmd in ioc
173 173 * event queue, and other requests should be reserved, and they would
174 174 * be free by its owner.
175 175 */
176 176 while (ioc_cmd != NULL) {
177 177 if (ioc_cmd->m_event_cmd.cmd_flags & CFLAG_CMDACK) {
178 178 NDBG20(("destroy!! remove Ack Flag ioc_cmd\n"));
179 179 if ((mpt->m_ioc_event_cmdq =
180 180 ioc_cmd->m_event_linkp) == NULL)
181 181 mpt->m_ioc_event_cmdtail =
182 182 &mpt->m_ioc_event_cmdq;
183 183 ioc_cmd_tmp = ioc_cmd;
184 184 ioc_cmd = ioc_cmd->m_event_linkp;
185 185 kmem_free(ioc_cmd_tmp, M_EVENT_STRUCT_SIZE);
186 186 } else {
187 187 /*
188 188 * it's not ack cmd, so continue to check next one
189 189 */
190 190
191 191 NDBG20(("destroy!! it's not Ack Flag, continue\n"));
192 192 ioc_cmd = ioc_cmd->m_event_linkp;
193 193 }
194 194
195 195 }
196 196 }
197 197
198 198 void
199 199 mptsas_start_config_page_access(mptsas_t *mpt, mptsas_cmd_t *cmd)
200 200 {
201 201 pMpi2ConfigRequest_t request;
202 202 pMpi2SGESimple64_t sge;
203 203 struct scsi_pkt *pkt = cmd->cmd_pkt;
204 204 mptsas_config_request_t *config = pkt->pkt_ha_private;
205 205 uint8_t direction;
206 206 uint32_t length, flagslength, request_desc_low;
207 207
208 208 ASSERT(mutex_owned(&mpt->m_mutex));
209 209
210 210 /*
211 211 * Point to the correct message and clear it as well as the global
212 212 * config page memory.
213 213 */
214 214 request = (pMpi2ConfigRequest_t)(mpt->m_req_frame +
215 215 (mpt->m_req_frame_size * cmd->cmd_slot));
216 216 bzero(request, mpt->m_req_frame_size);
217 217
218 218 /*
219 219 * Form the request message.
220 220 */
221 221 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Function,
222 222 MPI2_FUNCTION_CONFIG);
223 223 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Action, config->action);
224 224 direction = MPI2_SGE_FLAGS_IOC_TO_HOST;
225 225 length = 0;
226 226 sge = (pMpi2SGESimple64_t)&request->PageBufferSGE;
227 227 if (config->action == MPI2_CONFIG_ACTION_PAGE_HEADER) {
228 228 if (config->page_type > MPI2_CONFIG_PAGETYPE_MASK) {
229 229 ddi_put8(mpt->m_acc_req_frame_hdl,
230 230 &request->Header.PageType,
231 231 MPI2_CONFIG_PAGETYPE_EXTENDED);
232 232 ddi_put8(mpt->m_acc_req_frame_hdl,
233 233 &request->ExtPageType, config->page_type);
234 234 } else {
235 235 ddi_put8(mpt->m_acc_req_frame_hdl,
236 236 &request->Header.PageType, config->page_type);
237 237 }
238 238 } else {
239 239 ddi_put8(mpt->m_acc_req_frame_hdl, &request->ExtPageType,
240 240 config->ext_page_type);
241 241 ddi_put16(mpt->m_acc_req_frame_hdl, &request->ExtPageLength,
242 242 config->ext_page_length);
243 243 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageType,
244 244 config->page_type);
245 245 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageLength,
246 246 config->page_length);
247 247 ddi_put8(mpt->m_acc_req_frame_hdl,
248 248 &request->Header.PageVersion, config->page_version);
249 249 if ((config->page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
250 250 MPI2_CONFIG_PAGETYPE_EXTENDED) {
251 251 length = config->ext_page_length * 4;
252 252 } else {
253 253 length = config->page_length * 4;
254 254 }
255 255
256 256 if (config->action == MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
257 257 direction = MPI2_SGE_FLAGS_HOST_TO_IOC;
258 258 }
259 259 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.Low,
260 260 (uint32_t)cmd->cmd_dma_addr);
261 261 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->Address.High,
262 262 (uint32_t)(cmd->cmd_dma_addr >> 32));
263 263 }
264 264 ddi_put8(mpt->m_acc_req_frame_hdl, &request->Header.PageNumber,
265 265 config->page_number);
266 266 ddi_put32(mpt->m_acc_req_frame_hdl, &request->PageAddress,
267 267 config->page_address);
268 268 flagslength = ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
269 269 MPI2_SGE_FLAGS_END_OF_BUFFER |
270 270 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
271 271 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
272 272 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
273 273 direction |
274 274 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
275 275 flagslength |= length;
276 276 ddi_put32(mpt->m_acc_req_frame_hdl, &sge->FlagsLength, flagslength);
277 277
278 278 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
279 279 DDI_DMA_SYNC_FORDEV);
280 280 request_desc_low = (cmd->cmd_slot << 16) +
281 281 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
282 282 cmd->cmd_rfm = NULL;
283 283 MPTSAS_START_CMD(mpt, request_desc_low, 0);
284 284 if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) !=
285 285 DDI_SUCCESS) ||
286 286 (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) !=
287 287 DDI_SUCCESS)) {
288 288 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
289 289 }
290 290 }
291 291
292 292 int
293 293 mptsas_access_config_page(mptsas_t *mpt, uint8_t action, uint8_t page_type,
294 294 uint8_t page_number, uint32_t page_address, int (*callback) (mptsas_t *,
295 295 caddr_t, ddi_acc_handle_t, uint16_t, uint32_t, va_list), ...)
296 296 {
297 297 va_list ap;
298 298 ddi_dma_attr_t attrs;
299 299 ddi_dma_cookie_t cookie;
300 300 ddi_acc_handle_t accessp;
301 301 size_t len = 0;
302 302 mptsas_config_request_t config;
303 303 int rval = DDI_SUCCESS, config_flags = 0;
304 304 mptsas_cmd_t *cmd;
305 305 struct scsi_pkt *pkt;
306 306 pMpi2ConfigReply_t reply;
307 307 uint16_t iocstatus = 0;
308 308 uint32_t iocloginfo;
309 309 caddr_t page_memp;
310 310 boolean_t free_dma = B_FALSE;
311 311
312 312 va_start(ap, callback);
313 313 ASSERT(mutex_owned(&mpt->m_mutex));
314 314
315 315 /*
316 316 * Get a command from the pool.
317 317 */
318 318 if ((rval = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
319 319 mptsas_log(mpt, CE_NOTE, "command pool is full for config "
320 320 "page request");
321 321 rval = DDI_FAILURE;
322 322 goto page_done;
323 323 }
324 324 config_flags |= MPTSAS_REQUEST_POOL_CMD;
325 325
326 326 bzero((caddr_t)cmd, sizeof (*cmd));
327 327 bzero((caddr_t)pkt, scsi_pkt_size());
328 328 bzero((caddr_t)&config, sizeof (config));
329 329
330 330 /*
331 331 * Save the data for this request to be used in the call to start the
332 332 * config header request.
333 333 */
334 334 config.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
335 335 config.page_type = page_type;
336 336 config.page_number = page_number;
337 337 config.page_address = page_address;
338 338
339 339 /*
340 340 * Form a blank cmd/pkt to store the acknowledgement message
341 341 */
342 342 pkt->pkt_ha_private = (opaque_t)&config;
343 343 pkt->pkt_flags = FLAG_HEAD;
344 344 pkt->pkt_time = 60;
345 345 cmd->cmd_pkt = pkt;
346 346 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_CONFIG;
347 347
348 348 /*
349 349 * Save the config header request message in a slot.
350 350 */
351 351 if (mptsas_save_cmd(mpt, cmd) == TRUE) {
352 352 cmd->cmd_flags |= CFLAG_PREPARED;
353 353 mptsas_start_config_page_access(mpt, cmd);
354 354 } else {
355 355 mptsas_waitq_add(mpt, cmd);
356 356 }
357 357
358 358 /*
359 359 * If this is a request for a RAID info page, or any page called during
360 360 * the RAID info page request, poll because these config page requests
361 361 * are nested. Poll to avoid data corruption due to one page's data
362 362 * overwriting the outer page request's data. This can happen when
363 363 * the mutex is released in cv_wait.
364 364 */
365 365 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
366 366 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
367 367 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
368 368 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
369 369 } else {
370 370 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
371 371 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
372 372 }
373 373 }
374 374
375 375 /*
376 376 * Check if the header request completed without timing out
377 377 */
378 378 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
379 379 mptsas_log(mpt, CE_WARN, "config header request timeout");
380 380 rval = DDI_FAILURE;
381 381 goto page_done;
382 382 }
383 383
384 384 /*
385 385 * cmd_rfm points to the reply message if a reply was given. Check the
386 386 * IOCStatus to make sure everything went OK with the header request.
387 387 */
388 388 if (cmd->cmd_rfm) {
389 389 config_flags |= MPTSAS_ADDRESS_REPLY;
390 390 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
391 391 DDI_DMA_SYNC_FORCPU);
392 392 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
393 393 - mpt->m_reply_frame_dma_addr));
394 394 config.page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
395 395 &reply->Header.PageType);
396 396 config.page_number = ddi_get8(mpt->m_acc_reply_frame_hdl,
397 397 &reply->Header.PageNumber);
398 398 config.page_length = ddi_get8(mpt->m_acc_reply_frame_hdl,
399 399 &reply->Header.PageLength);
400 400 config.page_version = ddi_get8(mpt->m_acc_reply_frame_hdl,
401 401 &reply->Header.PageVersion);
402 402 config.ext_page_type = ddi_get8(mpt->m_acc_reply_frame_hdl,
403 403 &reply->ExtPageType);
404 404 config.ext_page_length = ddi_get16(mpt->m_acc_reply_frame_hdl,
405 405 &reply->ExtPageLength);
406 406
407 407 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
408 408 &reply->IOCStatus);
409 409 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
410 410 &reply->IOCLogInfo);
411 411
412 412 if (iocstatus) {
413 413 NDBG13(("mptsas_access_config_page header: "
414 414 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
415 415 iocloginfo));
416 416 rval = DDI_FAILURE;
417 417 goto page_done;
418 418 }
419 419
420 420 if ((config.page_type & MPI2_CONFIG_PAGETYPE_MASK) ==
421 421 MPI2_CONFIG_PAGETYPE_EXTENDED)
422 422 len = (config.ext_page_length * 4);
423 423 else
424 424 len = (config.page_length * 4);
425 425
426 426 }
427 427
428 428 if (pkt->pkt_reason == CMD_RESET) {
429 429 mptsas_log(mpt, CE_WARN, "ioc reset abort config header "
430 430 "request");
431 431 rval = DDI_FAILURE;
432 432 goto page_done;
433 433 }
434 434
435 435 /*
436 436 * Put the reply frame back on the free queue, increment the free
437 437 * index, and write the new index to the free index register. But only
438 438 * if this reply is an ADDRESS reply.
439 439 */
440 440 if (config_flags & MPTSAS_ADDRESS_REPLY) {
441 441 ddi_put32(mpt->m_acc_free_queue_hdl,
442 442 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
443 443 cmd->cmd_rfm);
444 444 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
445 445 DDI_DMA_SYNC_FORDEV);
446 446 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
447 447 mpt->m_free_index = 0;
448 448 }
449 449 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
450 450 mpt->m_free_index);
451 451 config_flags &= (~MPTSAS_ADDRESS_REPLY);
452 452 }
453 453
454 454 /*
455 455 * Allocate DMA buffer here. Store the info regarding this buffer in
456 456 * the cmd struct so that it can be used for this specific command and
457 457 * de-allocated after the command completes. The size of the reply
458 458 * will not be larger than the reply frame size.
459 459 */
460 460 attrs = mpt->m_msg_dma_attr;
461 461 attrs.dma_attr_sgllen = 1;
462 462 attrs.dma_attr_granular = (uint32_t)len;
463 463
464 464 if (mptsas_dma_addr_create(mpt, attrs,
465 465 &cmd->cmd_dmahandle, &accessp, &page_memp,
466 466 len, &cookie) == FALSE) {
467 467 rval = DDI_FAILURE;
468 468 mptsas_log(mpt, CE_WARN,
469 469 "mptsas_dma_addr_create(len=0x%x) failed", (int)len);
470 470 goto page_done;
471 471 }
472 472 /* NOW we can safely call mptsas_dma_addr_destroy(). */
473 473 free_dma = B_TRUE;
474 474
475 475 cmd->cmd_dma_addr = cookie.dmac_laddress;
476 476 bzero(page_memp, len);
477 477
478 478 /*
479 479 * Save the data for this request to be used in the call to start the
480 480 * config page read
481 481 */
482 482 config.action = action;
483 483 config.page_address = page_address;
484 484
485 485 /*
486 486 * Re-use the cmd that was used to get the header. Reset some of the
487 487 * values.
488 488 */
489 489 bzero((caddr_t)pkt, scsi_pkt_size());
490 490 pkt->pkt_ha_private = (opaque_t)&config;
491 491 pkt->pkt_flags = FLAG_HEAD;
492 492 pkt->pkt_time = 60;
493 493 cmd->cmd_flags = CFLAG_PREPARED | CFLAG_CMDIOC | CFLAG_CONFIG;
494 494
495 495 /*
496 496 * Send the config page request. cmd is re-used from header request.
497 497 */
498 498 mptsas_start_config_page_access(mpt, cmd);
499 499
500 500 /*
501 501 * If this is a request for a RAID info page, or any page called during
502 502 * the RAID info page request, poll because these config page requests
503 503 * are nested. Poll to avoid data corruption due to one page's data
504 504 * overwriting the outer page request's data. This can happen when
505 505 * the mutex is released in cv_wait.
506 506 */
507 507 if ((page_type == MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG) ||
508 508 (page_type == MPI2_CONFIG_PAGETYPE_RAID_VOLUME) ||
509 509 (page_type == MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK)) {
510 510 (void) mptsas_poll(mpt, cmd, pkt->pkt_time * 1000);
511 511 } else {
512 512 while ((cmd->cmd_flags & CFLAG_FINISHED) == 0) {
513 513 cv_wait(&mpt->m_config_cv, &mpt->m_mutex);
514 514 }
515 515 }
516 516
517 517 /*
518 518 * Check if the request completed without timing out
519 519 */
520 520 if (cmd->cmd_flags & CFLAG_TIMEOUT) {
521 521 mptsas_log(mpt, CE_WARN, "config page request timeout");
522 522 rval = DDI_FAILURE;
523 523 goto page_done;
524 524 }
525 525
526 526 /*
527 527 * cmd_rfm points to the reply message if a reply was given. The reply
528 528 * frame and the config page are returned from this function in the
529 529 * param list.
530 530 */
531 531 if (cmd->cmd_rfm) {
532 532 config_flags |= MPTSAS_ADDRESS_REPLY;
533 533 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
534 534 DDI_DMA_SYNC_FORCPU);
535 535 (void) ddi_dma_sync(cmd->cmd_dmahandle, 0, 0,
536 536 DDI_DMA_SYNC_FORCPU);
537 537 reply = (pMpi2ConfigReply_t)(mpt->m_reply_frame + (cmd->cmd_rfm
538 538 - mpt->m_reply_frame_dma_addr));
539 539 iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
540 540 &reply->IOCStatus);
541 541 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
542 542 iocloginfo = ddi_get32(mpt->m_acc_reply_frame_hdl,
543 543 &reply->IOCLogInfo);
544 544 }
545 545
546 546 if (callback(mpt, page_memp, accessp, iocstatus, iocloginfo, ap)) {
547 547 rval = DDI_FAILURE;
548 548 goto page_done;
549 549 }
550 550
551 551 mptsas_fma_check(mpt, cmd);
552 552 /*
553 553 * Check the DMA/ACC handles and then free the DMA buffer.
554 554 */
555 555 if ((mptsas_check_dma_handle(cmd->cmd_dmahandle) != DDI_SUCCESS) ||
556 556 (mptsas_check_acc_handle(accessp) != DDI_SUCCESS)) {
557 557 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
558 558 rval = DDI_FAILURE;
559 559 }
560 560
561 561 if (pkt->pkt_reason == CMD_TRAN_ERR) {
562 562 mptsas_log(mpt, CE_WARN, "config fma error");
563 563 rval = DDI_FAILURE;
564 564 goto page_done;
565 565 }
566 566 if (pkt->pkt_reason == CMD_RESET) {
567 567 mptsas_log(mpt, CE_WARN, "ioc reset abort config request");
568 568 rval = DDI_FAILURE;
569 569 goto page_done;
570 570 }
571 571
572 572 page_done:
573 573 va_end(ap);
574 574 /*
575 575 * Put the reply frame back on the free queue, increment the free
576 576 * index, and write the new index to the free index register. But only
577 577 * if this reply is an ADDRESS reply.
578 578 */
579 579 if (config_flags & MPTSAS_ADDRESS_REPLY) {
580 580 ddi_put32(mpt->m_acc_free_queue_hdl,
581 581 &((uint32_t *)(void *)mpt->m_free_queue)[mpt->m_free_index],
582 582 cmd->cmd_rfm);
583 583 (void) ddi_dma_sync(mpt->m_dma_free_queue_hdl, 0, 0,
584 584 DDI_DMA_SYNC_FORDEV);
585 585 if (++mpt->m_free_index == mpt->m_free_queue_depth) {
586 586 mpt->m_free_index = 0;
587 587 }
588 588 ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex,
589 589 mpt->m_free_index);
590 590 }
591 591
592 592 if (free_dma)
593 593 mptsas_dma_addr_destroy(&cmd->cmd_dmahandle, &accessp);
594 594
595 595 if (cmd && (cmd->cmd_flags & CFLAG_PREPARED)) {
596 596 mptsas_remove_cmd(mpt, cmd);
597 597 config_flags &= (~MPTSAS_REQUEST_POOL_CMD);
598 598 }
599 599 if (config_flags & MPTSAS_REQUEST_POOL_CMD)
600 600 mptsas_return_to_pool(mpt, cmd);
601 601
602 602 if (config_flags & MPTSAS_CMD_TIMEOUT) {
603 603 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
604 604 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
605 605 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
606 606 }
607 607 }
608 608
609 609 return (rval);
610 610 }
611 611
612 612 int
613 613 mptsas_send_config_request_msg(mptsas_t *mpt, uint8_t action, uint8_t pagetype,
614 614 uint32_t pageaddress, uint8_t pagenumber, uint8_t pageversion,
615 615 uint8_t pagelength, uint32_t SGEflagslength, uint32_t SGEaddress32)
616 616 {
617 617 pMpi2ConfigRequest_t config;
618 618 int send_numbytes;
619 619
620 620 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
621 621 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
622 622 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
623 623 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
624 624 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
625 625 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType, pagetype);
626 626 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
627 627 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
628 628 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageLength, pagelength);
629 629 ddi_put32(mpt->m_hshk_acc_hdl,
630 630 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
631 631 ddi_put32(mpt->m_hshk_acc_hdl,
632 632 &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
633 633 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
634 634
635 635 /*
636 636 * Post message via handshake
637 637 */
638 638 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
639 639 mpt->m_hshk_acc_hdl)) {
640 640 return (-1);
641 641 }
642 642 return (0);
643 643 }
644 644
645 645 int
646 646 mptsas_send_extended_config_request_msg(mptsas_t *mpt, uint8_t action,
647 647 uint8_t extpagetype, uint32_t pageaddress, uint8_t pagenumber,
648 648 uint8_t pageversion, uint16_t extpagelength,
649 649 uint32_t SGEflagslength, uint32_t SGEaddress32)
650 650 {
651 651 pMpi2ConfigRequest_t config;
652 652 int send_numbytes;
653 653
654 654 bzero(mpt->m_hshk_memp, sizeof (MPI2_CONFIG_REQUEST));
655 655 config = (pMpi2ConfigRequest_t)mpt->m_hshk_memp;
656 656 ddi_put8(mpt->m_hshk_acc_hdl, &config->Function, MPI2_FUNCTION_CONFIG);
657 657 ddi_put8(mpt->m_hshk_acc_hdl, &config->Action, action);
658 658 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageNumber, pagenumber);
659 659 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageType,
660 660 MPI2_CONFIG_PAGETYPE_EXTENDED);
661 661 ddi_put8(mpt->m_hshk_acc_hdl, &config->ExtPageType, extpagetype);
662 662 ddi_put32(mpt->m_hshk_acc_hdl, &config->PageAddress, pageaddress);
663 663 ddi_put8(mpt->m_hshk_acc_hdl, &config->Header.PageVersion, pageversion);
664 664 ddi_put16(mpt->m_hshk_acc_hdl, &config->ExtPageLength, extpagelength);
665 665 ddi_put32(mpt->m_hshk_acc_hdl,
666 666 &config->PageBufferSGE.MpiSimple.FlagsLength, SGEflagslength);
667 667 ddi_put32(mpt->m_hshk_acc_hdl,
668 668 &config->PageBufferSGE.MpiSimple.u.Address32, SGEaddress32);
669 669 send_numbytes = sizeof (MPI2_CONFIG_REQUEST);
670 670
671 671 /*
672 672 * Post message via handshake
673 673 */
674 674 if (mptsas_send_handshake_msg(mpt, (caddr_t)config, send_numbytes,
675 675 mpt->m_hshk_acc_hdl)) {
676 676 return (-1);
677 677 }
678 678 return (0);
679 679 }
680 680
681 681 int
682 682 mptsas_ioc_wait_for_response(mptsas_t *mpt)
683 683 {
684 684 int polls = 0;
685 685
686 686 while ((ddi_get32(mpt->m_datap,
687 687 &mpt->m_reg->HostInterruptStatus) & MPI2_HIS_IOP_DOORBELL_STATUS)) {
688 688 drv_usecwait(1000);
689 689 if (polls++ > 60000) {
690 690 return (-1);
691 691 }
692 692 }
693 693 return (0);
694 694 }
695 695
696 696 int
697 697 mptsas_ioc_wait_for_doorbell(mptsas_t *mpt)
698 698 {
699 699 int polls = 0;
700 700
701 701 while ((ddi_get32(mpt->m_datap,
702 702 &mpt->m_reg->HostInterruptStatus) & MPI2_HIM_DIM) == 0) {
703 703 drv_usecwait(1000);
704 704 if (polls++ > 300000) {
705 705 return (-1);
706 706 }
707 707 }
708 708 return (0);
709 709 }
710 710
711 711 int
712 712 mptsas_send_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
713 713 ddi_acc_handle_t accessp)
714 714 {
715 715 int i;
716 716
717 717 /*
718 718 * clean pending doorbells
719 719 */
720 720 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
721 721 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
722 722 ((MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) |
723 723 ((numbytes / 4) << MPI2_DOORBELL_ADD_DWORDS_SHIFT)));
724 724
725 725 if (mptsas_ioc_wait_for_doorbell(mpt)) {
726 726 NDBG19(("mptsas_send_handshake failed. Doorbell not ready\n"));
727 727 return (-1);
728 728 }
729 729
730 730 /*
731 731 * clean pending doorbells again
732 732 */
733 733 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
734 734
735 735 if (mptsas_ioc_wait_for_response(mpt)) {
736 736 NDBG19(("mptsas_send_handshake failed. Doorbell not "
737 737 "cleared\n"));
738 738 return (-1);
739 739 }
740 740
741 741 /*
742 742 * post handshake message
743 743 */
744 744 for (i = 0; (i < numbytes / 4); i++, memp += 4) {
745 745 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
746 746 ddi_get32(accessp, (uint32_t *)((void *)(memp))));
747 747 if (mptsas_ioc_wait_for_response(mpt)) {
748 748 NDBG19(("mptsas_send_handshake failed posting "
749 749 "message\n"));
750 750 return (-1);
751 751 }
752 752 }
753 753
754 754 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
755 755 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
756 756 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
757 757 return (-1);
758 758 }
759 759
760 760 return (0);
761 761 }
762 762
763 763 int
764 764 mptsas_get_handshake_msg(mptsas_t *mpt, caddr_t memp, int numbytes,
765 765 ddi_acc_handle_t accessp)
766 766 {
767 767 int i, totalbytes, bytesleft;
768 768 uint16_t val;
769 769
770 770 /*
771 771 * wait for doorbell
772 772 */
773 773 if (mptsas_ioc_wait_for_doorbell(mpt)) {
774 774 NDBG19(("mptsas_get_handshake failed. Doorbell not ready\n"));
775 775 return (-1);
776 776 }
777 777
778 778 /*
779 779 * get first 2 bytes of handshake message to determine how much
780 780 * data we will be getting
781 781 */
782 782 for (i = 0; i < 2; i++, memp += 2) {
783 783 val = (ddi_get32(mpt->m_datap,
784 784 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
785 785 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
786 786 if (mptsas_ioc_wait_for_doorbell(mpt)) {
787 787 NDBG19(("mptsas_get_handshake failure getting initial"
788 788 " data\n"));
789 789 return (-1);
790 790 }
791 791 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
792 792 if (i == 1) {
793 793 totalbytes = (val & 0xFF) * 2;
794 794 }
795 795 }
796 796
797 797 /*
798 798 * If we are expecting less bytes than the message wants to send
799 799 * we simply save as much as we expected and then throw out the rest
800 800 * later
801 801 */
802 802 if (totalbytes > (numbytes / 2)) {
803 803 bytesleft = ((numbytes / 2) - 2);
804 804 } else {
805 805 bytesleft = (totalbytes - 2);
806 806 }
807 807
808 808 /*
809 809 * Get the rest of the data
810 810 */
811 811 for (i = 0; i < bytesleft; i++, memp += 2) {
812 812 val = (ddi_get32(mpt->m_datap,
813 813 &mpt->m_reg->Doorbell) & MPI2_DOORBELL_DATA_MASK);
814 814 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
815 815 if (mptsas_ioc_wait_for_doorbell(mpt)) {
816 816 NDBG19(("mptsas_get_handshake failure getting"
817 817 " main data\n"));
818 818 return (-1);
819 819 }
820 820 ddi_put16(accessp, (uint16_t *)((void *)(memp)), val);
821 821 }
822 822
823 823 /*
824 824 * Sometimes the device will send more data than is expected
825 825 * This data is not used by us but needs to be cleared from
826 826 * ioc doorbell. So we just read the values and throw
827 827 * them out.
828 828 */
829 829 if (totalbytes > (numbytes / 2)) {
830 830 for (i = (numbytes / 2); i < totalbytes; i++) {
831 831 val = (ddi_get32(mpt->m_datap,
832 832 &mpt->m_reg->Doorbell) &
833 833 MPI2_DOORBELL_DATA_MASK);
834 834 ddi_put32(mpt->m_datap,
835 835 &mpt->m_reg->HostInterruptStatus, 0);
836 836 if (mptsas_ioc_wait_for_doorbell(mpt)) {
837 837 NDBG19(("mptsas_get_handshake failure getting "
838 838 "extra garbage data\n"));
839 839 return (-1);
840 840 }
841 841 }
842 842 }
843 843
844 844 ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptStatus, 0);
845 845
846 846 if (mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) {
847 847 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
848 848 ddi_fm_acc_err_clear(mpt->m_datap, DDI_FME_VER0);
849 849 return (-1);
850 850 }
851 851
852 852 return (0);
853 853 }
854 854
855 855 int
856 856 mptsas_kick_start(mptsas_t *mpt)
857 857 {
858 858 int polls = 0;
859 859 uint32_t diag_reg, ioc_state, saved_HCB_size;
860 860
861 861 /*
862 862 * Start a hard reset. Write magic number and wait 500 mSeconds.
863 863 */
864 864 MPTSAS_ENABLE_DRWE(mpt);
865 865 drv_usecwait(500000);
866 866
867 867 /*
868 868 * Read the current Diag Reg and save the Host Controlled Boot size.
869 869 */
870 870 diag_reg = ddi_get32(mpt->m_datap, &mpt->m_reg->HostDiagnostic);
871 871 saved_HCB_size = ddi_get32(mpt->m_datap, &mpt->m_reg->HCBSize);
872 872
873 873 /*
874 874 * Set Reset Adapter bit and wait 50 mSeconds.
875 875 */
876 876 diag_reg |= MPI2_DIAG_RESET_ADAPTER;
877 877 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
878 878 drv_usecwait(50000);
879 879
880 880 /*
881 881 * Poll, waiting for Reset Adapter bit to clear. 300 Seconds max
882 882 * (600000 * 500 = 300,000,000 uSeconds, 300 seconds).
883 883 * If no more adapter (all FF's), just return failure.
884 884 */
885 885 for (polls = 0; polls < 600000; polls++) {
886 886 diag_reg = ddi_get32(mpt->m_datap,
887 887 &mpt->m_reg->HostDiagnostic);
888 888 if (diag_reg == 0xFFFFFFFF) {
889 889 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
890 890 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
891 891 return (DDI_FAILURE);
892 892 }
893 893 if (!(diag_reg & MPI2_DIAG_RESET_ADAPTER)) {
894 894 break;
895 895 }
896 896 drv_usecwait(500);
897 897 }
898 898 if (polls == 600000) {
899 899 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
900 900 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
901 901 return (DDI_FAILURE);
902 902 }
903 903
904 904 /*
905 905 * Check if adapter is in Host Boot Mode. If so, restart adapter
906 906 * assuming the HCB points to good FW.
907 907 * Set BootDeviceSel to HCDW (Host Code and Data Window).
908 908 */
909 909 if (diag_reg & MPI2_DIAG_HCB_MODE) {
910 910 diag_reg &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
911 911 diag_reg |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
912 912 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
913 913
914 914 /*
915 915 * Re-enable the HCDW.
916 916 */
917 917 ddi_put32(mpt->m_datap, &mpt->m_reg->HCBSize,
918 918 (saved_HCB_size | MPI2_HCB_SIZE_HCB_ENABLE));
919 919 }
920 920
921 921 /*
922 922 * Restart the adapter.
923 923 */
924 924 diag_reg &= ~MPI2_DIAG_HOLD_IOC_RESET;
925 925 ddi_put32(mpt->m_datap, &mpt->m_reg->HostDiagnostic, diag_reg);
926 926
927 927 /*
928 928 * Disable writes to the Host Diag register.
929 929 */
930 930 ddi_put32(mpt->m_datap, &mpt->m_reg->WriteSequence,
931 931 MPI2_WRSEQ_FLUSH_KEY_VALUE);
932 932
933 933 /*
934 934 * Wait 60 seconds max for FW to come to ready state.
935 935 */
936 936 for (polls = 0; polls < 60000; polls++) {
937 937 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
938 938 if (ioc_state == 0xFFFFFFFF) {
939 939 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
940 940 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
941 941 return (DDI_FAILURE);
942 942 }
943 943 if ((ioc_state & MPI2_IOC_STATE_MASK) ==
944 944 MPI2_IOC_STATE_READY) {
945 945 break;
946 946 }
947 947 drv_usecwait(1000);
948 948 }
949 949 if (polls == 60000) {
950 950 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
951 951 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
952 952 return (DDI_FAILURE);
953 953 }
954 954
955 955 /*
956 956 * Clear the ioc ack events queue.
957 957 */
958 958 mptsas_destroy_ioc_event_cmd(mpt);
959 959
960 960 return (DDI_SUCCESS);
961 961 }
962 962
963 963 int
964 964 mptsas_ioc_reset(mptsas_t *mpt, int first_time)
965 965 {
966 966 int polls = 0;
967 967 uint32_t reset_msg;
968 968 uint32_t ioc_state;
969 969
970 970 ioc_state = ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell);
971 971 /*
972 972 * If chip is already in ready state then there is nothing to do.
973 973 */
974 974 if (ioc_state == MPI2_IOC_STATE_READY) {
975 975 return (MPTSAS_NO_RESET);
976 976 }
977 977 /*
978 978 * If the chip is already operational, we just need to send
979 979 * it a message unit reset to put it back in the ready state
980 980 */
981 981 if (ioc_state & MPI2_IOC_STATE_OPERATIONAL) {
982 982 /*
983 983 * If the first time, try MUR anyway, because we haven't even
984 984 * queried the card for m_event_replay and other capabilities.
985 985 * Other platforms do it this way, we can still do a hard
986 986 * reset if we need to, MUR takes less time than a full
987 987 * adapter reset, and there are reports that some HW
988 988 * combinations will lock up when receiving a hard reset.
989 989 */
990 990 if ((first_time || mpt->m_event_replay) &&
991 991 (mpt->m_softstate & MPTSAS_SS_MSG_UNIT_RESET)) {
992 992 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
993 993 reset_msg = MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET;
994 994 ddi_put32(mpt->m_datap, &mpt->m_reg->Doorbell,
995 995 (reset_msg << MPI2_DOORBELL_FUNCTION_SHIFT));
996 996 if (mptsas_ioc_wait_for_response(mpt)) {
997 997 NDBG19(("mptsas_ioc_reset failure sending "
998 998 "message_unit_reset\n"));
999 999 goto hard_reset;
1000 1000 }
1001 1001
1002 1002 /*
1003 1003 * Wait no more than 60 seconds for chip to become
1004 1004 * ready.
1005 1005 */
1006 1006 while ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell) &
1007 1007 MPI2_IOC_STATE_READY) == 0x0) {
1008 1008 drv_usecwait(1000);
1009 1009 if (polls++ > 60000) {
1010 1010 goto hard_reset;
1011 1011 }
1012 1012 }
1013 1013
1014 1014 /*
1015 1015 * Save the last reset mode done on IOC which will be
1016 1016 * helpful while resuming from suspension.
1017 1017 */
1018 1018 mpt->m_softstate |= MPTSAS_DID_MSG_UNIT_RESET;
1019 1019
1020 1020 /*
1021 1021 * the message unit reset would do reset operations
1022 1022 * clear reply and request queue, so we should clear
1023 1023 * ACK event cmd.
1024 1024 */
1025 1025 mptsas_destroy_ioc_event_cmd(mpt);
1026 1026 return (MPTSAS_SUCCESS_MUR);
1027 1027 }
1028 1028 }
1029 1029 hard_reset:
1030 1030 mpt->m_softstate &= ~MPTSAS_DID_MSG_UNIT_RESET;
1031 1031 if (mptsas_kick_start(mpt) == DDI_FAILURE) {
1032 1032 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
1033 1033 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
1034 1034 return (MPTSAS_RESET_FAIL);
1035 1035 }
1036 1036 return (MPTSAS_SUCCESS_HARDRESET);
↓ open down ↓ |
1036 lines elided |
↑ open up ↑ |
1037 1037 }
1038 1038
1039 1039
1040 1040 int
1041 1041 mptsas_request_from_pool(mptsas_t *mpt, mptsas_cmd_t **cmd,
1042 1042 struct scsi_pkt **pkt)
1043 1043 {
1044 1044 m_event_struct_t *ioc_cmd = NULL;
1045 1045
1046 1046 ioc_cmd = kmem_zalloc(M_EVENT_STRUCT_SIZE, KM_SLEEP);
1047 - if (ioc_cmd == NULL) {
1048 - return (DDI_FAILURE);
1049 - }
1050 1047 ioc_cmd->m_event_linkp = NULL;
1051 1048 mptsas_ioc_event_cmdq_add(mpt, ioc_cmd);
1052 1049 *cmd = &(ioc_cmd->m_event_cmd);
1053 1050 *pkt = &(ioc_cmd->m_event_pkt);
1054 1051
1055 1052 return (DDI_SUCCESS);
1056 1053 }
1057 1054
1058 1055 void
1059 1056 mptsas_return_to_pool(mptsas_t *mpt, mptsas_cmd_t *cmd)
1060 1057 {
1061 1058 m_event_struct_t *ioc_cmd = NULL;
1062 1059
1063 1060 ioc_cmd = mptsas_ioc_event_find_by_cmd(mpt, cmd);
1064 1061 if (ioc_cmd == NULL) {
1065 1062 return;
1066 1063 }
1067 1064
1068 1065 mptsas_ioc_event_cmdq_delete(mpt, ioc_cmd);
1069 1066 kmem_free(ioc_cmd, M_EVENT_STRUCT_SIZE);
1070 1067 ioc_cmd = NULL;
1071 1068 }
1072 1069
1073 1070 /*
1074 1071 * NOTE: We should be able to queue TM requests in the controller to make this
1075 1072 * a lot faster. If resetting all targets, for example, we can load the hi
1076 1073 * priority queue with its limit and the controller will reply as they are
1077 1074 * completed. This way, we don't have to poll for one reply at a time.
1078 1075 * Think about enhancing this later.
1079 1076 */
1080 1077 int
1081 1078 mptsas_ioc_task_management(mptsas_t *mpt, int task_type, uint16_t dev_handle,
1082 1079 int lun, uint8_t *reply, uint32_t reply_size, int mode)
1083 1080 {
1084 1081 /*
1085 1082 * In order to avoid allocating variables on the stack,
1086 1083 * we make use of the pre-existing mptsas_cmd_t and
1087 1084 * scsi_pkt which are included in the mptsas_t which
1088 1085 * is passed to this routine.
1089 1086 */
1090 1087
1091 1088 pMpi2SCSITaskManagementRequest_t task;
1092 1089 int rval = FALSE;
1093 1090 mptsas_cmd_t *cmd;
1094 1091 struct scsi_pkt *pkt;
1095 1092 mptsas_slots_t *slots = mpt->m_active;
1096 1093 uint32_t request_desc_low, i;
1097 1094 pMPI2DefaultReply_t reply_msg;
1098 1095
1099 1096 /*
1100 1097 * Can't start another task management routine.
1101 1098 */
1102 1099 if (slots->m_slot[MPTSAS_TM_SLOT(mpt)] != NULL) {
1103 1100 mptsas_log(mpt, CE_WARN, "Can only start 1 task management"
1104 1101 " command at a time\n");
1105 1102 return (FALSE);
1106 1103 }
1107 1104
1108 1105 cmd = &(mpt->m_event_task_mgmt.m_event_cmd);
1109 1106 pkt = &(mpt->m_event_task_mgmt.m_event_pkt);
1110 1107
1111 1108 bzero((caddr_t)cmd, sizeof (*cmd));
1112 1109 bzero((caddr_t)pkt, scsi_pkt_size());
1113 1110
1114 1111 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1115 1112 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1116 1113 pkt->pkt_ha_private = (opaque_t)cmd;
1117 1114 pkt->pkt_flags = (FLAG_NOINTR | FLAG_HEAD);
1118 1115 pkt->pkt_time = 60;
1119 1116 pkt->pkt_address.a_target = dev_handle;
1120 1117 pkt->pkt_address.a_lun = (uchar_t)lun;
1121 1118 cmd->cmd_pkt = pkt;
1122 1119 cmd->cmd_scblen = 1;
1123 1120 cmd->cmd_flags = CFLAG_TM_CMD;
1124 1121 cmd->cmd_slot = MPTSAS_TM_SLOT(mpt);
1125 1122
1126 1123 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = cmd;
1127 1124
1128 1125 /*
1129 1126 * Store the TM message in memory location corresponding to the TM slot
1130 1127 * number.
1131 1128 */
1132 1129 task = (pMpi2SCSITaskManagementRequest_t)(mpt->m_req_frame +
1133 1130 (mpt->m_req_frame_size * cmd->cmd_slot));
1134 1131 bzero(task, mpt->m_req_frame_size);
1135 1132
1136 1133 /*
1137 1134 * form message for requested task
1138 1135 */
1139 1136 mptsas_init_std_hdr(mpt->m_acc_req_frame_hdl, task, dev_handle, lun, 0,
1140 1137 MPI2_FUNCTION_SCSI_TASK_MGMT);
1141 1138
1142 1139 /*
1143 1140 * Set the task type
1144 1141 */
1145 1142 ddi_put8(mpt->m_acc_req_frame_hdl, &task->TaskType, task_type);
1146 1143
1147 1144 /*
1148 1145 * Send TM request using High Priority Queue.
1149 1146 */
1150 1147 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1151 1148 DDI_DMA_SYNC_FORDEV);
1152 1149 request_desc_low = (cmd->cmd_slot << 16) +
1153 1150 MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
1154 1151 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1155 1152 rval = mptsas_poll(mpt, cmd, MPTSAS_POLL_TIME);
1156 1153
1157 1154 if (pkt->pkt_reason == CMD_INCOMPLETE)
1158 1155 rval = FALSE;
1159 1156
1160 1157 /*
1161 1158 * If a reply frame was used and there is a reply buffer to copy the
1162 1159 * reply data into, copy it. If this fails, log a message, but don't
1163 1160 * fail the TM request.
1164 1161 */
1165 1162 if (cmd->cmd_rfm && reply) {
1166 1163 (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0,
1167 1164 DDI_DMA_SYNC_FORCPU);
1168 1165 reply_msg = (pMPI2DefaultReply_t)
1169 1166 (mpt->m_reply_frame + (cmd->cmd_rfm -
1170 1167 mpt->m_reply_frame_dma_addr));
1171 1168 if (reply_size > sizeof (MPI2_SCSI_TASK_MANAGE_REPLY)) {
1172 1169 reply_size = sizeof (MPI2_SCSI_TASK_MANAGE_REPLY);
1173 1170 }
1174 1171 mutex_exit(&mpt->m_mutex);
1175 1172 for (i = 0; i < reply_size; i++) {
1176 1173 if (ddi_copyout((uint8_t *)reply_msg + i, reply + i, 1,
1177 1174 mode)) {
1178 1175 mptsas_log(mpt, CE_WARN, "failed to copy out "
1179 1176 "reply data for TM request");
1180 1177 break;
1181 1178 }
1182 1179 }
1183 1180 mutex_enter(&mpt->m_mutex);
1184 1181 }
1185 1182
1186 1183 /*
1187 1184 * clear the TM slot before returning
1188 1185 */
1189 1186 slots->m_slot[MPTSAS_TM_SLOT(mpt)] = NULL;
1190 1187
1191 1188 /*
1192 1189 * If we lost our task management command
1193 1190 * we need to reset the ioc
1194 1191 */
1195 1192 if (rval == FALSE) {
1196 1193 mptsas_log(mpt, CE_WARN, "mptsas_ioc_task_management failed "
1197 1194 "try to reset ioc to recovery!");
1198 1195 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1199 1196 if (mptsas_restart_ioc(mpt)) {
1200 1197 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1201 1198 rval = FAILED;
1202 1199 }
1203 1200 }
1204 1201
1205 1202 return (rval);
1206 1203 }
1207 1204
1208 1205 /*
1209 1206 * Complete firmware download frame for v2.0 cards.
1210 1207 */
1211 1208 static void
1212 1209 mptsas_uflash2(pMpi2FWDownloadRequest fwdownload,
1213 1210 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1214 1211 ddi_dma_cookie_t flsh_cookie)
1215 1212 {
1216 1213 pMpi2FWDownloadTCSGE_t tcsge;
1217 1214 pMpi2SGESimple64_t sge;
1218 1215 uint32_t flagslength;
1219 1216
1220 1217 ddi_put8(acc_hdl, &fwdownload->Function,
1221 1218 MPI2_FUNCTION_FW_DOWNLOAD);
1222 1219 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1223 1220 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1224 1221 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1225 1222 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1226 1223
1227 1224 tcsge = (pMpi2FWDownloadTCSGE_t)&fwdownload->SGL;
1228 1225 ddi_put8(acc_hdl, &tcsge->ContextSize, 0);
1229 1226 ddi_put8(acc_hdl, &tcsge->DetailsLength, 12);
1230 1227 ddi_put8(acc_hdl, &tcsge->Flags, 0);
1231 1228 ddi_put32(acc_hdl, &tcsge->ImageOffset, 0);
1232 1229 ddi_put32(acc_hdl, &tcsge->ImageSize, size);
1233 1230
1234 1231 sge = (pMpi2SGESimple64_t)(tcsge + 1);
1235 1232 flagslength = size;
1236 1233 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
1237 1234 MPI2_SGE_FLAGS_END_OF_BUFFER |
1238 1235 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1239 1236 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
1240 1237 MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
1241 1238 MPI2_SGE_FLAGS_HOST_TO_IOC |
1242 1239 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
1243 1240 ddi_put32(acc_hdl, &sge->FlagsLength, flagslength);
1244 1241 ddi_put32(acc_hdl, &sge->Address.Low,
1245 1242 flsh_cookie.dmac_address);
1246 1243 ddi_put32(acc_hdl, &sge->Address.High,
1247 1244 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1248 1245 }
1249 1246
1250 1247 /*
1251 1248 * Complete firmware download frame for v2.5 cards.
1252 1249 */
1253 1250 static void
1254 1251 mptsas_uflash25(pMpi25FWDownloadRequest fwdownload,
1255 1252 ddi_acc_handle_t acc_hdl, uint32_t size, uint8_t type,
1256 1253 ddi_dma_cookie_t flsh_cookie)
1257 1254 {
1258 1255 pMpi2IeeeSgeSimple64_t sge;
1259 1256 uint8_t flags;
1260 1257
1261 1258 ddi_put8(acc_hdl, &fwdownload->Function,
1262 1259 MPI2_FUNCTION_FW_DOWNLOAD);
1263 1260 ddi_put8(acc_hdl, &fwdownload->ImageType, type);
1264 1261 ddi_put8(acc_hdl, &fwdownload->MsgFlags,
1265 1262 MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT);
1266 1263 ddi_put32(acc_hdl, &fwdownload->TotalImageSize, size);
1267 1264
1268 1265 ddi_put32(acc_hdl, &fwdownload->ImageOffset, 0);
1269 1266 ddi_put32(acc_hdl, &fwdownload->ImageSize, size);
1270 1267
1271 1268 sge = (pMpi2IeeeSgeSimple64_t)&fwdownload->SGL;
1272 1269 flags = MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT |
1273 1270 MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR |
1274 1271 MPI25_IEEE_SGE_FLAGS_END_OF_LIST;
1275 1272 ddi_put8(acc_hdl, &sge->Flags, flags);
1276 1273 ddi_put32(acc_hdl, &sge->Length, size);
1277 1274 ddi_put32(acc_hdl, &sge->Address.Low,
1278 1275 flsh_cookie.dmac_address);
1279 1276 ddi_put32(acc_hdl, &sge->Address.High,
1280 1277 (uint32_t)(flsh_cookie.dmac_laddress >> 32));
1281 1278 }
1282 1279
1283 1280 static int mptsas_enable_mpi25_flashupdate = 0;
1284 1281
1285 1282 int
1286 1283 mptsas_update_flash(mptsas_t *mpt, caddr_t ptrbuffer, uint32_t size,
1287 1284 uint8_t type, int mode)
1288 1285 {
1289 1286
1290 1287 /*
1291 1288 * In order to avoid allocating variables on the stack,
1292 1289 * we make use of the pre-existing mptsas_cmd_t and
1293 1290 * scsi_pkt which are included in the mptsas_t which
1294 1291 * is passed to this routine.
1295 1292 */
1296 1293
1297 1294 ddi_dma_attr_t flsh_dma_attrs;
1298 1295 ddi_dma_cookie_t flsh_cookie;
1299 1296 ddi_dma_handle_t flsh_dma_handle;
1300 1297 ddi_acc_handle_t flsh_accessp;
1301 1298 caddr_t memp, flsh_memp;
1302 1299 mptsas_cmd_t *cmd;
1303 1300 struct scsi_pkt *pkt;
1304 1301 int i;
1305 1302 int rvalue = 0;
1306 1303 uint32_t request_desc_low;
1307 1304
1308 1305 if (mpt->m_MPI25 && !mptsas_enable_mpi25_flashupdate) {
1309 1306 /*
1310 1307 * The code is there but not tested yet.
1311 1308 * User has to know there are risks here.
1312 1309 */
1313 1310 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): "
1314 1311 "Updating firmware through MPI 2.5 has not been "
1315 1312 "tested yet!\n"
1316 1313 "To enable set mptsas_enable_mpi25_flashupdate to 1\n");
1317 1314 return (-1);
1318 1315 } /* Otherwise, you pay your money and you take your chances. */
1319 1316
1320 1317 if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) {
1321 1318 mptsas_log(mpt, CE_WARN, "mptsas_update_flash(): allocation "
1322 1319 "failed. event ack command pool is full\n");
1323 1320 return (rvalue);
1324 1321 }
1325 1322
1326 1323 bzero((caddr_t)cmd, sizeof (*cmd));
1327 1324 bzero((caddr_t)pkt, scsi_pkt_size());
1328 1325 cmd->ioc_cmd_slot = (uint32_t)rvalue;
1329 1326
1330 1327 /*
1331 1328 * dynamically create a customized dma attribute structure
1332 1329 * that describes the flash file.
1333 1330 */
1334 1331 flsh_dma_attrs = mpt->m_msg_dma_attr;
1335 1332 flsh_dma_attrs.dma_attr_sgllen = 1;
1336 1333
1337 1334 if (mptsas_dma_addr_create(mpt, flsh_dma_attrs, &flsh_dma_handle,
1338 1335 &flsh_accessp, &flsh_memp, size, &flsh_cookie) == FALSE) {
1339 1336 mptsas_log(mpt, CE_WARN,
1340 1337 "(unable to allocate dma resource.");
1341 1338 mptsas_return_to_pool(mpt, cmd);
1342 1339 return (-1);
1343 1340 }
1344 1341
1345 1342 bzero(flsh_memp, size);
1346 1343
1347 1344 for (i = 0; i < size; i++) {
1348 1345 (void) ddi_copyin(ptrbuffer + i, flsh_memp + i, 1, mode);
1349 1346 }
1350 1347 (void) ddi_dma_sync(flsh_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
1351 1348
1352 1349 /*
1353 1350 * form a cmd/pkt to store the fw download message
1354 1351 */
1355 1352 pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
1356 1353 pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb;
1357 1354 pkt->pkt_ha_private = (opaque_t)cmd;
1358 1355 pkt->pkt_flags = FLAG_HEAD;
1359 1356 pkt->pkt_time = 60;
1360 1357 cmd->cmd_pkt = pkt;
1361 1358 cmd->cmd_scblen = 1;
1362 1359 cmd->cmd_flags = CFLAG_CMDIOC | CFLAG_FW_CMD;
1363 1360
1364 1361 /*
1365 1362 * Save the command in a slot
1366 1363 */
1367 1364 if (mptsas_save_cmd(mpt, cmd) == FALSE) {
1368 1365 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1369 1366 mptsas_return_to_pool(mpt, cmd);
1370 1367 return (-1);
1371 1368 }
1372 1369
1373 1370 /*
1374 1371 * Fill in fw download message
1375 1372 */
1376 1373 ASSERT(cmd->cmd_slot != 0);
1377 1374 memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot);
1378 1375 bzero(memp, mpt->m_req_frame_size);
1379 1376
1380 1377 if (mpt->m_MPI25)
1381 1378 mptsas_uflash25((pMpi25FWDownloadRequest)memp,
1382 1379 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1383 1380 else
1384 1381 mptsas_uflash2((pMpi2FWDownloadRequest)memp,
1385 1382 mpt->m_acc_req_frame_hdl, size, type, flsh_cookie);
1386 1383
1387 1384 /*
1388 1385 * Start command
1389 1386 */
1390 1387 (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0,
1391 1388 DDI_DMA_SYNC_FORDEV);
1392 1389 request_desc_low = (cmd->cmd_slot << 16) +
1393 1390 MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1394 1391 cmd->cmd_rfm = NULL;
1395 1392 MPTSAS_START_CMD(mpt, request_desc_low, 0);
1396 1393
1397 1394 rvalue = 0;
1398 1395 (void) cv_reltimedwait(&mpt->m_fw_cv, &mpt->m_mutex,
1399 1396 drv_usectohz(60 * MICROSEC), TR_CLOCK_TICK);
1400 1397 if (!(cmd->cmd_flags & CFLAG_FINISHED)) {
1401 1398 mpt->m_softstate &= ~MPTSAS_SS_MSG_UNIT_RESET;
1402 1399 if ((mptsas_restart_ioc(mpt)) == DDI_FAILURE) {
1403 1400 mptsas_log(mpt, CE_WARN, "mptsas_restart_ioc failed");
1404 1401 }
1405 1402 rvalue = -1;
1406 1403 }
1407 1404 mptsas_remove_cmd(mpt, cmd);
1408 1405 mptsas_dma_addr_destroy(&flsh_dma_handle, &flsh_accessp);
1409 1406
1410 1407 return (rvalue);
1411 1408 }
1412 1409
1413 1410 static int
1414 1411 mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1415 1412 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1416 1413 va_list ap)
1417 1414 {
1418 1415 #ifndef __lock_lint
1419 1416 _NOTE(ARGUNUSED(ap))
1420 1417 #endif
1421 1418 pMpi2SasDevicePage0_t sasdevpage;
1422 1419 int rval = DDI_SUCCESS, i;
1423 1420 uint8_t *sas_addr = NULL;
1424 1421 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1425 1422 uint16_t *devhdl, *bay_num, *enclosure;
1426 1423 uint64_t *sas_wwn;
1427 1424 uint32_t *dev_info;
1428 1425 uint8_t *physport, *phynum;
1429 1426 uint16_t *pdevhdl, *io_flags;
1430 1427 uint32_t page_address;
1431 1428
1432 1429 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1433 1430 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1434 1431 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_device_page0 "
1435 1432 "header: IOCStatus=0x%x, IOCLogInfo=0x%x",
1436 1433 iocstatus, iocloginfo);
1437 1434 rval = DDI_FAILURE;
1438 1435 return (rval);
1439 1436 }
1440 1437 page_address = va_arg(ap, uint32_t);
1441 1438 /*
1442 1439 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1443 1440 * are no more pages. If everything is OK up to this point but the
1444 1441 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1445 1442 * signal that device traversal is complete.
1446 1443 */
1447 1444 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1448 1445 if ((page_address & MPI2_SAS_DEVICE_PGAD_FORM_MASK) ==
1449 1446 MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE) {
1450 1447 mpt->m_done_traverse_dev = 1;
1451 1448 }
1452 1449 rval = DDI_FAILURE;
1453 1450 return (rval);
1454 1451 }
1455 1452 devhdl = va_arg(ap, uint16_t *);
1456 1453 sas_wwn = va_arg(ap, uint64_t *);
1457 1454 dev_info = va_arg(ap, uint32_t *);
1458 1455 physport = va_arg(ap, uint8_t *);
1459 1456 phynum = va_arg(ap, uint8_t *);
1460 1457 pdevhdl = va_arg(ap, uint16_t *);
1461 1458 bay_num = va_arg(ap, uint16_t *);
1462 1459 enclosure = va_arg(ap, uint16_t *);
1463 1460 io_flags = va_arg(ap, uint16_t *);
1464 1461
1465 1462 sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
1466 1463
1467 1464 *dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
1468 1465 *devhdl = ddi_get16(accessp, &sasdevpage->DevHandle);
1469 1466 sas_addr = (uint8_t *)(&sasdevpage->SASAddress);
1470 1467 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1471 1468 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1472 1469 }
1473 1470 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1474 1471 *sas_wwn = LE_64(*sas_wwn);
1475 1472 *physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
1476 1473 *phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
1477 1474 *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
1478 1475 *bay_num = ddi_get16(accessp, &sasdevpage->Slot);
1479 1476 *enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
1480 1477 *io_flags = ddi_get16(accessp, &sasdevpage->Flags);
1481 1478
1482 1479 if (*io_flags & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) {
1483 1480 /*
1484 1481 * Leave a messages about FP cabability in the log.
1485 1482 */
1486 1483 mptsas_log(mpt, CE_CONT,
1487 1484 "!w%016"PRIx64" FastPath Capable%s", *sas_wwn,
1488 1485 (*io_flags &
1489 1486 MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)?
1490 1487 " and Enabled":" but Disabled");
1491 1488 }
1492 1489
1493 1490 return (rval);
1494 1491 }
1495 1492
1496 1493 /*
1497 1494 * Request MPI configuration page SAS device page 0 to get DevHandle, device
1498 1495 * info and SAS address.
1499 1496 */
1500 1497 int
1501 1498 mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
1502 1499 uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
1503 1500 uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
1504 1501 uint16_t *bay_num, uint16_t *enclosure, uint16_t *io_flags)
1505 1502 {
1506 1503 int rval = DDI_SUCCESS;
1507 1504
1508 1505 ASSERT(mutex_owned(&mpt->m_mutex));
1509 1506
1510 1507 /*
1511 1508 * Get the header and config page. reply contains the reply frame,
1512 1509 * which holds status info for the request.
1513 1510 */
1514 1511 rval = mptsas_access_config_page(mpt,
1515 1512 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1516 1513 MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
1517 1514 mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
1518 1515 dev_info, physport, phynum, pdev_handle,
1519 1516 bay_num, enclosure, io_flags);
1520 1517
1521 1518 return (rval);
1522 1519 }
1523 1520
1524 1521 static int
1525 1522 mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1526 1523 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1527 1524 va_list ap)
1528 1525 {
1529 1526 #ifndef __lock_lint
1530 1527 _NOTE(ARGUNUSED(ap))
1531 1528 #endif
1532 1529 pMpi2ExpanderPage0_t expddevpage;
1533 1530 int rval = DDI_SUCCESS, i;
1534 1531 uint8_t *sas_addr = NULL;
1535 1532 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1536 1533 uint16_t *devhdl;
1537 1534 uint64_t *sas_wwn;
1538 1535 uint8_t physport;
1539 1536 mptsas_phymask_t *phymask;
1540 1537 uint16_t *pdevhdl;
1541 1538 uint32_t page_address;
1542 1539
1543 1540 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1544 1541 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1545 1542 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
1546 1543 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1547 1544 iocstatus, iocloginfo);
1548 1545 rval = DDI_FAILURE;
1549 1546 return (rval);
1550 1547 }
1551 1548 page_address = va_arg(ap, uint32_t);
1552 1549 /*
1553 1550 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
1554 1551 * are no more pages. If everything is OK up to this point but the
1555 1552 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
1556 1553 * signal that device traversal is complete.
1557 1554 */
1558 1555 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
1559 1556 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
1560 1557 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
1561 1558 mpt->m_done_traverse_smp = 1;
1562 1559 }
1563 1560 rval = DDI_FAILURE;
1564 1561 return (rval);
1565 1562 }
1566 1563 devhdl = va_arg(ap, uint16_t *);
1567 1564 sas_wwn = va_arg(ap, uint64_t *);
1568 1565 phymask = va_arg(ap, mptsas_phymask_t *);
1569 1566 pdevhdl = va_arg(ap, uint16_t *);
1570 1567
1571 1568 expddevpage = (pMpi2ExpanderPage0_t)page_memp;
1572 1569
1573 1570 *devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
1574 1571 physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
1575 1572 *phymask = mptsas_physport_to_phymask(mpt, physport);
1576 1573 *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
1577 1574 sas_addr = (uint8_t *)(&expddevpage->SASAddress);
1578 1575 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1579 1576 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1580 1577 }
1581 1578 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1582 1579 *sas_wwn = LE_64(*sas_wwn);
1583 1580
1584 1581 return (rval);
1585 1582 }
1586 1583
1587 1584 /*
1588 1585 * Request MPI configuration page SAS device page 0 to get DevHandle, phymask
1589 1586 * and SAS address.
1590 1587 */
1591 1588 int
1592 1589 mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
1593 1590 mptsas_smp_t *info)
1594 1591 {
1595 1592 int rval = DDI_SUCCESS;
1596 1593
1597 1594 ASSERT(mutex_owned(&mpt->m_mutex));
1598 1595
1599 1596 /*
1600 1597 * Get the header and config page. reply contains the reply frame,
1601 1598 * which holds status info for the request.
1602 1599 */
1603 1600 rval = mptsas_access_config_page(mpt,
1604 1601 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1605 1602 MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
1606 1603 mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
1607 1604 &info->m_addr.mta_wwn, &info->m_addr.mta_phymask, &info->m_pdevhdl);
1608 1605
1609 1606 return (rval);
1610 1607 }
1611 1608
1612 1609 static int
1613 1610 mptsas_sasportpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
1614 1611 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1615 1612 va_list ap)
1616 1613 {
1617 1614 #ifndef __lock_lint
1618 1615 _NOTE(ARGUNUSED(ap))
1619 1616 #endif
1620 1617 int rval = DDI_SUCCESS, i;
1621 1618 uint8_t *sas_addr = NULL;
1622 1619 uint64_t *sas_wwn;
1623 1620 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
1624 1621 uint8_t *portwidth;
1625 1622 pMpi2SasPortPage0_t sasportpage;
1626 1623
1627 1624 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1628 1625 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_port_page0 "
1629 1626 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1630 1627 iocstatus, iocloginfo);
1631 1628 rval = DDI_FAILURE;
1632 1629 return (rval);
1633 1630 }
1634 1631 sas_wwn = va_arg(ap, uint64_t *);
1635 1632 portwidth = va_arg(ap, uint8_t *);
1636 1633
1637 1634 sasportpage = (pMpi2SasPortPage0_t)page_memp;
1638 1635 sas_addr = (uint8_t *)(&sasportpage->SASAddress);
1639 1636 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
1640 1637 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
1641 1638 }
1642 1639 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
1643 1640 *sas_wwn = LE_64(*sas_wwn);
1644 1641 *portwidth = ddi_get8(accessp, &sasportpage->PortWidth);
1645 1642 return (rval);
1646 1643 }
1647 1644
1648 1645 /*
1649 1646 * Request MPI configuration page SAS port page 0 to get initiator SAS address
1650 1647 * and port width.
1651 1648 */
1652 1649 int
1653 1650 mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
1654 1651 uint64_t *sas_wwn, uint8_t *portwidth)
1655 1652 {
1656 1653 int rval = DDI_SUCCESS;
1657 1654
1658 1655 ASSERT(mutex_owned(&mpt->m_mutex));
1659 1656
1660 1657 /*
1661 1658 * Get the header and config page. reply contains the reply frame,
1662 1659 * which holds status info for the request.
1663 1660 */
1664 1661 rval = mptsas_access_config_page(mpt,
1665 1662 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1666 1663 MPI2_CONFIG_EXTPAGETYPE_SAS_PORT, 0, page_address,
1667 1664 mptsas_sasportpage_0_cb, sas_wwn, portwidth);
1668 1665
1669 1666 return (rval);
1670 1667 }
1671 1668
1672 1669 static int
1673 1670 mptsas_sasiou_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
1674 1671 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1675 1672 va_list ap)
1676 1673 {
1677 1674 #ifndef __lock_lint
1678 1675 _NOTE(ARGUNUSED(ap))
1679 1676 #endif
1680 1677 int rval = DDI_SUCCESS;
1681 1678 pMpi2SasIOUnitPage0_t sasioupage0;
1682 1679 int i, num_phys;
1683 1680 uint32_t cpdi[MPTSAS_MAX_PHYS], *retrypage0, *readpage1;
1684 1681 uint8_t port_flags;
1685 1682
1686 1683 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1687 1684 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page0 "
1688 1685 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1689 1686 iocstatus, iocloginfo);
1690 1687 rval = DDI_FAILURE;
1691 1688 return (rval);
1692 1689 }
1693 1690 readpage1 = va_arg(ap, uint32_t *);
1694 1691 retrypage0 = va_arg(ap, uint32_t *);
1695 1692
1696 1693 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1697 1694
1698 1695 num_phys = ddi_get8(accessp, &sasioupage0->NumPhys);
1699 1696 /*
1700 1697 * ASSERT that the num_phys value in SAS IO Unit Page 0 is the same as
1701 1698 * was initially set. This should never change throughout the life of
1702 1699 * the driver.
1703 1700 */
1704 1701 ASSERT(num_phys == mpt->m_num_phys);
1705 1702 for (i = 0; i < num_phys; i++) {
1706 1703 cpdi[i] = ddi_get32(accessp,
1707 1704 &sasioupage0->PhyData[i].
1708 1705 ControllerPhyDeviceInfo);
1709 1706 port_flags = ddi_get8(accessp,
1710 1707 &sasioupage0->PhyData[i].PortFlags);
1711 1708 mpt->m_phy_info[i].port_num =
1712 1709 ddi_get8(accessp,
1713 1710 &sasioupage0->PhyData[i].Port);
1714 1711 mpt->m_phy_info[i].ctrl_devhdl =
1715 1712 ddi_get16(accessp, &sasioupage0->
1716 1713 PhyData[i].ControllerDevHandle);
1717 1714 mpt->m_phy_info[i].attached_devhdl =
1718 1715 ddi_get16(accessp, &sasioupage0->
1719 1716 PhyData[i].AttachedDevHandle);
1720 1717 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1721 1718 mpt->m_phy_info[i].port_flags = port_flags;
1722 1719
1723 1720 if (port_flags & DISCOVERY_IN_PROGRESS) {
1724 1721 *retrypage0 = *retrypage0 + 1;
1725 1722 break;
1726 1723 } else {
1727 1724 *retrypage0 = 0;
1728 1725 }
1729 1726 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
1730 1727 /*
1731 1728 * some PHY configuration described in
1732 1729 * SAS IO Unit Page1
1733 1730 */
1734 1731 *readpage1 = 1;
1735 1732 }
1736 1733 }
1737 1734
1738 1735 return (rval);
1739 1736 }
1740 1737
1741 1738 static int
1742 1739 mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
1743 1740 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1744 1741 va_list ap)
1745 1742 {
1746 1743 #ifndef __lock_lint
1747 1744 _NOTE(ARGUNUSED(ap))
1748 1745 #endif
1749 1746 int rval = DDI_SUCCESS;
1750 1747 pMpi2SasIOUnitPage1_t sasioupage1;
1751 1748 int i, num_phys;
1752 1749 uint32_t cpdi[MPTSAS_MAX_PHYS];
1753 1750 uint8_t port_flags;
1754 1751
1755 1752 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
1756 1753 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_io_unit_page1 "
1757 1754 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
1758 1755 iocstatus, iocloginfo);
1759 1756 rval = DDI_FAILURE;
1760 1757 return (rval);
1761 1758 }
1762 1759
1763 1760 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1764 1761 num_phys = ddi_get8(accessp, &sasioupage1->NumPhys);
1765 1762 /*
1766 1763 * ASSERT that the num_phys value in SAS IO Unit Page 1 is the same as
1767 1764 * was initially set. This should never change throughout the life of
1768 1765 * the driver.
1769 1766 */
1770 1767 ASSERT(num_phys == mpt->m_num_phys);
1771 1768 for (i = 0; i < num_phys; i++) {
1772 1769 cpdi[i] = ddi_get32(accessp, &sasioupage1->PhyData[i].
1773 1770 ControllerPhyDeviceInfo);
1774 1771 port_flags = ddi_get8(accessp,
1775 1772 &sasioupage1->PhyData[i].PortFlags);
1776 1773 mpt->m_phy_info[i].port_num =
1777 1774 ddi_get8(accessp,
1778 1775 &sasioupage1->PhyData[i].Port);
1779 1776 mpt->m_phy_info[i].port_flags = port_flags;
1780 1777 mpt->m_phy_info[i].phy_device_type = cpdi[i];
1781 1778 }
1782 1779 return (rval);
1783 1780 }
1784 1781
1785 1782 /*
1786 1783 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1787 1784 * page1 to update the PHY information. This is the message passing method of
1788 1785 * this function which should be called except during initialization.
1789 1786 */
1790 1787 int
1791 1788 mptsas_get_sas_io_unit_page(mptsas_t *mpt)
1792 1789 {
1793 1790 int rval = DDI_SUCCESS, state;
1794 1791 uint32_t readpage1 = 0, retrypage0 = 0;
1795 1792
1796 1793 ASSERT(mutex_owned(&mpt->m_mutex));
1797 1794
1798 1795 /*
1799 1796 * Now we cycle through the state machine. Here's what happens:
1800 1797 * 1. Read IO unit page 0 and set phy information
1801 1798 * 2. See if Read IO unit page1 is needed because of port configuration
1802 1799 * 3. Read IO unit page 1 and update phy information.
1803 1800 */
1804 1801 state = IOUC_READ_PAGE0;
1805 1802 while (state != IOUC_DONE) {
1806 1803 if (state == IOUC_READ_PAGE0) {
1807 1804 rval = mptsas_access_config_page(mpt,
1808 1805 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1809 1806 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, 0,
1810 1807 mptsas_sasiou_page_0_cb, &readpage1,
1811 1808 &retrypage0);
1812 1809 } else if (state == IOUC_READ_PAGE1) {
1813 1810 rval = mptsas_access_config_page(mpt,
1814 1811 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
1815 1812 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 1, 0,
1816 1813 mptsas_sasiou_page_1_cb);
1817 1814 }
1818 1815
1819 1816 if (rval == DDI_SUCCESS) {
1820 1817 switch (state) {
1821 1818 case IOUC_READ_PAGE0:
1822 1819 /*
1823 1820 * retry 30 times if discovery is in process
1824 1821 */
1825 1822 if (retrypage0 && (retrypage0 < 30)) {
1826 1823 drv_usecwait(1000 * 100);
1827 1824 state = IOUC_READ_PAGE0;
1828 1825 break;
1829 1826 } else if (retrypage0 == 30) {
1830 1827 mptsas_log(mpt, CE_WARN,
1831 1828 "!Discovery in progress, can't "
1832 1829 "verify IO unit config, then "
1833 1830 "after 30 times retry, give "
1834 1831 "up!");
1835 1832 state = IOUC_DONE;
1836 1833 rval = DDI_FAILURE;
1837 1834 break;
1838 1835 }
1839 1836
1840 1837 if (readpage1 == 0) {
1841 1838 state = IOUC_DONE;
1842 1839 rval = DDI_SUCCESS;
1843 1840 break;
1844 1841 }
1845 1842
1846 1843 state = IOUC_READ_PAGE1;
1847 1844 break;
1848 1845
1849 1846 case IOUC_READ_PAGE1:
1850 1847 state = IOUC_DONE;
1851 1848 rval = DDI_SUCCESS;
1852 1849 break;
1853 1850 }
1854 1851 } else {
1855 1852 return (rval);
1856 1853 }
1857 1854 }
1858 1855
1859 1856 return (rval);
1860 1857 }
1861 1858
1862 1859 static int
1863 1860 mptsas_biospage_3_cb(mptsas_t *mpt, caddr_t page_memp,
1864 1861 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
1865 1862 va_list ap)
1866 1863 {
1867 1864 #ifndef __lock_lint
1868 1865 _NOTE(ARGUNUSED(ap))
1869 1866 #endif
1870 1867 pMpi2BiosPage3_t sasbiospage;
1871 1868 int rval = DDI_SUCCESS;
1872 1869 uint32_t *bios_version;
1873 1870
1874 1871 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
1875 1872 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
1876 1873 mptsas_log(mpt, CE_WARN, "mptsas_get_bios_page3 header: "
1877 1874 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus, iocloginfo);
1878 1875 rval = DDI_FAILURE;
1879 1876 return (rval);
1880 1877 }
1881 1878 bios_version = va_arg(ap, uint32_t *);
1882 1879 sasbiospage = (pMpi2BiosPage3_t)page_memp;
1883 1880 *bios_version = ddi_get32(accessp, &sasbiospage->BiosVersion);
1884 1881
1885 1882 return (rval);
1886 1883 }
1887 1884
1888 1885 /*
1889 1886 * Request MPI configuration page BIOS page 3 to get BIOS version. Since all
1890 1887 * other information in this page is not needed, just ignore it.
1891 1888 */
1892 1889 int
1893 1890 mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version)
1894 1891 {
1895 1892 int rval = DDI_SUCCESS;
1896 1893
1897 1894 ASSERT(mutex_owned(&mpt->m_mutex));
1898 1895
1899 1896 /*
1900 1897 * Get the header and config page. reply contains the reply frame,
1901 1898 * which holds status info for the request.
1902 1899 */
1903 1900 rval = mptsas_access_config_page(mpt,
1904 1901 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, MPI2_CONFIG_PAGETYPE_BIOS, 3,
1905 1902 0, mptsas_biospage_3_cb, bios_version);
1906 1903
1907 1904 return (rval);
1908 1905 }
1909 1906
1910 1907 /*
1911 1908 * Read IO unit page 0 to get information for each PHY. If needed, Read IO Unit
1912 1909 * page1 to update the PHY information. This is the handshaking version of
1913 1910 * this function, which should be called during initialization only.
1914 1911 */
1915 1912 int
1916 1913 mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt)
1917 1914 {
1918 1915 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
1919 1916 ddi_dma_cookie_t page_cookie;
1920 1917 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
1921 1918 ddi_acc_handle_t recv_accessp, page_accessp;
1922 1919 pMpi2ConfigReply_t configreply;
1923 1920 pMpi2SasIOUnitPage0_t sasioupage0;
1924 1921 pMpi2SasIOUnitPage1_t sasioupage1;
1925 1922 int recv_numbytes;
1926 1923 caddr_t recv_memp, page_memp;
1927 1924 int i, num_phys, start_phy = 0;
1928 1925 int page0_size =
1929 1926 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_0) +
1930 1927 (sizeof (MPI2_SAS_IO_UNIT0_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1931 1928 int page1_size =
1932 1929 sizeof (MPI2_CONFIG_PAGE_SASIOUNIT_1) +
1933 1930 (sizeof (MPI2_SAS_IO_UNIT1_PHY_DATA) * (MPTSAS_MAX_PHYS - 1));
1934 1931 uint32_t flags_length;
1935 1932 uint32_t cpdi[MPTSAS_MAX_PHYS];
1936 1933 uint32_t readpage1 = 0, retrypage0 = 0;
1937 1934 uint16_t iocstatus;
1938 1935 uint8_t port_flags, page_number, action;
1939 1936 uint32_t reply_size = 256; /* Big enough for any page */
1940 1937 uint_t state;
1941 1938 int rval = DDI_FAILURE;
1942 1939 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
1943 1940
1944 1941 /*
1945 1942 * Initialize our "state machine". This is a bit convoluted,
1946 1943 * but it keeps us from having to do the ddi allocations numerous
1947 1944 * times.
1948 1945 */
1949 1946
1950 1947 NDBG20(("mptsas_get_sas_io_unit_page_hndshk enter"));
1951 1948 ASSERT(mutex_owned(&mpt->m_mutex));
1952 1949 state = IOUC_READ_PAGE0;
1953 1950
1954 1951 /*
1955 1952 * dynamically create a customized dma attribute structure
1956 1953 * that describes mpt's config reply page request structure.
1957 1954 */
1958 1955 recv_dma_attrs = mpt->m_msg_dma_attr;
1959 1956 recv_dma_attrs.dma_attr_sgllen = 1;
1960 1957 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
1961 1958
1962 1959 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
1963 1960 &recv_dma_handle, &recv_accessp, &recv_memp,
1964 1961 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
1965 1962 mptsas_log(mpt, CE_WARN,
1966 1963 "mptsas_get_sas_io_unit_page_hndshk: recv dma failed");
1967 1964 goto cleanup;
1968 1965 }
1969 1966 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
1970 1967 free_recv = B_TRUE;
1971 1968
1972 1969 page_dma_attrs = mpt->m_msg_dma_attr;
1973 1970 page_dma_attrs.dma_attr_sgllen = 1;
1974 1971 page_dma_attrs.dma_attr_granular = reply_size;
1975 1972
1976 1973 if (mptsas_dma_addr_create(mpt, page_dma_attrs,
1977 1974 &page_dma_handle, &page_accessp, &page_memp,
1978 1975 reply_size, &page_cookie) == FALSE) {
1979 1976 mptsas_log(mpt, CE_WARN,
1980 1977 "mptsas_get_sas_io_unit_page_hndshk: page dma failed");
1981 1978 goto cleanup;
1982 1979 }
1983 1980 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
1984 1981 free_page = B_TRUE;
1985 1982
1986 1983 /*
1987 1984 * Now we cycle through the state machine. Here's what happens:
1988 1985 * 1. Read IO unit page 0 and set phy information
1989 1986 * 2. See if Read IO unit page1 is needed because of port configuration
1990 1987 * 3. Read IO unit page 1 and update phy information.
1991 1988 */
1992 1989
1993 1990 sasioupage0 = (pMpi2SasIOUnitPage0_t)page_memp;
1994 1991 sasioupage1 = (pMpi2SasIOUnitPage1_t)page_memp;
1995 1992
1996 1993 while (state != IOUC_DONE) {
1997 1994 switch (state) {
1998 1995 case IOUC_READ_PAGE0:
1999 1996 page_number = 0;
2000 1997 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2001 1998 flags_length = (uint32_t)page0_size;
2002 1999 flags_length |= ((uint32_t)(
2003 2000 MPI2_SGE_FLAGS_LAST_ELEMENT |
2004 2001 MPI2_SGE_FLAGS_END_OF_BUFFER |
2005 2002 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2006 2003 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2007 2004 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2008 2005 MPI2_SGE_FLAGS_IOC_TO_HOST |
2009 2006 MPI2_SGE_FLAGS_END_OF_LIST) <<
2010 2007 MPI2_SGE_FLAGS_SHIFT);
2011 2008
2012 2009 break;
2013 2010
2014 2011 case IOUC_READ_PAGE1:
2015 2012 page_number = 1;
2016 2013 action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
2017 2014 flags_length = (uint32_t)page1_size;
2018 2015 flags_length |= ((uint32_t)(
2019 2016 MPI2_SGE_FLAGS_LAST_ELEMENT |
2020 2017 MPI2_SGE_FLAGS_END_OF_BUFFER |
2021 2018 MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2022 2019 MPI2_SGE_FLAGS_SYSTEM_ADDRESS |
2023 2020 MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2024 2021 MPI2_SGE_FLAGS_IOC_TO_HOST |
2025 2022 MPI2_SGE_FLAGS_END_OF_LIST) <<
2026 2023 MPI2_SGE_FLAGS_SHIFT);
2027 2024
2028 2025 break;
2029 2026 default:
2030 2027 break;
2031 2028 }
2032 2029
2033 2030 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2034 2031 configreply = (pMpi2ConfigReply_t)recv_memp;
2035 2032 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2036 2033
2037 2034 if (mptsas_send_extended_config_request_msg(mpt,
2038 2035 MPI2_CONFIG_ACTION_PAGE_HEADER,
2039 2036 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
2040 2037 0, page_number, 0, 0, 0, 0)) {
2041 2038 goto cleanup;
2042 2039 }
2043 2040
2044 2041 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2045 2042 recv_accessp)) {
2046 2043 goto cleanup;
2047 2044 }
2048 2045
2049 2046 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2050 2047 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2051 2048
2052 2049 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2053 2050 mptsas_log(mpt, CE_WARN,
2054 2051 "mptsas_get_sas_io_unit_page_hndshk: read page "
2055 2052 "header iocstatus = 0x%x", iocstatus);
2056 2053 goto cleanup;
2057 2054 }
2058 2055
2059 2056 if (action != MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
2060 2057 bzero(page_memp, reply_size);
2061 2058 }
2062 2059
2063 2060 if (mptsas_send_extended_config_request_msg(mpt, action,
2064 2061 MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT, 0, page_number,
2065 2062 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2066 2063 ddi_get16(recv_accessp, &configreply->ExtPageLength),
2067 2064 flags_length, page_cookie.dmac_address)) {
2068 2065 goto cleanup;
2069 2066 }
2070 2067
2071 2068 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2072 2069 recv_accessp)) {
2073 2070 goto cleanup;
2074 2071 }
2075 2072
2076 2073 iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus);
2077 2074 iocstatus = MPTSAS_IOCSTATUS(iocstatus);
2078 2075
2079 2076 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
2080 2077 mptsas_log(mpt, CE_WARN,
2081 2078 "mptsas_get_sas_io_unit_page_hndshk: IO unit "
2082 2079 "config failed for action %d, iocstatus = 0x%x",
2083 2080 action, iocstatus);
2084 2081 goto cleanup;
2085 2082 }
2086 2083
2087 2084 switch (state) {
2088 2085 case IOUC_READ_PAGE0:
2089 2086 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2090 2087 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2091 2088 goto cleanup;
2092 2089 }
2093 2090
2094 2091 num_phys = ddi_get8(page_accessp,
2095 2092 &sasioupage0->NumPhys);
2096 2093 ASSERT(num_phys == mpt->m_num_phys);
2097 2094 if (num_phys > MPTSAS_MAX_PHYS) {
2098 2095 mptsas_log(mpt, CE_WARN, "Number of phys "
2099 2096 "supported by HBA (%d) is more than max "
2100 2097 "supported by driver (%d). Driver will "
2101 2098 "not attach.", num_phys,
2102 2099 MPTSAS_MAX_PHYS);
2103 2100 rval = DDI_FAILURE;
2104 2101 goto cleanup;
2105 2102 }
2106 2103 for (i = start_phy; i < num_phys; i++, start_phy = i) {
2107 2104 cpdi[i] = ddi_get32(page_accessp,
2108 2105 &sasioupage0->PhyData[i].
2109 2106 ControllerPhyDeviceInfo);
2110 2107 port_flags = ddi_get8(page_accessp,
2111 2108 &sasioupage0->PhyData[i].PortFlags);
2112 2109
2113 2110 mpt->m_phy_info[i].port_num =
2114 2111 ddi_get8(page_accessp,
2115 2112 &sasioupage0->PhyData[i].Port);
2116 2113 mpt->m_phy_info[i].ctrl_devhdl =
2117 2114 ddi_get16(page_accessp, &sasioupage0->
2118 2115 PhyData[i].ControllerDevHandle);
2119 2116 mpt->m_phy_info[i].attached_devhdl =
2120 2117 ddi_get16(page_accessp, &sasioupage0->
2121 2118 PhyData[i].AttachedDevHandle);
2122 2119 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2123 2120 mpt->m_phy_info[i].port_flags = port_flags;
2124 2121
2125 2122 if (port_flags & DISCOVERY_IN_PROGRESS) {
2126 2123 retrypage0++;
2127 2124 NDBG20(("Discovery in progress, can't "
2128 2125 "verify IO unit config, then NO.%d"
2129 2126 " times retry", retrypage0));
2130 2127 break;
2131 2128 } else {
2132 2129 retrypage0 = 0;
2133 2130 }
2134 2131 if (!(port_flags & AUTO_PORT_CONFIGURATION)) {
2135 2132 /*
2136 2133 * some PHY configuration described in
2137 2134 * SAS IO Unit Page1
2138 2135 */
2139 2136 readpage1 = 1;
2140 2137 }
2141 2138 }
2142 2139
2143 2140 /*
2144 2141 * retry 30 times if discovery is in process
2145 2142 */
2146 2143 if (retrypage0 && (retrypage0 < 30)) {
2147 2144 drv_usecwait(1000 * 100);
2148 2145 state = IOUC_READ_PAGE0;
2149 2146 break;
2150 2147 } else if (retrypage0 == 30) {
2151 2148 mptsas_log(mpt, CE_WARN,
2152 2149 "!Discovery in progress, can't "
2153 2150 "verify IO unit config, then after"
2154 2151 " 30 times retry, give up!");
2155 2152 state = IOUC_DONE;
2156 2153 rval = DDI_FAILURE;
2157 2154 break;
2158 2155 }
2159 2156
2160 2157 if (readpage1 == 0) {
2161 2158 state = IOUC_DONE;
2162 2159 rval = DDI_SUCCESS;
2163 2160 break;
2164 2161 }
2165 2162
2166 2163 state = IOUC_READ_PAGE1;
2167 2164 break;
2168 2165
2169 2166 case IOUC_READ_PAGE1:
2170 2167 if ((ddi_dma_sync(page_dma_handle, 0, 0,
2171 2168 DDI_DMA_SYNC_FORCPU)) != DDI_SUCCESS) {
2172 2169 goto cleanup;
2173 2170 }
2174 2171
2175 2172 num_phys = ddi_get8(page_accessp,
2176 2173 &sasioupage1->NumPhys);
2177 2174 ASSERT(num_phys == mpt->m_num_phys);
2178 2175 if (num_phys > MPTSAS_MAX_PHYS) {
2179 2176 mptsas_log(mpt, CE_WARN, "Number of phys "
2180 2177 "supported by HBA (%d) is more than max "
2181 2178 "supported by driver (%d). Driver will "
2182 2179 "not attach.", num_phys,
2183 2180 MPTSAS_MAX_PHYS);
2184 2181 rval = DDI_FAILURE;
2185 2182 goto cleanup;
2186 2183 }
2187 2184 for (i = 0; i < num_phys; i++) {
2188 2185 cpdi[i] = ddi_get32(page_accessp,
2189 2186 &sasioupage1->PhyData[i].
2190 2187 ControllerPhyDeviceInfo);
2191 2188 port_flags = ddi_get8(page_accessp,
2192 2189 &sasioupage1->PhyData[i].PortFlags);
2193 2190 mpt->m_phy_info[i].port_num =
2194 2191 ddi_get8(page_accessp,
2195 2192 &sasioupage1->PhyData[i].Port);
2196 2193 mpt->m_phy_info[i].port_flags = port_flags;
2197 2194 mpt->m_phy_info[i].phy_device_type = cpdi[i];
2198 2195
2199 2196 }
2200 2197
2201 2198 state = IOUC_DONE;
2202 2199 rval = DDI_SUCCESS;
2203 2200 break;
2204 2201 }
2205 2202 }
2206 2203 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2207 2204 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2208 2205 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2209 2206 rval = DDI_FAILURE;
2210 2207 goto cleanup;
2211 2208 }
2212 2209 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2213 2210 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2214 2211 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2215 2212 rval = DDI_FAILURE;
2216 2213 goto cleanup;
2217 2214 }
2218 2215
2219 2216 cleanup:
2220 2217 if (free_recv)
2221 2218 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2222 2219 if (free_page)
2223 2220 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2224 2221 if (rval != DDI_SUCCESS) {
2225 2222 mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE);
2226 2223 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST);
2227 2224 }
2228 2225 return (rval);
2229 2226 }
2230 2227
2231 2228 /*
2232 2229 * mptsas_get_manufacture_page5
2233 2230 *
2234 2231 * This function will retrieve the base WWID from the adapter. Since this
2235 2232 * function is only called during the initialization process, use handshaking.
2236 2233 */
2237 2234 int
2238 2235 mptsas_get_manufacture_page5(mptsas_t *mpt)
2239 2236 {
2240 2237 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2241 2238 ddi_dma_cookie_t page_cookie;
2242 2239 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2243 2240 ddi_acc_handle_t recv_accessp, page_accessp;
2244 2241 pMpi2ConfigReply_t configreply;
2245 2242 caddr_t recv_memp, page_memp;
2246 2243 int recv_numbytes;
2247 2244 pMpi2ManufacturingPage5_t m5;
2248 2245 uint32_t flagslength;
2249 2246 int rval = DDI_SUCCESS;
2250 2247 uint_t iocstatus;
2251 2248 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2252 2249
2253 2250 MPTSAS_DISABLE_INTR(mpt);
2254 2251
2255 2252 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2256 2253 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5, 0, 0, 0, 0)) {
2257 2254 rval = DDI_FAILURE;
2258 2255 goto done;
2259 2256 }
2260 2257
2261 2258 /*
2262 2259 * dynamically create a customized dma attribute structure
2263 2260 * that describes the MPT's config reply page request structure.
2264 2261 */
2265 2262 recv_dma_attrs = mpt->m_msg_dma_attr;
2266 2263 recv_dma_attrs.dma_attr_sgllen = 1;
2267 2264 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2268 2265
2269 2266 if (mptsas_dma_addr_create(mpt, recv_dma_attrs,
2270 2267 &recv_dma_handle, &recv_accessp, &recv_memp,
2271 2268 (sizeof (MPI2_CONFIG_REPLY)), NULL) == FALSE) {
2272 2269 rval = DDI_FAILURE;
2273 2270 goto done;
2274 2271 }
2275 2272 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2276 2273 free_recv = B_TRUE;
2277 2274
2278 2275 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2279 2276 configreply = (pMpi2ConfigReply_t)recv_memp;
2280 2277 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2281 2278
2282 2279 /*
2283 2280 * get config reply message
2284 2281 */
2285 2282 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2286 2283 recv_accessp)) {
2287 2284 rval = DDI_FAILURE;
2288 2285 goto done;
2289 2286 }
2290 2287
2291 2288 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2292 2289 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2293 2290 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2294 2291 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2295 2292 goto done;
2296 2293 }
2297 2294
2298 2295 /*
2299 2296 * dynamically create a customized dma attribute structure
2300 2297 * that describes the MPT's config page structure.
2301 2298 */
2302 2299 page_dma_attrs = mpt->m_msg_dma_attr;
2303 2300 page_dma_attrs.dma_attr_sgllen = 1;
2304 2301 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_5));
2305 2302
2306 2303 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2307 2304 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_5)),
2308 2305 &page_cookie) == FALSE) {
2309 2306 rval = DDI_FAILURE;
2310 2307 goto done;
2311 2308 }
2312 2309 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2313 2310 free_page = B_TRUE;
2314 2311
2315 2312 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_5));
2316 2313 m5 = (pMpi2ManufacturingPage5_t)page_memp;
2317 2314
2318 2315 /*
2319 2316 * Give reply address to IOC to store config page in and send
2320 2317 * config request out.
2321 2318 */
2322 2319
2323 2320 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_5);
2324 2321 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2325 2322 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2326 2323 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2327 2324 MPI2_SGE_FLAGS_IOC_TO_HOST |
2328 2325 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2329 2326
2330 2327 if (mptsas_send_config_request_msg(mpt,
2331 2328 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2332 2329 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 5,
2333 2330 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2334 2331 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2335 2332 flagslength, page_cookie.dmac_address)) {
2336 2333 rval = DDI_FAILURE;
2337 2334 goto done;
2338 2335 }
2339 2336
2340 2337 /*
2341 2338 * get reply view handshake
2342 2339 */
2343 2340 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2344 2341 recv_accessp)) {
2345 2342 rval = DDI_FAILURE;
2346 2343 goto done;
2347 2344 }
2348 2345
2349 2346 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2350 2347 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 config: "
2351 2348 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2352 2349 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2353 2350 goto done;
2354 2351 }
2355 2352
2356 2353 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2357 2354
2358 2355 /*
2359 2356 * Fusion-MPT stores fields in little-endian format. This is
2360 2357 * why the low-order 32 bits are stored first.
2361 2358 */
2362 2359 mpt->un.sasaddr.m_base_wwid_lo =
2363 2360 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID);
2364 2361 mpt->un.sasaddr.m_base_wwid_hi =
2365 2362 ddi_get32(page_accessp, (uint32_t *)(void *)&m5->Phy[0].WWID + 1);
2366 2363
2367 2364 if (ddi_prop_update_int64(DDI_DEV_T_NONE, mpt->m_dip,
2368 2365 "base-wwid", mpt->un.m_base_wwid) != DDI_PROP_SUCCESS) {
2369 2366 NDBG2(("%s%d: failed to create base-wwid property",
2370 2367 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2371 2368 }
2372 2369
2373 2370 /*
2374 2371 * Set the number of PHYs present.
2375 2372 */
2376 2373 mpt->m_num_phys = ddi_get8(page_accessp, (uint8_t *)&m5->NumPhys);
2377 2374
2378 2375 if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
2379 2376 "num-phys", mpt->m_num_phys) != DDI_PROP_SUCCESS) {
2380 2377 NDBG2(("%s%d: failed to create num-phys property",
2381 2378 ddi_driver_name(mpt->m_dip), ddi_get_instance(mpt->m_dip)));
2382 2379 }
2383 2380
2384 2381 mptsas_log(mpt, CE_NOTE, "!mpt%d: Initiator WWNs: 0x%016llx-0x%016llx",
2385 2382 mpt->m_instance, (unsigned long long)mpt->un.m_base_wwid,
2386 2383 (unsigned long long)mpt->un.m_base_wwid + mpt->m_num_phys - 1);
2387 2384
2388 2385 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2389 2386 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2390 2387 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2391 2388 rval = DDI_FAILURE;
2392 2389 goto done;
2393 2390 }
2394 2391 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2395 2392 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2396 2393 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2397 2394 rval = DDI_FAILURE;
2398 2395 }
2399 2396 done:
2400 2397 /*
2401 2398 * free up memory
2402 2399 */
2403 2400 if (free_recv)
2404 2401 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2405 2402 if (free_page)
2406 2403 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2407 2404 MPTSAS_ENABLE_INTR(mpt);
2408 2405
2409 2406 return (rval);
2410 2407 }
2411 2408
2412 2409 static int
2413 2410 mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
2414 2411 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2415 2412 va_list ap)
2416 2413 {
2417 2414 #ifndef __lock_lint
2418 2415 _NOTE(ARGUNUSED(ap))
2419 2416 #endif
2420 2417 pMpi2SasPhyPage0_t sasphypage;
2421 2418 int rval = DDI_SUCCESS;
2422 2419 uint16_t *owner_devhdl, *attached_devhdl;
2423 2420 uint8_t *attached_phy_identify;
2424 2421 uint32_t *attached_phy_info;
2425 2422 uint8_t *programmed_link_rate;
2426 2423 uint8_t *hw_link_rate;
2427 2424 uint8_t *change_count;
2428 2425 uint32_t *phy_info;
2429 2426 uint8_t *negotiated_link_rate;
2430 2427 uint32_t page_address;
2431 2428
2432 2429 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2433 2430 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2434 2431 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
2435 2432 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2436 2433 iocstatus, iocloginfo);
2437 2434 rval = DDI_FAILURE;
2438 2435 return (rval);
2439 2436 }
2440 2437 page_address = va_arg(ap, uint32_t);
2441 2438 /*
2442 2439 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2443 2440 * are no more pages. If everything is OK up to this point but the
2444 2441 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2445 2442 * signal that device traversal is complete.
2446 2443 */
2447 2444 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2448 2445 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2449 2446 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2450 2447 mpt->m_done_traverse_smp = 1;
2451 2448 }
2452 2449 rval = DDI_FAILURE;
2453 2450 return (rval);
2454 2451 }
2455 2452 owner_devhdl = va_arg(ap, uint16_t *);
2456 2453 attached_devhdl = va_arg(ap, uint16_t *);
2457 2454 attached_phy_identify = va_arg(ap, uint8_t *);
2458 2455 attached_phy_info = va_arg(ap, uint32_t *);
2459 2456 programmed_link_rate = va_arg(ap, uint8_t *);
2460 2457 hw_link_rate = va_arg(ap, uint8_t *);
2461 2458 change_count = va_arg(ap, uint8_t *);
2462 2459 phy_info = va_arg(ap, uint32_t *);
2463 2460 negotiated_link_rate = va_arg(ap, uint8_t *);
2464 2461
2465 2462 sasphypage = (pMpi2SasPhyPage0_t)page_memp;
2466 2463
2467 2464 *owner_devhdl =
2468 2465 ddi_get16(accessp, &sasphypage->OwnerDevHandle);
2469 2466 *attached_devhdl =
2470 2467 ddi_get16(accessp, &sasphypage->AttachedDevHandle);
2471 2468 *attached_phy_identify =
2472 2469 ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
2473 2470 *attached_phy_info =
2474 2471 ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
2475 2472 *programmed_link_rate =
2476 2473 ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
2477 2474 *hw_link_rate =
2478 2475 ddi_get8(accessp, &sasphypage->HwLinkRate);
2479 2476 *change_count =
2480 2477 ddi_get8(accessp, &sasphypage->ChangeCount);
2481 2478 *phy_info =
2482 2479 ddi_get32(accessp, &sasphypage->PhyInfo);
2483 2480 *negotiated_link_rate =
2484 2481 ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
2485 2482
2486 2483 return (rval);
2487 2484 }
2488 2485
2489 2486 /*
2490 2487 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2491 2488 * and SAS address.
2492 2489 */
2493 2490 int
2494 2491 mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
2495 2492 smhba_info_t *info)
2496 2493 {
2497 2494 int rval = DDI_SUCCESS;
2498 2495
2499 2496 ASSERT(mutex_owned(&mpt->m_mutex));
2500 2497
2501 2498 /*
2502 2499 * Get the header and config page. reply contains the reply frame,
2503 2500 * which holds status info for the request.
2504 2501 */
2505 2502 rval = mptsas_access_config_page(mpt,
2506 2503 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2507 2504 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
2508 2505 mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
2509 2506 &info->attached_devhdl, &info->attached_phy_identify,
2510 2507 &info->attached_phy_info, &info->programmed_link_rate,
2511 2508 &info->hw_link_rate, &info->change_count,
2512 2509 &info->phy_info, &info->negotiated_link_rate);
2513 2510
2514 2511 return (rval);
2515 2512 }
2516 2513
2517 2514 static int
2518 2515 mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
2519 2516 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
2520 2517 va_list ap)
2521 2518 {
2522 2519 #ifndef __lock_lint
2523 2520 _NOTE(ARGUNUSED(ap))
2524 2521 #endif
2525 2522 pMpi2SasPhyPage1_t sasphypage;
2526 2523 int rval = DDI_SUCCESS;
2527 2524
2528 2525 uint32_t *invalid_dword_count;
2529 2526 uint32_t *running_disparity_error_count;
2530 2527 uint32_t *loss_of_dword_sync_count;
2531 2528 uint32_t *phy_reset_problem_count;
2532 2529 uint32_t page_address;
2533 2530
2534 2531 if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
2535 2532 (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
2536 2533 mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
2537 2534 "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
2538 2535 iocstatus, iocloginfo);
2539 2536 rval = DDI_FAILURE;
2540 2537 return (rval);
2541 2538 }
2542 2539 page_address = va_arg(ap, uint32_t);
2543 2540 /*
2544 2541 * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
2545 2542 * are no more pages. If everything is OK up to this point but the
2546 2543 * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
2547 2544 * signal that device traversal is complete.
2548 2545 */
2549 2546 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
2550 2547 if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
2551 2548 MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
2552 2549 mpt->m_done_traverse_smp = 1;
2553 2550 }
2554 2551 rval = DDI_FAILURE;
2555 2552 return (rval);
2556 2553 }
2557 2554
2558 2555 invalid_dword_count = va_arg(ap, uint32_t *);
2559 2556 running_disparity_error_count = va_arg(ap, uint32_t *);
2560 2557 loss_of_dword_sync_count = va_arg(ap, uint32_t *);
2561 2558 phy_reset_problem_count = va_arg(ap, uint32_t *);
2562 2559
2563 2560 sasphypage = (pMpi2SasPhyPage1_t)page_memp;
2564 2561
2565 2562 *invalid_dword_count =
2566 2563 ddi_get32(accessp, &sasphypage->InvalidDwordCount);
2567 2564 *running_disparity_error_count =
2568 2565 ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
2569 2566 *loss_of_dword_sync_count =
2570 2567 ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
2571 2568 *phy_reset_problem_count =
2572 2569 ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
2573 2570
2574 2571 return (rval);
2575 2572 }
2576 2573
2577 2574 /*
2578 2575 * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
2579 2576 * and SAS address.
2580 2577 */
2581 2578 int
2582 2579 mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
2583 2580 smhba_info_t *info)
2584 2581 {
2585 2582 int rval = DDI_SUCCESS;
2586 2583
2587 2584 ASSERT(mutex_owned(&mpt->m_mutex));
2588 2585
2589 2586 /*
2590 2587 * Get the header and config page. reply contains the reply frame,
2591 2588 * which holds status info for the request.
2592 2589 */
2593 2590 rval = mptsas_access_config_page(mpt,
2594 2591 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2595 2592 MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
2596 2593 mptsas_sasphypage_1_cb, page_address,
2597 2594 &info->invalid_dword_count,
2598 2595 &info->running_disparity_error_count,
2599 2596 &info->loss_of_dword_sync_count,
2600 2597 &info->phy_reset_problem_count);
2601 2598
2602 2599 return (rval);
2603 2600 }
2604 2601 /*
2605 2602 * mptsas_get_manufacture_page0
2606 2603 *
2607 2604 * This function will retrieve the base
2608 2605 * Chip name, Board Name,Board Trace number from the adapter.
2609 2606 * Since this function is only called during the
2610 2607 * initialization process, use handshaking.
2611 2608 */
2612 2609 int
2613 2610 mptsas_get_manufacture_page0(mptsas_t *mpt)
2614 2611 {
2615 2612 ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
2616 2613 ddi_dma_cookie_t page_cookie;
2617 2614 ddi_dma_handle_t recv_dma_handle, page_dma_handle;
2618 2615 ddi_acc_handle_t recv_accessp, page_accessp;
2619 2616 pMpi2ConfigReply_t configreply;
2620 2617 caddr_t recv_memp, page_memp;
2621 2618 int recv_numbytes;
2622 2619 pMpi2ManufacturingPage0_t m0;
2623 2620 uint32_t flagslength;
2624 2621 int rval = DDI_SUCCESS;
2625 2622 uint_t iocstatus;
2626 2623 uint8_t i = 0;
2627 2624 boolean_t free_recv = B_FALSE, free_page = B_FALSE;
2628 2625
2629 2626 MPTSAS_DISABLE_INTR(mpt);
2630 2627
2631 2628 if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
2632 2629 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
2633 2630 rval = DDI_FAILURE;
2634 2631 goto done;
2635 2632 }
2636 2633
2637 2634 /*
2638 2635 * dynamically create a customized dma attribute structure
2639 2636 * that describes the MPT's config reply page request structure.
2640 2637 */
2641 2638 recv_dma_attrs = mpt->m_msg_dma_attr;
2642 2639 recv_dma_attrs.dma_attr_sgllen = 1;
2643 2640 recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
2644 2641
2645 2642 if (mptsas_dma_addr_create(mpt, recv_dma_attrs, &recv_dma_handle,
2646 2643 &recv_accessp, &recv_memp, (sizeof (MPI2_CONFIG_REPLY)),
2647 2644 NULL) == FALSE) {
2648 2645 rval = DDI_FAILURE;
2649 2646 goto done;
2650 2647 }
2651 2648 /* Now safe to call mptsas_dma_addr_destroy(recv_dma_handle). */
2652 2649 free_recv = B_TRUE;
2653 2650
2654 2651 bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
2655 2652 configreply = (pMpi2ConfigReply_t)recv_memp;
2656 2653 recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
2657 2654
2658 2655 /*
2659 2656 * get config reply message
2660 2657 */
2661 2658 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2662 2659 recv_accessp)) {
2663 2660 rval = DDI_FAILURE;
2664 2661 goto done;
2665 2662 }
2666 2663
2667 2664 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2668 2665 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
2669 2666 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2670 2667 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2671 2668 goto done;
2672 2669 }
2673 2670
2674 2671 /*
2675 2672 * dynamically create a customized dma attribute structure
2676 2673 * that describes the MPT's config page structure.
2677 2674 */
2678 2675 page_dma_attrs = mpt->m_msg_dma_attr;
2679 2676 page_dma_attrs.dma_attr_sgllen = 1;
2680 2677 page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
2681 2678
2682 2679 if (mptsas_dma_addr_create(mpt, page_dma_attrs, &page_dma_handle,
2683 2680 &page_accessp, &page_memp, (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
2684 2681 &page_cookie) == FALSE) {
2685 2682 rval = DDI_FAILURE;
2686 2683 goto done;
2687 2684 }
2688 2685 /* Now safe to call mptsas_dma_addr_destroy(page_dma_handle). */
2689 2686 free_page = B_TRUE;
2690 2687
2691 2688 bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
2692 2689 m0 = (pMpi2ManufacturingPage0_t)page_memp;
2693 2690
2694 2691 /*
2695 2692 * Give reply address to IOC to store config page in and send
2696 2693 * config request out.
2697 2694 */
2698 2695
2699 2696 flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
2700 2697 flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
2701 2698 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
2702 2699 MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
2703 2700 MPI2_SGE_FLAGS_IOC_TO_HOST |
2704 2701 MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
2705 2702
2706 2703 if (mptsas_send_config_request_msg(mpt,
2707 2704 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
2708 2705 MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
2709 2706 ddi_get8(recv_accessp, &configreply->Header.PageVersion),
2710 2707 ddi_get8(recv_accessp, &configreply->Header.PageLength),
2711 2708 flagslength, page_cookie.dmac_address)) {
2712 2709 rval = DDI_FAILURE;
2713 2710 goto done;
2714 2711 }
2715 2712
2716 2713 /*
2717 2714 * get reply view handshake
2718 2715 */
2719 2716 if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
2720 2717 recv_accessp)) {
2721 2718 rval = DDI_FAILURE;
2722 2719 goto done;
2723 2720 }
2724 2721
2725 2722 if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
2726 2723 mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
2727 2724 "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
2728 2725 ddi_get32(recv_accessp, &configreply->IOCLogInfo));
2729 2726 goto done;
2730 2727 }
2731 2728
2732 2729 (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
2733 2730
2734 2731 /*
2735 2732 * Fusion-MPT stores fields in little-endian format. This is
2736 2733 * why the low-order 32 bits are stored first.
2737 2734 */
2738 2735
2739 2736 for (i = 0; i < 16; i++) {
2740 2737 mpt->m_MANU_page0.ChipName[i] =
2741 2738 ddi_get8(page_accessp,
2742 2739 (uint8_t *)(void *)&m0->ChipName[i]);
2743 2740 }
2744 2741
2745 2742 for (i = 0; i < 8; i++) {
2746 2743 mpt->m_MANU_page0.ChipRevision[i] =
2747 2744 ddi_get8(page_accessp,
2748 2745 (uint8_t *)(void *)&m0->ChipRevision[i]);
2749 2746 }
2750 2747
2751 2748 for (i = 0; i < 16; i++) {
2752 2749 mpt->m_MANU_page0.BoardName[i] =
2753 2750 ddi_get8(page_accessp,
2754 2751 (uint8_t *)(void *)&m0->BoardName[i]);
2755 2752 }
2756 2753
2757 2754 for (i = 0; i < 16; i++) {
2758 2755 mpt->m_MANU_page0.BoardAssembly[i] =
2759 2756 ddi_get8(page_accessp,
2760 2757 (uint8_t *)(void *)&m0->BoardAssembly[i]);
2761 2758 }
2762 2759
2763 2760 for (i = 0; i < 16; i++) {
2764 2761 mpt->m_MANU_page0.BoardTracerNumber[i] =
2765 2762 ddi_get8(page_accessp,
2766 2763 (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
2767 2764 }
2768 2765
2769 2766 if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
2770 2767 (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
2771 2768 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2772 2769 rval = DDI_FAILURE;
2773 2770 goto done;
2774 2771 }
2775 2772 if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
2776 2773 (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
2777 2774 ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
2778 2775 rval = DDI_FAILURE;
2779 2776 }
2780 2777 done:
2781 2778 /*
2782 2779 * free up memory
2783 2780 */
2784 2781 if (free_recv)
2785 2782 mptsas_dma_addr_destroy(&recv_dma_handle, &recv_accessp);
2786 2783 if (free_page)
2787 2784 mptsas_dma_addr_destroy(&page_dma_handle, &page_accessp);
2788 2785 MPTSAS_ENABLE_INTR(mpt);
2789 2786
2790 2787 return (rval);
2791 2788 }
↓ open down ↓ |
1732 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX