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