mptsas_init.c revision 9907:98086c85a8f7
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Copyright (c) 2000 to 2009, LSI Corporation.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms of all code within
32 * this file that is exclusively owned by LSI, with or without
33 * modification, is permitted provided that, in addition to the CDDL 1.0
34 * License requirements, the following conditions are met:
35 *
36 *    Neither the name of the author nor the names of its contributors may be
37 *    used to endorse or promote products derived from this software without
38 *    specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
43 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
44 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
45 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
46 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
47 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
48 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
51 * DAMAGE.
52 */
53
54/*
55 * mptsas_init - This file contains all the functions used to initialize
56 * MPT2.0 based hardware.
57 */
58
59#if defined(lint) || defined(DEBUG)
60#define	MPTSAS_DEBUG
61#endif
62
63/*
64 * standard header files
65 */
66#include <sys/note.h>
67#include <sys/scsi/scsi.h>
68
69#pragma pack(1)
70#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
71#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
72#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
73#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
74#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
75#pragma pack()
76/*
77 * private header files.
78 */
79#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
80
81static int mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
82	ddi_acc_handle_t accessp);
83static int mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
84	ddi_acc_handle_t accessp);
85static int mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
86	ddi_acc_handle_t accessp);
87static int mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp,
88    int var, ddi_acc_handle_t accessp);
89static int mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
90	ddi_acc_handle_t accessp);
91static int mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
92	ddi_acc_handle_t accessp);
93static int mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp,
94	int var, ddi_acc_handle_t accessp);
95static int mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt,
96    caddr_t memp, int var, ddi_acc_handle_t accessp);
97static int mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
98	ddi_acc_handle_t accessp);
99static int mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
100	ddi_acc_handle_t accessp);
101
102static const char *
103mptsas_product_type_string(mptsas_t *mpt)
104{
105	switch (mpt->m_productid & MPI2_FW_HEADER_PID_PROD_MASK) {
106
107	case MPI2_FW_HEADER_PID_PROD_A:
108		return ("A");
109	default:
110		return ("?");
111	}
112}
113
114int
115mptsas_ioc_get_facts(mptsas_t *mpt)
116{
117	/*
118	 * Send get facts messages
119	 */
120	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REQUEST), NULL,
121	    mptsas_ioc_do_get_facts)) {
122		return (DDI_FAILURE);
123	}
124
125	/*
126	 * Get facts reply messages
127	 */
128	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_FACTS_REPLY), NULL,
129	    mptsas_ioc_do_get_facts_reply)) {
130		return (DDI_FAILURE);
131	}
132
133	return (DDI_SUCCESS);
134}
135
136static int
137mptsas_ioc_do_get_facts(mptsas_t *mpt, caddr_t memp, int var,
138		ddi_acc_handle_t accessp)
139{
140#ifndef __lock_lint
141	_NOTE(ARGUNUSED(var))
142#endif
143	pMpi2IOCFactsRequest_t	facts;
144	int			numbytes;
145
146	bzero(memp, sizeof (*facts));
147	facts = (void *)memp;
148	ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_IOC_FACTS);
149	numbytes = sizeof (*facts);
150
151	/*
152	 * Post message via handshake
153	 */
154	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
155		return (DDI_FAILURE);
156	}
157
158	return (DDI_SUCCESS);
159}
160
161static int
162mptsas_ioc_do_get_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
163		ddi_acc_handle_t accessp)
164{
165#ifndef __lock_lint
166	_NOTE(ARGUNUSED(var))
167#endif
168
169	pMpi2IOCFactsReply_t	factsreply;
170	int			numbytes;
171	uint_t			iocstatus;
172	char			buf[32];
173	uint16_t		numReplyFrames;
174	uint16_t		queueSize, queueDiff;
175	int			simple_sge_main;
176	int			simple_sge_next;
177
178	bzero(memp, sizeof (*factsreply));
179	factsreply = (void *)memp;
180	numbytes = sizeof (*factsreply);
181
182	/*
183	 * get ioc facts reply message
184	 */
185	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
186		return (DDI_FAILURE);
187	}
188
189	if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) {
190		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_facts_reply: "
191		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
192		    ddi_get32(accessp, &factsreply->IOCLogInfo));
193		return (DDI_FAILURE);
194	}
195
196	/*
197	 * store key values from reply to mpt structure
198	 */
199	mpt->m_fwversion = ddi_get32(accessp, &factsreply->FWVersion.Word);
200	mpt->m_productid = ddi_get16(accessp, &factsreply->ProductID);
201
202
203	(void) sprintf(buf, "%u.%u.%u.%u",
204	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Major),
205	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Minor),
206	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Unit),
207	    ddi_get8(accessp, &factsreply->FWVersion.Struct.Dev));
208	mptsas_log(mpt, CE_NOTE, "?mpt%d Firmware version v%s (%s)\n",
209	    mpt->m_instance, buf, mptsas_product_type_string(mpt));
210	(void) ddi_prop_update_string(DDI_DEV_T_NONE, mpt->m_dip,
211	    "firmware-version", buf);
212
213	/*
214	 * Set up request info.
215	 */
216	mpt->m_max_requests = ddi_get16(accessp,
217	    &factsreply->RequestCredit) - 1;
218	mpt->m_req_frame_size = ddi_get16(accessp,
219	    &factsreply->IOCRequestFrameSize) * 4;
220
221	/*
222	 * Size of reply free queue should be the number of requests
223	 * plus some additional for events (32).  Make sure number of
224	 * reply frames is not a multiple of 16 so that the queue sizes
225	 * are calculated correctly later to be a multiple of 16.
226	 */
227	mpt->m_reply_frame_size = ddi_get8(accessp,
228	    &factsreply->ReplyFrameSize) * 4;
229	numReplyFrames = mpt->m_max_requests + 32;
230	if (!(numReplyFrames % 16)) {
231		numReplyFrames--;
232	}
233	mpt->m_max_replies = numReplyFrames;
234	queueSize = numReplyFrames;
235	queueSize += 16 - (queueSize % 16);
236	mpt->m_free_queue_depth = queueSize;
237
238	/*
239	 * Size of reply descriptor post queue should be the number of
240	 * request frames + the number of reply frames + 1 and needs to
241	 * be a multiple of 16.  This size can be no larger than
242	 * MaxReplyDescriptorPostQueueDepth from IOCFacts.  If the
243	 * calculated queue size is larger than allowed, subtract a
244	 * multiple of 16 from m_max_requests, m_max_replies, and
245	 * m_reply_free_depth.
246	 */
247	queueSize = mpt->m_max_requests + numReplyFrames + 1;
248	if (queueSize % 16) {
249		queueSize += 16 - (queueSize % 16);
250	}
251	mpt->m_post_queue_depth = ddi_get16(accessp,
252	    &factsreply->MaxReplyDescriptorPostQueueDepth);
253	if (queueSize > mpt->m_post_queue_depth) {
254		queueDiff = queueSize - mpt->m_post_queue_depth;
255		if (queueDiff % 16) {
256			queueDiff += 16 - (queueDiff % 16);
257		}
258		mpt->m_max_requests -= queueDiff;
259		mpt->m_max_replies -= queueDiff;
260		mpt->m_free_queue_depth -= queueDiff;
261		queueSize -= queueDiff;
262	}
263	mpt->m_post_queue_depth = queueSize;
264
265	/*
266	 * Set up other stuff.
267	 */
268	mpt->m_max_chain_depth = ddi_get8(accessp,
269	    &factsreply->MaxChainDepth);
270
271	/*
272	 * Calculate max frames per request based on DMA S/G length.
273	 */
274
275	simple_sge_main = MPTSAS_MAX_FRAME_SGES64(mpt) - 1;
276	simple_sge_next = mpt->m_req_frame_size /
277	    sizeof (MPI2_SGE_SIMPLE64) - 1;
278
279	mpt->m_max_request_frames = (MPTSAS_MAX_DMA_SEGS -
280	    simple_sge_main) / simple_sge_next + 1;
281	if (((MPTSAS_MAX_DMA_SEGS - simple_sge_main) %
282	    simple_sge_next) > 1) {
283		mpt->m_max_request_frames++;
284	}
285
286	return (DDI_SUCCESS);
287}
288
289int
290mptsas_ioc_get_port_facts(mptsas_t *mpt, int port)
291{
292	/*
293	 * Send get port facts message
294	 */
295	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REQUEST), port,
296	    mptsas_ioc_do_get_port_facts)) {
297		return (DDI_FAILURE);
298	}
299
300	/*
301	 * Get port facts reply message
302	 */
303	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_FACTS_REPLY), port,
304	    mptsas_ioc_do_get_port_facts_reply)) {
305		return (DDI_FAILURE);
306	}
307
308	return (DDI_SUCCESS);
309}
310
311static int
312mptsas_ioc_do_get_port_facts(mptsas_t *mpt, caddr_t memp, int var,
313			ddi_acc_handle_t accessp)
314{
315	pMpi2PortFactsRequest_t	facts;
316	int			numbytes;
317
318	bzero(memp, sizeof (*facts));
319	facts = (void *)memp;
320	ddi_put8(accessp, &facts->Function, MPI2_FUNCTION_PORT_FACTS);
321	ddi_put8(accessp, &facts->PortNumber, var);
322	numbytes = sizeof (*facts);
323
324	/*
325	 * Send port facts message via handshake
326	 */
327	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
328		return (DDI_FAILURE);
329	}
330
331	return (DDI_SUCCESS);
332}
333
334static int
335mptsas_ioc_do_get_port_facts_reply(mptsas_t *mpt, caddr_t memp, int var,
336				ddi_acc_handle_t accessp)
337{
338#ifndef __lock_lint
339	_NOTE(ARGUNUSED(var))
340#endif
341	pMpi2PortFactsReply_t	factsreply;
342	int			numbytes;
343	uint_t			iocstatus;
344
345	bzero(memp, sizeof (*factsreply));
346	factsreply = (void *)memp;
347	numbytes = sizeof (*factsreply);
348
349	/*
350	 * Get port facts reply message via handshake
351	 */
352	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
353		return (DDI_FAILURE);
354	}
355
356	if (iocstatus = ddi_get16(accessp, &factsreply->IOCStatus)) {
357		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_get_port_facts_reply: "
358		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
359		    ddi_get32(accessp, &factsreply->IOCLogInfo));
360		return (DDI_FAILURE);
361	}
362
363	return (DDI_SUCCESS);
364}
365
366int
367mptsas_ioc_enable_port(mptsas_t *mpt)
368{
369	/*
370	 * Send enable port message
371	 */
372	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REQUEST), 0,
373	    mptsas_ioc_do_enable_port)) {
374		return (DDI_FAILURE);
375	}
376
377	/*
378	 * Get enable port reply message
379	 */
380	if (mptsas_do_dma(mpt, sizeof (MPI2_PORT_ENABLE_REPLY), 0,
381	    mptsas_ioc_do_enable_port_reply)) {
382		return (DDI_FAILURE);
383	}
384
385	return (DDI_SUCCESS);
386}
387
388static int
389mptsas_ioc_do_enable_port(mptsas_t *mpt, caddr_t memp, int var,
390	ddi_acc_handle_t accessp)
391{
392#ifndef __lock_lint
393	_NOTE(ARGUNUSED(var))
394#endif
395	pMpi2PortEnableRequest_t	enable;
396	int				numbytes;
397
398	bzero(memp, sizeof (*enable));
399	enable = (void *)memp;
400	ddi_put8(accessp, &enable->Function, MPI2_FUNCTION_PORT_ENABLE);
401	numbytes = sizeof (*enable);
402
403	/*
404	 * Send message via handshake
405	 */
406	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
407		return (DDI_FAILURE);
408	}
409
410	return (DDI_SUCCESS);
411}
412
413static int
414mptsas_ioc_do_enable_port_reply(mptsas_t *mpt, caddr_t memp, int var,
415	ddi_acc_handle_t accessp)
416{
417#ifndef __lock_lint
418	_NOTE(ARGUNUSED(var))
419#endif
420
421	int			numbytes;
422	uint_t			iocstatus;
423	pMpi2PortEnableReply_t	portreply;
424
425	numbytes = sizeof (MPI2_PORT_ENABLE_REPLY);
426	bzero(memp, numbytes);
427	portreply = (void *)memp;
428
429	/*
430	 * Get message via handshake
431	 */
432	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
433		return (DDI_FAILURE);
434	}
435
436	if (iocstatus = ddi_get16(accessp, &portreply->IOCStatus)) {
437		mptsas_log(mpt, CE_WARN, "mptsas_ioc_do_enable_port_reply: "
438		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
439		    ddi_get32(accessp, &portreply->IOCLogInfo));
440		return (DDI_FAILURE);
441	}
442
443	return (DDI_SUCCESS);
444}
445
446int
447mptsas_ioc_enable_event_notification(mptsas_t *mpt)
448{
449	ASSERT(mutex_owned(&mpt->m_mutex));
450
451	/*
452	 * Send enable event notification message
453	 */
454	if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REQUEST), NULL,
455	    mptsas_ioc_do_enable_event_notification)) {
456		return (DDI_FAILURE);
457	}
458
459	/*
460	 * Get enable event reply message
461	 */
462	if (mptsas_do_dma(mpt, sizeof (MPI2_EVENT_NOTIFICATION_REPLY), NULL,
463	    mptsas_ioc_do_enable_event_notification_reply)) {
464		return (DDI_FAILURE);
465	}
466
467	return (DDI_SUCCESS);
468}
469
470static int
471mptsas_ioc_do_enable_event_notification(mptsas_t *mpt, caddr_t memp, int var,
472	ddi_acc_handle_t accessp)
473{
474#ifndef __lock_lint
475	_NOTE(ARGUNUSED(var))
476#endif
477
478	pMpi2EventNotificationRequest_t	event;
479	int				numbytes;
480
481	bzero(memp, sizeof (*event));
482	event = (void *)memp;
483	ddi_put8(accessp, &event->Function, MPI2_FUNCTION_EVENT_NOTIFICATION);
484	numbytes = sizeof (*event);
485
486	/*
487	 * Send message via handshake
488	 */
489	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
490		return (DDI_FAILURE);
491	}
492
493	return (DDI_SUCCESS);
494}
495
496static int
497mptsas_ioc_do_enable_event_notification_reply(mptsas_t *mpt, caddr_t memp,
498    int var, ddi_acc_handle_t accessp)
499{
500#ifndef __lock_lint
501	_NOTE(ARGUNUSED(var))
502#endif
503	int				numbytes;
504	uint_t				iocstatus;
505	pMpi2EventNotificationReply_t	eventsreply;
506
507	numbytes = sizeof (MPI2_EVENT_NOTIFICATION_REPLY);
508	bzero(memp, numbytes);
509	eventsreply = (void *)memp;
510
511	/*
512	 * Get message via handshake
513	 */
514	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
515		return (DDI_FAILURE);
516	}
517
518	if (iocstatus = ddi_get16(accessp, &eventsreply->IOCStatus)) {
519		mptsas_log(mpt, CE_WARN,
520		    "mptsas_ioc_do_enable_event_notification_reply: "
521		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
522		    ddi_get32(accessp, &eventsreply->IOCLogInfo));
523		return (DDI_FAILURE);
524	}
525
526	return (DDI_SUCCESS);
527}
528
529int
530mptsas_ioc_init(mptsas_t *mpt)
531{
532	/*
533	 * Send ioc init message
534	 */
535	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REQUEST), NULL,
536	    mptsas_do_ioc_init)) {
537		return (DDI_FAILURE);
538	}
539
540	/*
541	 * Get ioc init reply message
542	 */
543	if (mptsas_do_dma(mpt, sizeof (MPI2_IOC_INIT_REPLY), NULL,
544	    mptsas_do_ioc_init_reply)) {
545		return (DDI_FAILURE);
546	}
547
548	return (DDI_SUCCESS);
549}
550
551static int
552mptsas_do_ioc_init(mptsas_t *mpt, caddr_t memp, int var,
553    ddi_acc_handle_t accessp)
554{
555#ifndef __lock_lint
556	_NOTE(ARGUNUSED(var))
557#endif
558
559	pMpi2IOCInitRequest_t	init;
560	int			numbytes;
561
562	bzero(memp, sizeof (*init));
563	init = (void *)memp;
564	ddi_put8(accessp, &init->Function, MPI2_FUNCTION_IOC_INIT);
565	ddi_put8(accessp, &init->WhoInit, MPI2_WHOINIT_HOST_DRIVER);
566	ddi_put16(accessp, &init->MsgVersion, MPI2_VERSION);
567	ddi_put16(accessp, &init->HeaderVersion, MPI2_HEADER_VERSION);
568	ddi_put16(accessp, &init->SystemRequestFrameSize,
569	    mpt->m_req_frame_size / 4);
570	ddi_put16(accessp, &init->ReplyDescriptorPostQueueDepth,
571	    mpt->m_post_queue_depth);
572	ddi_put16(accessp, &init->ReplyFreeQueueDepth,
573	    mpt->m_free_queue_depth);
574
575	/*
576	 * These addresses are set using the DMA cookie addresses from when the
577	 * memory was allocated.  Sense buffer hi address should be 0.
578	 */
579	ddi_put32(accessp, &init->SenseBufferAddressHigh, 0);
580	ddi_put32(accessp, &init->SystemReplyAddressHigh,
581	    (uint32_t)(mpt->m_reply_frame_dma_addr >> 32));
582	ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.High,
583	    (uint32_t)(mpt->m_req_frame_dma_addr >> 32));
584	ddi_put32(accessp, &init->SystemRequestFrameBaseAddress.Low,
585	    (uint32_t)mpt->m_req_frame_dma_addr);
586	ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.High,
587	    (uint32_t)(mpt->m_post_queue_dma_addr >> 32));
588	ddi_put32(accessp, &init->ReplyDescriptorPostQueueAddress.Low,
589	    (uint32_t)mpt->m_post_queue_dma_addr);
590	ddi_put32(accessp, &init->ReplyFreeQueueAddress.High,
591	    (uint32_t)(mpt->m_free_queue_dma_addr >> 32));
592	ddi_put32(accessp, &init->ReplyFreeQueueAddress.Low,
593	    (uint32_t)mpt->m_free_queue_dma_addr);
594
595	numbytes = sizeof (*init);
596
597	/*
598	 * Post message via handshake
599	 */
600	if (mptsas_send_handshake_msg(mpt, memp, numbytes, accessp)) {
601		return (DDI_FAILURE);
602	}
603
604	return (DDI_SUCCESS);
605}
606
607static int
608mptsas_do_ioc_init_reply(mptsas_t *mpt, caddr_t memp, int var,
609		ddi_acc_handle_t accessp)
610{
611#ifndef __lock_lint
612	_NOTE(ARGUNUSED(var))
613#endif
614
615	pMpi2IOCInitReply_t	initreply;
616	int			numbytes;
617	uint_t			iocstatus;
618
619	numbytes = sizeof (MPI2_IOC_INIT_REPLY);
620	bzero(memp, numbytes);
621	initreply = (void *)memp;
622
623	/*
624	 * Get reply message via handshake
625	 */
626	if (mptsas_get_handshake_msg(mpt, memp, numbytes, accessp)) {
627		return (DDI_FAILURE);
628	}
629
630	if (iocstatus = ddi_get16(accessp, &initreply->IOCStatus)) {
631		mptsas_log(mpt, CE_WARN, "mptsas_do_ioc_init_reply: "
632		    "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
633		    ddi_get32(accessp, &initreply->IOCLogInfo));
634		return (DDI_FAILURE);
635	}
636
637	if ((ddi_get32(mpt->m_datap, &mpt->m_reg->Doorbell)) &
638	    MPI2_IOC_STATE_OPERATIONAL) {
639		mptsas_log(mpt, CE_NOTE,
640		    "?mpt%d: IOC Operational.\n", mpt->m_instance);
641	} else {
642		return (DDI_FAILURE);
643	}
644
645	return (DDI_SUCCESS);
646}
647