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 Emulex. All rights reserved. 24 * Use is subject to License terms. 25 */ 26 27 #include <emlxs.h> 28 29 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 30 EMLXS_MSG_DEF(EMLXS_PKT_C); 31 32 #if (EMLXS_MODREV >= EMLXS_MODREV3) 33 typedef struct _emlxs_pkt_cookie_t 34 { 35 ddi_dma_cookie_t pkt_cmd_cookie; 36 ddi_dma_cookie_t pkt_resp_cookie; 37 ddi_dma_cookie_t pkt_data_cookie; 38 39 } emlxs_pkt_cookie_t; 40 #endif /* >= EMLXS_MODREV3 */ 41 42 43 /* ARGSUSED */ 44 static void 45 emlxs_pkt_thread(emlxs_hba_t *hba, void *arg1, void *arg2) 46 { 47 emlxs_port_t *port; 48 fc_packet_t *pkt = (fc_packet_t *)arg1; 49 int32_t rval; 50 emlxs_buf_t *sbp; 51 52 sbp = PKT2PRIV(pkt); 53 port = sbp->port; 54 55 /* Send the pkt now */ 56 rval = emlxs_pkt_send(pkt, 1); 57 58 if (rval != FC_SUCCESS) { 59 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg, 60 "Deferred emlxs_pkt_send failed: status=%x pkt=%p", rval, 61 pkt); 62 63 if (pkt->pkt_comp) { 64 emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT, 0, 1); 65 66 (*pkt->pkt_comp) (pkt); 67 } else { 68 emlxs_pkt_free(pkt); 69 } 70 } 71 72 return; 73 74 } /* emlxs_pkt_thread() */ 75 76 77 extern int32_t 78 emlxs_pkt_send(fc_packet_t *pkt, uint32_t now) 79 { 80 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private; 81 emlxs_hba_t *hba = HBA; 82 int32_t rval; 83 84 if (now) { 85 rval = emlxs_transport((opaque_t)port, pkt); 86 } else { 87 /* Spawn a thread to send the pkt */ 88 emlxs_thread_spawn(hba, emlxs_pkt_thread, (char *)pkt, NULL); 89 90 rval = FC_SUCCESS; 91 } 92 93 return (rval); 94 95 } /* emlxs_pkt_send() */ 96 97 98 extern void 99 emlxs_pkt_free(fc_packet_t *pkt) 100 { 101 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private; 102 103 (void) emlxs_pkt_uninit((opaque_t)port, pkt); 104 105 if (pkt->pkt_datalen) { 106 (void) ddi_dma_unbind_handle(pkt->pkt_data_dma); 107 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 108 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 109 } 110 111 if (pkt->pkt_rsplen) { 112 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 113 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 114 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 115 } 116 117 if (pkt->pkt_cmdlen) { 118 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 119 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 120 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 121 } 122 #if (EMLXS_MODREV >= EMLXS_MODREV3) 123 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t) + 124 sizeof (emlxs_pkt_cookie_t))); 125 #else 126 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t))); 127 #endif /* >= EMLXS_MODREV3 */ 128 129 return; 130 131 } /* emlxs_pkt_free() */ 132 133 134 /* Default pkt callback routine */ 135 extern void 136 emlxs_pkt_callback(fc_packet_t *pkt) 137 { 138 emlxs_pkt_free(pkt); 139 140 return; 141 142 } /* emlxs_pkt_callback() */ 143 144 145 146 extern fc_packet_t * 147 emlxs_pkt_alloc(emlxs_port_t *port, uint32_t cmdlen, uint32_t rsplen, 148 uint32_t datalen, int32_t sleep) 149 { 150 emlxs_hba_t *hba = HBA; 151 fc_packet_t *pkt; 152 int32_t(*cb) (caddr_t); 153 unsigned long real_len; 154 uint32_t pkt_size; 155 emlxs_buf_t *sbp; 156 157 #if (EMLXS_MODREV >= EMLXS_MODREV3) 158 emlxs_pkt_cookie_t *pkt_cookie; 159 160 pkt_size = 161 sizeof (fc_packet_t) + sizeof (emlxs_buf_t) + 162 sizeof (emlxs_pkt_cookie_t); 163 #else 164 uint32_t num_cookie; 165 166 pkt_size = sizeof (fc_packet_t) + sizeof (emlxs_buf_t); 167 #endif /* >= EMLXS_MODREV3 */ 168 169 170 /* Allocate some space */ 171 if (!(pkt = (fc_packet_t *)kmem_alloc(pkt_size, sleep))) { 172 return (NULL); 173 } 174 175 bzero(pkt, pkt_size); 176 177 cb = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 178 179 pkt->pkt_ulp_private = (opaque_t)port; 180 pkt->pkt_fca_private = 181 (opaque_t)((uintptr_t)pkt + sizeof (fc_packet_t)); 182 pkt->pkt_comp = emlxs_pkt_callback; 183 pkt->pkt_tran_flags = (FC_TRAN_CLASS3 | FC_TRAN_INTR); 184 pkt->pkt_cmdlen = cmdlen; 185 pkt->pkt_rsplen = rsplen; 186 pkt->pkt_datalen = datalen; 187 188 #if (EMLXS_MODREV >= EMLXS_MODREV3) 189 pkt_cookie = 190 (emlxs_pkt_cookie_t *)((uintptr_t)pkt + sizeof (fc_packet_t) + 191 sizeof (emlxs_buf_t)); 192 pkt->pkt_cmd_cookie = &pkt_cookie->pkt_cmd_cookie; 193 pkt->pkt_resp_cookie = &pkt_cookie->pkt_resp_cookie; 194 pkt->pkt_data_cookie = &pkt_cookie->pkt_data_cookie; 195 #endif /* >= EMLXS_MODREV3 */ 196 197 if (cmdlen) { 198 /* Allocate the cmd buf */ 199 if (ddi_dma_alloc_handle(hba->dip, &emlxs_dma_attr_1sg, cb, 200 NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) { 201 cmdlen = 0; 202 rsplen = 0; 203 datalen = 0; 204 goto failed; 205 } 206 207 if (ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmdlen, 208 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL, 209 (caddr_t *)&pkt->pkt_cmd, &real_len, 210 &pkt->pkt_cmd_acc) != DDI_SUCCESS) { 211 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 212 213 cmdlen = 0; 214 rsplen = 0; 215 datalen = 0; 216 goto failed; 217 } 218 219 if (real_len < cmdlen) { 220 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 221 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 222 223 cmdlen = 0; 224 rsplen = 0; 225 datalen = 0; 226 goto failed; 227 } 228 #if (EMLXS_MODREV >= EMLXS_MODREV3) 229 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 230 pkt->pkt_cmd, real_len, 231 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL, 232 pkt->pkt_cmd_cookie, 233 &pkt->pkt_cmd_cookie_cnt) != DDI_DMA_MAPPED) 234 #else 235 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 236 pkt->pkt_cmd, real_len, 237 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL, 238 &pkt->pkt_cmd_cookie, &num_cookie) != DDI_DMA_MAPPED) 239 #endif /* >= EMLXS_MODREV3 */ 240 { 241 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 242 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 243 244 cmdlen = 0; 245 rsplen = 0; 246 datalen = 0; 247 goto failed; 248 } 249 #if (EMLXS_MODREV >= EMLXS_MODREV3) 250 if (pkt->pkt_cmd_cookie_cnt != 1) 251 #else 252 if (num_cookie != 1) 253 #endif /* >= EMLXS_MODREV3 */ 254 { 255 rsplen = 0; 256 datalen = 0; 257 goto failed; 258 } 259 260 bzero(pkt->pkt_cmd, cmdlen); 261 262 } 263 264 if (rsplen) { 265 /* Allocate the rsp buf */ 266 if (ddi_dma_alloc_handle(hba->dip, &emlxs_dma_attr_1sg, cb, 267 NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) { 268 rsplen = 0; 269 datalen = 0; 270 goto failed; 271 272 } 273 274 if (ddi_dma_mem_alloc(pkt->pkt_resp_dma, rsplen, 275 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL, 276 (caddr_t *)&pkt->pkt_resp, &real_len, 277 &pkt->pkt_resp_acc) != DDI_SUCCESS) { 278 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 279 280 rsplen = 0; 281 datalen = 0; 282 goto failed; 283 } 284 285 if (real_len < rsplen) { 286 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 287 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 288 289 rsplen = 0; 290 datalen = 0; 291 goto failed; 292 } 293 #if (EMLXS_MODREV >= EMLXS_MODREV3) 294 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 295 pkt->pkt_resp, real_len, 296 DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL, 297 pkt->pkt_resp_cookie, 298 &pkt->pkt_resp_cookie_cnt) != DDI_DMA_MAPPED) 299 #else 300 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 301 pkt->pkt_resp, real_len, 302 DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL, 303 &pkt->pkt_resp_cookie, &num_cookie) != DDI_DMA_MAPPED) 304 #endif /* >= EMLXS_MODREV3 */ 305 { 306 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 307 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 308 309 rsplen = 0; 310 datalen = 0; 311 goto failed; 312 } 313 #if (EMLXS_MODREV >= EMLXS_MODREV3) 314 if (pkt->pkt_resp_cookie_cnt != 1) 315 #else 316 if (num_cookie != 1) 317 #endif /* >= EMLXS_MODREV3 */ 318 { 319 datalen = 0; 320 goto failed; 321 } 322 323 bzero(pkt->pkt_resp, rsplen); 324 325 } 326 327 /* Allocate the data buf */ 328 if (datalen) { 329 /* Allocate the rsp buf */ 330 if (ddi_dma_alloc_handle(hba->dip, &emlxs_dma_attr_1sg, cb, 331 NULL, &pkt->pkt_data_dma) != DDI_SUCCESS) { 332 datalen = 0; 333 goto failed; 334 } 335 336 if (ddi_dma_mem_alloc(pkt->pkt_data_dma, datalen, 337 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL, 338 (caddr_t *)&pkt->pkt_data, &real_len, 339 &pkt->pkt_data_acc) != DDI_SUCCESS) { 340 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 341 342 datalen = 0; 343 goto failed; 344 } 345 346 if (real_len < datalen) { 347 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 348 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 349 350 datalen = 0; 351 goto failed; 352 } 353 #if (EMLXS_MODREV >= EMLXS_MODREV3) 354 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL, 355 pkt->pkt_data, real_len, 356 DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, 357 NULL, pkt->pkt_data_cookie, 358 &pkt->pkt_data_cookie_cnt) != DDI_DMA_MAPPED) 359 #else 360 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL, 361 pkt->pkt_data, real_len, 362 DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, 363 NULL, &pkt->pkt_data_cookie, 364 &num_cookie) != DDI_DMA_MAPPED) 365 #endif /* >= EMLXS_MODREV3 */ 366 { 367 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 368 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 369 370 datalen = 0; 371 goto failed; 372 } 373 #if (EMLXS_MODREV >= EMLXS_MODREV3) 374 if (pkt->pkt_data_cookie_cnt != 1) 375 #else 376 if (num_cookie != 1) 377 #endif /* >= EMLXS_MODREV3 */ 378 { 379 goto failed; 380 } 381 382 bzero(pkt->pkt_data, datalen); 383 } 384 385 sbp = PKT2PRIV(pkt); 386 bzero((void *)sbp, sizeof (emlxs_buf_t)); 387 388 mutex_init(&sbp->mtx, NULL, MUTEX_DRIVER, (void *)hba->intr_arg); 389 sbp->pkt_flags = PACKET_VALID | PACKET_RETURNED | PACKET_ALLOCATED; 390 sbp->port = port; 391 sbp->pkt = pkt; 392 sbp->iocbq.sbp = sbp; 393 394 return (pkt); 395 396 failed: 397 398 if (datalen) { 399 (void) ddi_dma_unbind_handle(pkt->pkt_data_dma); 400 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 401 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 402 } 403 404 if (rsplen) { 405 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 406 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 407 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 408 } 409 410 if (cmdlen) { 411 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 412 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 413 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 414 } 415 416 if (pkt) { 417 kmem_free(pkt, pkt_size); 418 } 419 420 return (NULL); 421 422 } /* emlxs_pkt_alloc() */ 423