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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 #include <sys/scsi/impl/usmp.h>
31 * Pass usmp_cmd into ioctl
34 SendSMPPassThru(const char *devpath
, void *reqframe
, HBA_UINT32
*reqsize
,
35 void *rspframe
, HBA_UINT32
*rspsize
) {
36 const char ROUTINE
[] = "SendSMPPassThru";
41 bzero(&ucmd_buf
, sizeof (ucmd_buf
));
43 ucmd_buf
.usmp_req
= (caddr_t
)reqframe
;
44 ucmd_buf
.usmp_rsp
= (caddr_t
)rspframe
;
45 ucmd_buf
.usmp_reqsize
= (size_t)(*reqsize
);
46 ucmd_buf
.usmp_rspsize
= (size_t)(*rspsize
);
47 ucmd_buf
.usmp_timeout
= SMP_DEFAULT_TIMEOUT
;
53 if ((fd
= open(devpath
, O_RDONLY
| O_NONBLOCK
)) == -1) {
54 log(LOG_DEBUG
, ROUTINE
,
55 "open devpath %s failed due to %s",
56 devpath
, strerror(errno
));
57 return (HBA_STATUS_ERROR
);
63 if (ioctl(fd
, USMPFUNC
, &ucmd_buf
) == -1) {
64 if ((errno
== ETIME
) || (errno
== ETIMEDOUT
) ||
66 ret
= HBA_STATUS_ERROR_TRY_AGAIN
;
67 } else if (errno
== EBUSY
) {
68 ret
= HBA_STATUS_ERROR_BUSY
;
70 ret
= HBA_STATUS_ERROR
;
72 log(LOG_DEBUG
, ROUTINE
, "ioctl:USMPFUNC failed due to %s",
79 return (HBA_STATUS_OK
);
83 * Send a USMP command to a remote SMP node
86 Sun_sasSendSMPPassThru(HBA_HANDLE handle
, HBA_WWN hbaPortWWN
,
87 HBA_WWN destPortWWN
, HBA_WWN domainPortWWN
, void *pReqBuffer
,
88 HBA_UINT32 ReqBufferSize
, void *pRspBuffer
, HBA_UINT32
*pRspBufferSize
)
90 const char ROUTINE
[] = "Sun_sasSendSMPPassThru";
92 struct sun_sas_hba
*hba_ptr
;
93 int domainPortFound
= 0;
94 int chkDomainPort
= 0;
96 struct sun_sas_port
*hba_port_ptr
, *hba_disco_port
;
101 /* Validate the arguments */
102 if (pRspBuffer
== NULL
) {
103 log(LOG_DEBUG
, ROUTINE
, "NULL response buffer");
104 return (HBA_STATUS_ERROR_ARG
);
106 if (pReqBuffer
== NULL
) {
107 log(LOG_DEBUG
, ROUTINE
, "NULL sense buffer");
108 return (HBA_STATUS_ERROR_ARG
);
110 if (pRspBufferSize
== NULL
) {
111 log(LOG_DEBUG
, ROUTINE
, "NULL response size");
112 return (HBA_STATUS_ERROR_ARG
);
115 lock(&all_hbas_lock
);
116 if ((hba_ptr
= Retrieve_Sun_sasHandle(handle
)) == NULL
) {
117 log(LOG_DEBUG
, ROUTINE
, "Invalid handle %08lx", handle
);
118 unlock(&all_hbas_lock
);
119 return (HBA_STATUS_ERROR_INVALID_HANDLE
);
122 /* Check for stale data */
123 status
= verifyAdapter(hba_ptr
);
124 if (status
!= HBA_STATUS_OK
) {
125 log(LOG_DEBUG
, ROUTINE
, "Verify adapter failed");
126 unlock(&all_hbas_lock
);
131 * We are not checking to see if our data is stale.
132 * By verifying this information here, we will take a big performance
133 * hit. This check will be done later only if the Inquiry ioctl fails
136 if (hba_ptr
->device_path
== NULL
) {
137 log(LOG_DEBUG
, ROUTINE
,
138 "HBA handle had NULL device path.\
139 Unable to send SCSI cmd");
140 unlock(&all_hbas_lock
);
141 return (HBA_STATUS_ERROR
);
144 if (wwnConversion(domainPortWWN
.wwn
))
147 /* Determine which port to use */
148 for (hba_port_ptr
= hba_ptr
->first_port
;
149 hba_port_ptr
!= NULL
;
150 hba_port_ptr
= hba_port_ptr
->next
) {
152 if (hbaPortFound
== 0) {
153 if (wwnConversion(hba_port_ptr
->port_attributes
.
154 PortSpecificAttribute
.SASPort
->LocalSASAddress
.wwn
)
155 != wwnConversion(hbaPortWWN
.wwn
)) {
157 * Since all the ports under the same HBA have
158 * the same LocalSASAddress, we should break
159 * the loop once we find it dosn't match.
167 if (chkDomainPort
!= 0) {
168 if (hba_port_ptr
->first_phy
!= NULL
&&
169 wwnConversion(hba_port_ptr
->first_phy
->
170 phy
.domainPortWWN
.wwn
) ==
171 wwnConversion(domainPortWWN
.wwn
)) {
174 if (!(domainPortFound
)) {
179 for (hba_disco_port
= hba_port_ptr
->first_attached_port
;
180 hba_disco_port
!= NULL
;
181 hba_disco_port
= hba_disco_port
->next
) {
184 * If discoveredPort is not given targetPort, just skip
186 if (wwnConversion(hba_disco_port
->port_attributes
.\
187 PortSpecificAttribute
.SASPort
->LocalSASAddress
.wwn
)
188 != wwnConversion(destPortWWN
.wwn
)) {
194 * If matching targetPort does not support SMP protocal
196 * comment it out for testing only
198 if ((hba_disco_port
->port_attributes
.\
199 PortSpecificAttribute
.SASPort
->PortProtocol
&
200 HBA_SASPORTPROTOCOL_SMP
) == 0) {
201 log(LOG_DEBUG
, ROUTINE
, "Input WWN %01611x\
202 does not support SMP protocol",
203 wwnConversion(hbaPortWWN
.wwn
));
204 unlock(&all_hbas_lock
);
205 return (HBA_STATUS_ERROR_INVALID_PROTOCOL_TYPE
);
209 * SMP target port doesn't have any scsi info.
210 * - like /dev/rdsk/cxtxdxsx
211 * So we use OSDeviceName from port attributes.
212 * - like /dev/smp/expd[0-9]
214 status
= SendSMPPassThru(
215 hba_disco_port
->port_attributes
.OSDeviceName
,
216 pReqBuffer
, &ReqBufferSize
,
217 pRspBuffer
, pRspBufferSize
);
219 unlock(&all_hbas_lock
);
221 duration
= end
- start
;
222 duration
/= HR_SECOND
;
223 log(LOG_DEBUG
, ROUTINE
, "Took total\
224 of %.4f seconds", duration
);
228 unlock(&all_hbas_lock
);
229 log(LOG_DEBUG
, ROUTINE
, "Unable to locate"
230 "requested SMP target port %16llx",
231 wwnConversion(destPortWWN
.wwn
));
232 return (HBA_STATUS_ERROR_ILLEGAL_WWN
);
235 unlock(&all_hbas_lock
);
236 if (hbaPortFound
== 0) {
237 log(LOG_DEBUG
, ROUTINE
,
238 "Unable to locate requested Port WWN %016llx on "
239 "handle %08lx", wwnConversion(hbaPortWWN
.wwn
), handle
);
240 } else if (chkDomainPort
&& !domainPortFound
) {
241 log(LOG_DEBUG
, ROUTINE
, "Unable to locate requested"
242 " domainPortWWN %016llx on handle %08lx",
243 wwnConversion(domainPortWWN
.wwn
), handle
);
245 log(LOG_DEBUG
, ROUTINE
, "Unable to locate"
246 "requested SMP target port %16llx",
247 wwnConversion(destPortWWN
.wwn
));
249 return (HBA_STATUS_ERROR_ILLEGAL_WWN
);