Print this page
5045 use atomic_{inc,dec}_* instead of atomic_add_*
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c
+++ new/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.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 */
25 25
26 26 /*
27 27 * This file defines interfaces between fcoe and fct driver.
28 28 */
29 29
30 30 /*
31 31 * Driver kernel header files
32 32 */
33 33 #include <sys/conf.h>
34 34 #include <sys/ddi.h>
35 35 #include <sys/stat.h>
36 36 #include <sys/pci.h>
37 37 #include <sys/sunddi.h>
38 38 #include <sys/modctl.h>
39 39 #include <sys/file.h>
40 40 #include <sys/cred.h>
41 41 #include <sys/byteorder.h>
42 42 #include <sys/atomic.h>
43 43 #include <sys/modhash.h>
44 44 #include <sys/scsi/scsi.h>
45 45 #include <sys/ethernet.h>
46 46
47 47 /*
48 48 * COMSTAR header files
49 49 */
50 50 #include <sys/stmf_defines.h>
51 51 #include <sys/fct_defines.h>
52 52 #include <sys/stmf.h>
53 53 #include <sys/portif.h>
54 54 #include <sys/fct.h>
55 55
56 56 /*
57 57 * FCoE hader files
58 58 */
59 59 #include <sys/fcoe/fcoe_common.h>
60 60
61 61 /*
62 62 * Driver's own header files
63 63 */
64 64 #include "fcoet.h"
65 65 #include "fcoet_fc.h"
66 66 #include "fcoet_eth.h"
67 67
68 68 /*
69 69 * function forward declaration
70 70 */
71 71 static fct_status_t fcoet_fill_plogi_req(fct_local_port_t *port,
72 72 fct_remote_port_t *rp, fct_cmd_t *login);
73 73 static fct_status_t fcoet_fill_plogi_resp(fct_local_port_t *port,
74 74 fct_remote_port_t *rp, fct_cmd_t *login);
75 75 static fct_status_t fcoet_send_sol_els(fct_cmd_t *cmd);
76 76 static fct_status_t fcoet_send_sol_ct(fct_cmd_t *cmd);
77 77 static fct_status_t fcoet_send_good_status(fct_cmd_t *cmd);
78 78 static fct_status_t fcoet_send_els_response(fct_cmd_t *cmd);
79 79 static fct_status_t fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags);
80 80 static fct_status_t fcoet_logo_fabric(fcoet_soft_state_t *ss);
81 81
82 82 /*
83 83 * Return the lower link information
84 84 */
85 85 fct_status_t
86 86 fcoet_get_link_info(fct_local_port_t *port, fct_link_info_t *li)
87 87 {
88 88 bcopy(&PORT2SS(port)->ss_link_info, li, sizeof (fct_link_info_t));
89 89 return (FCT_SUCCESS);
90 90 }
91 91
92 92 /*
93 93 * FCT will call this, when it wants to send PLOGI or has received PLOGI.
94 94 */
95 95 fct_status_t
96 96 fcoet_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp,
97 97 fct_cmd_t *login)
98 98 {
99 99 uint16_t handle;
100 100 fct_status_t ret;
101 101
102 102 switch (rp->rp_id) {
103 103 case 0xFFFFFC:
104 104 handle = 0x7FC;
105 105 break;
106 106
107 107 case 0xFFFFFD:
108 108 handle = 0x7FD;
109 109 break;
110 110
111 111 case 0xFFFFFE:
112 112 handle = 0x7FE;
113 113 break;
114 114
115 115 case 0xFFFFFF:
116 116 handle = 0x7FF;
117 117 break;
118 118
119 119 default:
120 120 /*
121 121 * For not well-known address, we let FCT to select one.
122 122 */
123 123 handle = FCT_HANDLE_NONE;
124 124 break;
125 125 }
126 126
127 127 rp->rp_handle = handle;
128 128 if (login->cmd_type == FCT_CMD_SOL_ELS) {
129 129 ret = fcoet_fill_plogi_req(port, rp, login);
130 130 } else {
131 131 ret = fcoet_fill_plogi_resp(port, rp, login);
132 132 }
133 133
134 134 return (ret);
135 135 }
136 136
137 137 /*
138 138 * FCT will call this to say "FCoET can release resources with this RP now."
139 139 */
140 140 /* ARGSUSED */
141 141 fct_status_t
142 142 fcoet_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp)
143 143 {
144 144 fcoet_soft_state_t *this_ss = PORT2SS(port);
145 145
146 146 this_ss->ss_rport_dereg_state = 0;
147 147 this_ss->ss_rportid_in_dereg = 0;
148 148 return (FCT_SUCCESS);
149 149 }
150 150
151 151 fct_status_t
152 152 fcoet_send_cmd(fct_cmd_t *cmd)
153 153 {
154 154 if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
155 155 return (fcoet_send_sol_els(cmd));
156 156 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
157 157 return (fcoet_send_sol_ct(cmd));
158 158 }
159 159
160 160 return (FCT_FAILURE);
161 161 }
162 162
163 163 /*
164 164 * SCSI response phase
165 165 * ELS_ACC/ELS_RJT
166 166 */
167 167 fct_status_t
168 168 fcoet_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags)
169 169 {
170 170 char info[FCT_INFO_LEN];
171 171
172 172 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
173 173 if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
174 174 goto send_cmd_rsp_error;
175 175 } else {
176 176 return (fcoet_send_status(cmd));
177 177 }
178 178 }
179 179
180 180 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
181 181 if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
182 182 goto send_cmd_rsp_error;
183 183 } else {
184 184 return (fcoet_send_els_response(cmd));
185 185 }
186 186 }
187 187
188 188 if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
189 189 cmd->cmd_handle = 0;
190 190 }
191 191
192 192 if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
193 193 return (fcoet_send_abts_response(cmd, 0));
194 194 } else {
195 195 ASSERT(0);
196 196 return (FCT_FAILURE);
197 197 }
198 198
199 199 send_cmd_rsp_error:
200 200 (void) snprintf(info, sizeof (info), "fcoet_send_cmd_response: can not "
201 201 "handle FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", (void *)cmd,
202 202 ioflags);
203 203 (void) fct_port_shutdown(CMD2SS(cmd)->ss_port,
204 204 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
205 205 return (FCT_FAILURE);
206 206 }
207 207
208 208 /*
209 209 * It's for read/write (xfer_rdy)
210 210 */
211 211 /* ARGSUSED */
212 212 fct_status_t
213 213 fcoet_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
214 214 {
215 215 fcoe_frame_t *frm;
216 216 int idx;
217 217 int frm_num;
218 218 int data_size;
219 219 int left_size;
220 220 int offset;
221 221 fcoet_exchange_t *xch = CMD2XCH(cmd);
222 222
223 223 ASSERT(!xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN]);
224 224 xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN] = dbuf;
225 225
226 226 left_size = (int)dbuf->db_data_size;
227 227 if (dbuf->db_relative_offset == 0)
228 228 xch->xch_left_data_size =
229 229 XCH2TASK(xch)->task_expected_xfer_length;
230 230
231 231 if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
232 232 /*
233 233 * If it's write type command, we need send xfer_rdy now
234 234 * We may need to consider bidirectional command later
235 235 */
236 236 dbuf->db_sglist_length = 0;
237 237 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(
238 238 CMD2SS(cmd)->ss_eport, sizeof (fcoe_fcp_xfer_rdy_t) +
239 239 FCFH_SIZE, NULL);
240 240 if (frm == NULL) {
241 241 ASSERT(0);
242 242 return (FCT_FAILURE);
243 243 } else {
244 244 fcoet_init_tfm(frm, CMD2XCH(cmd));
245 245 bzero(frm->frm_payload, frm->frm_payload_size);
246 246 }
247 247
248 248 FFM_R_CTL(0x05, frm);
249 249 FRM2TFM(frm)->tfm_rctl = 0x05;
250 250 FFM_TYPE(0x08, frm);
251 251 FFM_F_CTL(0x890000, frm);
252 252 FFM_OXID(cmd->cmd_oxid, frm);
253 253 FFM_RXID(cmd->cmd_rxid, frm);
254 254 FFM_S_ID(cmd->cmd_lportid, frm);
255 255 FFM_D_ID(cmd->cmd_rportid, frm);
256 256 FCOE_V2B_4(dbuf->db_relative_offset, frm->frm_payload);
257 257 FCOE_V2B_4(dbuf->db_data_size, frm->frm_payload + 4);
258 258 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
259 259
260 260 return (FCT_SUCCESS);
261 261 }
262 262
263 263 /*
264 264 * It's time to transfer READ data to remote side
265 265 */
266 266 frm_num = (dbuf->db_data_size + CMD2SS(cmd)->ss_fcp_data_payload_size -
267 267 1) / CMD2SS(cmd)->ss_fcp_data_payload_size;
268 268 offset = dbuf->db_relative_offset;
269 269 for (idx = 0; idx < frm_num; idx++) {
270 270 if (idx == (frm_num -1)) {
271 271 data_size = P2ROUNDUP(left_size, 4);
272 272 } else {
273 273 data_size = CMD2SS(cmd)->ss_fcp_data_payload_size;
274 274 }
275 275
276 276 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(
277 277 CMD2SS(cmd)->ss_eport, data_size + FCFH_SIZE,
278 278 FCOET_GET_NETB(dbuf, idx));
279 279 if (frm == NULL) {
280 280 ASSERT(0);
281 281 return (FCT_FAILURE);
282 282 } else {
283 283 fcoet_init_tfm(frm, CMD2XCH(cmd));
284 284 /*
285 285 * lock the xchg to avoid being released (by abort)
286 286 * after sent out and before release
287 287 */
288 288 FCOET_BUSY_XCHG(CMD2XCH(cmd));
289 289 }
290 290
291 291 FFM_R_CTL(0x01, frm);
292 292 FRM2TFM(frm)->tfm_rctl = 0x01;
293 293 FRM2TFM(frm)->tfm_buf_idx =
294 294 dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN;
295 295 FFM_TYPE(0x08, frm);
296 296 if (idx != frm_num - 1) {
↓ open down ↓ |
296 lines elided |
↑ open up ↑ |
297 297 FFM_F_CTL(0x800008, frm);
298 298 } else {
299 299 FFM_F_CTL(0x880008 | (data_size - left_size), frm);
300 300 }
301 301
302 302 FFM_OXID(cmd->cmd_oxid, frm);
303 303 FFM_RXID(cmd->cmd_rxid, frm);
304 304 FFM_S_ID(cmd->cmd_lportid, frm);
305 305 FFM_D_ID(cmd->cmd_rportid, frm);
306 306 FFM_SEQ_CNT(xch->xch_sequence_no, frm);
307 - atomic_add_8(&xch->xch_sequence_no, 1);
307 + atomic_inc_8(&xch->xch_sequence_no);
308 308 FFM_PARAM(offset, frm);
309 309 offset += data_size;
310 310 left_size -= data_size;
311 311
312 312 /*
313 313 * Disassociate netbs which will be freed by NIC driver
314 314 */
315 315 FCOET_SET_NETB(dbuf, idx, NULL);
316 316
317 317 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
318 318 }
319 319
320 320 return (FCT_SUCCESS);
321 321 }
322 322
323 323 fct_status_t
324 324 fcoet_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags)
325 325 {
326 326 fcoet_soft_state_t *this_ss = PORT2SS(port);
327 327 fct_status_t fct_ret = FCT_SUCCESS;
328 328
329 329 FCOET_LOG("fcoet_abort_cmd", "cmd=%p, xch=%p, cmd_specific=%p",
330 330 cmd, cmd->cmd_fca_private, cmd->cmd_specific);
331 331 switch (cmd->cmd_type) {
332 332 case FCT_CMD_RCVD_ABTS:
333 333 /*
334 334 * Sometimes unsolicited ABTS request will be received twice
335 335 * and the first ABTS is not done yet, so the second ABTS
336 336 * will be passed down here, in this case we will do
337 337 * nothing and abts response is not needed to be sent
338 338 * fct_ret = fcoet_send_abts_response(cmd, 1);
339 339 */
340 340 break;
341 341 case FCT_CMD_FCP_XCHG:
342 342 case FCT_CMD_RCVD_ELS:
343 343 if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
344 344 break;
345 345 }
346 346
347 347 CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT;
348 348 (void) fcoet_clear_unsol_exchange(CMD2XCH(cmd));
349 349 if (!(flags & FCT_IOF_FORCE_FCA_DONE)) {
350 350 mutex_enter(&this_ss->ss_watch_mutex);
351 351 CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt();
352 352 list_insert_tail(&this_ss->ss_abort_xchg_list,
353 353 CMD2XCH(cmd));
354 354 cv_signal(&this_ss->ss_watch_cv);
355 355 mutex_exit(&this_ss->ss_watch_mutex);
356 356 }
357 357 break;
358 358
359 359 case FCT_CMD_SOL_ELS:
360 360 case FCT_CMD_SOL_CT:
361 361 if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) {
362 362 break;
363 363 }
364 364
365 365 CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT;
366 366 fcoet_clear_sol_exchange(CMD2XCH(cmd));
367 367
368 368 if (!(flags & FCT_IOF_FORCE_FCA_DONE)) {
369 369 mutex_enter(&this_ss->ss_watch_mutex);
370 370 CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt();
371 371 cv_signal(&this_ss->ss_watch_cv);
372 372 list_insert_tail(&this_ss->ss_abort_xchg_list,
373 373 CMD2XCH(cmd));
374 374 mutex_exit(&this_ss->ss_watch_mutex);
375 375 }
376 376
377 377 break;
378 378
379 379 default:
380 380 ASSERT(0);
381 381 break;
382 382 }
383 383
384 384 if ((flags & FCT_IOF_FORCE_FCA_DONE) &&
385 385 (cmd->cmd_type != FCT_CMD_FCP_XCHG)) {
386 386 cmd->cmd_handle = 0;
387 387 }
388 388
389 389 return (fct_ret);
390 390 }
391 391
392 392 /* ARGSUSED */
393 393 fct_status_t
394 394 fcoet_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx)
395 395 {
396 396 cmn_err(CE_WARN, "FLOGI requested (not supported)");
397 397 return (FCT_FAILURE);
398 398 }
399 399
400 400 void
401 401 fcoet_send_sol_flogi(fcoet_soft_state_t *ss)
402 402 {
403 403 fcoet_exchange_t *xch;
404 404 fct_cmd_t *cmd;
405 405 fct_els_t *els;
406 406 fcoe_frame_t *frm;
407 407
408 408 /*
409 409 * FCT will initialize fct_cmd_t
410 410 * Initialize fcoet_exchange
411 411 */
412 412 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS,
413 413 sizeof (fcoet_exchange_t), 0);
414 414 xch = CMD2XCH(cmd);
415 415 els = CMD2ELS(cmd);
416 416
417 417 xch->xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
418 418 if (xch->xch_oxid == 0xFFFF) {
419 419 xch->xch_oxid =
420 420 atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
421 421 }
422 422 xch->xch_rxid = 0xFFFF;
423 423 xch->xch_flags = 0;
424 424 xch->xch_ss = ss;
425 425 xch->xch_cmd = cmd;
426 426 xch->xch_current_seq = NULL;
427 427 xch->xch_start_time = ddi_get_lbolt();
428 428
429 429 /*
430 430 * Keep it to compare with response
431 431 */
432 432 ss->ss_sol_flogi = xch;
433 433 els->els_resp_alloc_size = 116;
434 434 els->els_resp_size = 116;
435 435 els->els_resp_payload = (uint8_t *)
436 436 kmem_zalloc(els->els_resp_size, KM_SLEEP);
437 437 (void) mod_hash_insert(xch->xch_ss->ss_sol_oxid_hash,
438 438 (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
439 439 xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
440 440 atomic_or_32(&ss->ss_flags, SS_FLAG_DELAY_PLOGI);
441 441
442 442 /*
443 443 * FCoE will initialize fcoe_frame_t
444 444 */
445 445 frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
446 446 FLOGI_REQ_PAYLOAD_SIZE + FCFH_SIZE, NULL);
447 447 if (frm == NULL) {
448 448 ASSERT(0);
449 449 return;
450 450 } else {
451 451 fcoet_init_tfm(frm, xch);
452 452 bzero(frm->frm_payload, frm->frm_payload_size);
453 453 }
454 454
455 455 FFM_R_CTL(0x22, frm);
456 456 FRM2TFM(frm)->tfm_rctl = 0x22;
457 457 FFM_TYPE(0x01, frm);
458 458 FFM_F_CTL(0x290000, frm);
459 459 FFM_OXID(xch->xch_oxid, frm);
460 460 FFM_RXID(xch->xch_rxid, frm);
461 461 FFM_D_ID(0xfffffe, frm);
462 462 frm->frm_payload[0] = ELS_OP_FLOGI;
463 463 /* Common Service Parameters */
464 464 frm->frm_payload[4] = 0x20;
465 465 frm->frm_payload[5] = 0x08;
466 466 frm->frm_payload[6] = 0x0;
467 467 frm->frm_payload[7] = 0x03;
468 468 /* N_PORT */
469 469 frm->frm_payload[8] = 0x88;
470 470 frm->frm_payload[9] = 0x00;
471 471 frm->frm_payload[10] = 0x08;
472 472 frm->frm_payload[11] = 0x0;
473 473 frm->frm_payload[12] = 0x0;
474 474 frm->frm_payload[13] = 0xff;
475 475 frm->frm_payload[14] = 0x0;
476 476 frm->frm_payload[15] = 0x03;
477 477 frm->frm_payload[16] = 0x0;
478 478 frm->frm_payload[17] = 0x0;
479 479 frm->frm_payload[18] = 0x07;
480 480 frm->frm_payload[19] = 0xd0;
481 481 /* PWWN and NWWN */
482 482 frm->frm_payload[20] = 0x0;
483 483 bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload+20, 8);
484 484 bcopy(ss->ss_eport->eport_nodewwn, frm->frm_payload+28, 8);
485 485 /* Class 3 Service Parameters */
486 486 frm->frm_payload[68] = 0x88;
487 487 frm->frm_payload[74] = 0x08;
488 488 frm->frm_payload[77] = 0xff;
489 489
490 490 ss->ss_eport->eport_tx_frame(frm);
491 491 xch->xch_flags |= XCH_FLAG_NONFCP_REQ_SENT;
492 492 }
493 493
494 494 /*
495 495 * This is for solicited FLOGI only
496 496 */
497 497 void
498 498 fcoet_send_sol_abts(fcoet_exchange_t *xch)
499 499 {
500 500 fcoe_frame_t *frm;
501 501 fcoet_soft_state_t *ss = xch->xch_ss;
502 502
503 503 /*
504 504 * FCoE will initialize fcoe_frame_t
505 505 * ABTS has no payload
506 506 */
507 507 frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
508 508 FCFH_SIZE, NULL);
509 509 if (frm == NULL) {
510 510 ASSERT(0);
511 511 return;
512 512 } else {
513 513 fcoet_init_tfm(frm, xch);
514 514 frm->frm_payload = NULL;
515 515 }
516 516
517 517 FFM_R_CTL(0x81, frm);
518 518 FRM2TFM(frm)->tfm_rctl = 0x81;
519 519 FFM_F_CTL(0x090000, frm);
520 520 FFM_OXID(xch->xch_oxid, frm);
521 521 FFM_RXID(xch->xch_rxid, frm);
522 522 FFM_D_ID(0xfffffe, frm);
523 523 FFM_SEQ_CNT(xch->xch_sequence_no, frm);
524 524 xch->xch_start_time = ddi_get_lbolt();
525 525
526 526 ss->ss_eport->eport_tx_frame(frm);
527 527 }
528 528
529 529 void
530 530 fcoet_ctl(struct fct_local_port *port, int cmd, void *arg)
531 531 {
532 532 stmf_change_status_t st;
533 533 stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg;
534 534 fcoet_soft_state_t *this_ss = PORT2SS(port);
535 535
536 536 st.st_completion_status = FCT_SUCCESS;
537 537 st.st_additional_info = NULL;
538 538
539 539 switch (cmd) {
540 540 case FCT_CMD_PORT_ONLINE:
541 541 if (this_ss->ss_state == FCT_STATE_ONLINE)
542 542 st.st_completion_status = STMF_ALREADY;
543 543 else if (this_ss->ss_state != FCT_STATE_OFFLINE)
544 544 st.st_completion_status = FCT_FAILURE;
545 545 if (st.st_completion_status == FCT_SUCCESS) {
546 546 this_ss->ss_state = FCT_STATE_ONLINING;
547 547 this_ss->ss_state_not_acked = 1;
548 548 st.st_completion_status = fcoet_enable_port(this_ss);
549 549 if (st.st_completion_status != STMF_SUCCESS) {
550 550 this_ss->ss_state = FCT_STATE_OFFLINE;
551 551 this_ss->ss_state_not_acked = 0;
552 552 } else {
553 553 this_ss->ss_state = FCT_STATE_ONLINE;
554 554 }
555 555 }
556 556 fct_ctl(port->port_lport, FCT_CMD_PORT_ONLINE_COMPLETE, &st);
557 557 this_ss->ss_change_state_flags = 0;
558 558 break;
559 559
560 560 case FCT_CMD_PORT_OFFLINE:
561 561 if (this_ss->ss_state == FCT_STATE_OFFLINE) {
562 562 st.st_completion_status = STMF_ALREADY;
563 563 } else if (this_ss->ss_state != FCT_STATE_ONLINE) {
564 564 st.st_completion_status = FCT_FAILURE;
565 565 }
566 566 if (st.st_completion_status == FCT_SUCCESS) {
567 567 this_ss->ss_state = FCT_STATE_OFFLINING;
568 568 this_ss->ss_state_not_acked = 1;
569 569 this_ss->ss_change_state_flags = ssci->st_rflags;
570 570 st.st_completion_status = fcoet_disable_port(this_ss);
571 571 if (st.st_completion_status != STMF_SUCCESS) {
572 572 this_ss->ss_state = FCT_STATE_ONLINE;
573 573 this_ss->ss_state_not_acked = 0;
574 574 } else {
575 575 this_ss->ss_state = FCT_STATE_OFFLINE;
576 576 }
577 577 }
578 578 /*
579 579 * Notify the watchdog to do clear work
580 580 */
581 581 mutex_enter(&this_ss->ss_watch_mutex);
582 582 cv_signal(&this_ss->ss_watch_cv);
583 583 mutex_exit(&this_ss->ss_watch_mutex);
584 584 fct_ctl(port->port_lport, FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
585 585 break;
586 586
587 587 case FCT_ACK_PORT_ONLINE_COMPLETE:
588 588 this_ss->ss_state_not_acked = 0;
589 589 break;
590 590
591 591 case FCT_ACK_PORT_OFFLINE_COMPLETE:
592 592 this_ss->ss_state_not_acked = 0;
593 593 if (this_ss->ss_change_state_flags & STMF_RFLAG_RESET) {
594 594 if (fct_port_initialize(port,
595 595 this_ss->ss_change_state_flags,
596 596 "fcoet_ctl FCT_ACK_PORT_OFFLINE_COMPLETE "
597 597 "with RLFLAG_RESET") != FCT_SUCCESS) {
598 598 cmn_err(CE_WARN, "fcoet_ctl: "
599 599 "fct_port_initialize %s failed",
600 600 this_ss->ss_alias);
601 601 FCOET_LOG("fcoet_ctl: fct_port_initialize "
602 602 "%s failed", this_ss->ss_alias);
603 603 }
604 604 }
605 605 break;
606 606 default:
607 607 FCOET_LOG("fcoet_ctl", "Unsupported cmd %x", cmd);
608 608 break;
609 609 }
610 610 }
611 611
612 612 /*
613 613 * Filling the hba attributes
614 614 */
615 615 /* ARGSUSED */
616 616 void
617 617 fcoet_populate_hba_fru_details(struct fct_local_port *port,
618 618 struct fct_port_attrs *port_attrs)
619 619 {
620 620 (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
621 621 "Sun Microsystems, Inc.");
622 622 (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
623 623 "%s", FCOET_NAME);
624 624 (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
625 625 "%s", FCOET_VERSION);
626 626 (void) strcpy(port_attrs->serial_number, "N/A");
627 627 (void) strcpy(port_attrs->hardware_version, "N/A");
628 628 (void) strcpy(port_attrs->model, "FCoE Virtual FC HBA");
629 629 (void) strcpy(port_attrs->model_description, "N/A");
630 630 (void) strcpy(port_attrs->firmware_version, "N/A");
631 631 (void) strcpy(port_attrs->option_rom_version, "N/A");
632 632
633 633 port_attrs->vendor_specific_id = 0xFC0E;
634 634 port_attrs->max_frame_size = 2136;
635 635 port_attrs->supported_cos = 0x10000000;
636 636 /* Specified a fix speed here, need to change it in the future */
637 637 port_attrs->supported_speed = PORT_SPEED_1G | PORT_SPEED_10G;
638 638 }
639 639
640 640
641 641 static fct_status_t
642 642 fcoet_send_sol_els(fct_cmd_t *cmd)
643 643 {
644 644 fcoe_frame_t *frm;
645 645 fcoet_exchange_t *xch = NULL;
646 646
647 647 xch = CMD2XCH(cmd);
648 648 xch->xch_flags = 0;
649 649 xch->xch_ss = CMD2SS(cmd);
650 650 xch->xch_cmd = cmd;
651 651 xch->xch_current_seq = NULL;
652 652 xch->xch_left_data_size = 0;
653 653 xch->xch_sequence_no = 0;
654 654 xch->xch_start_time = ddi_get_lbolt();
655 655 xch->xch_rxid = 0xFFFF;
656 656 xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
657 657 if (xch->xch_oxid == 0xFFFF) {
658 658 xch->xch_oxid =
659 659 atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
660 660 }
661 661
662 662 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
663 663 CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL);
664 664 if (frm == NULL) {
665 665 ASSERT(0);
666 666 return (FCT_FAILURE);
667 667 } else {
668 668 fcoet_init_tfm(frm, CMD2XCH(cmd));
669 669 bzero(frm->frm_payload, frm->frm_payload_size);
670 670 }
671 671
672 672 (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash,
673 673 (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
674 674 xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
675 675 bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload,
676 676 frm->frm_payload_size);
677 677 FFM_R_CTL(0x22, frm);
678 678 FRM2TFM(frm)->tfm_rctl = 0x22;
679 679 FFM_TYPE(0x01, frm);
680 680 FFM_F_CTL(0x290000, frm);
681 681 FFM_OXID(xch->xch_oxid, frm);
682 682 FFM_RXID(xch->xch_rxid, frm);
683 683 FFM_S_ID(cmd->cmd_lportid, frm);
684 684 FFM_D_ID(cmd->cmd_rportid, frm);
685 685 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
686 686
687 687 return (FCT_SUCCESS);
688 688 }
689 689
690 690 static fct_status_t
691 691 fcoet_send_sol_ct(fct_cmd_t *cmd)
692 692 {
693 693 fcoe_frame_t *frm;
694 694 fcoet_exchange_t *xch;
695 695
696 696 xch = CMD2XCH(cmd);
697 697 xch->xch_flags = 0;
698 698 xch->xch_ss = CMD2SS(cmd);
699 699 xch->xch_cmd = cmd;
700 700 xch->xch_current_seq = NULL;
701 701 xch->xch_left_data_size = 0;
702 702 xch->xch_sequence_no = 0;
703 703 xch->xch_start_time = ddi_get_lbolt();
704 704 xch->xch_rxid = 0xFFFF;
705 705 xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
706 706 if (xch->xch_oxid == 0xFFFF) {
707 707 xch->xch_oxid =
708 708 atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1);
709 709 }
710 710
711 711 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
712 712 CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL);
713 713 if (frm == NULL) {
714 714 ASSERT(0);
715 715 return (FCT_FAILURE);
716 716 } else {
717 717 fcoet_init_tfm(frm, CMD2XCH(cmd));
718 718 bzero(frm->frm_payload, frm->frm_payload_size);
719 719 }
720 720
721 721 (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash,
722 722 (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch);
723 723 xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE;
724 724 bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload,
725 725 frm->frm_payload_size);
726 726 FFM_R_CTL(0x2, frm);
727 727 FRM2TFM(frm)->tfm_rctl = 0x2;
728 728 FFM_TYPE(0x20, frm);
729 729 FFM_F_CTL(0x290000, frm);
730 730 FFM_OXID(xch->xch_oxid, frm);
731 731 FFM_RXID(xch->xch_rxid, frm);
732 732 FFM_S_ID(cmd->cmd_lportid, frm);
733 733 FFM_D_ID(cmd->cmd_rportid, frm);
734 734 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
735 735
736 736 return (FCT_SUCCESS);
737 737 }
738 738
739 739 fct_status_t
740 740 fcoet_send_status(fct_cmd_t *cmd)
741 741 {
742 742 fcoe_frame_t *frm;
743 743 scsi_task_t *task = CMD2TASK(cmd);
744 744 fcoe_fcp_rsp_t *ffr;
745 745 int raw_frame_size;
746 746
747 747 /*
748 748 * Fast channel for good status phase
749 749 */
750 750 if (task->task_scsi_status == STATUS_GOOD && !task->task_resid) {
751 751 return (fcoet_send_good_status(cmd));
752 752 }
753 753
754 754 raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t);
755 755 if (task->task_scsi_status == STATUS_CHECK) {
756 756 raw_frame_size += task->task_sense_length;
757 757 }
758 758 raw_frame_size = P2ROUNDUP(raw_frame_size, 4);
759 759
760 760 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
761 761 raw_frame_size, NULL);
762 762 if (frm == NULL) {
763 763 ASSERT(0);
764 764 return (FCT_FAILURE);
765 765 } else {
766 766 fcoet_init_tfm(frm, CMD2XCH(cmd));
767 767 bzero(frm->frm_payload, frm->frm_payload_size);
768 768 /*
769 769 * lock the xchg to avoid being released (by abort)
770 770 * after sent out and before release
771 771 */
772 772 FCOET_BUSY_XCHG(CMD2XCH(cmd));
773 773 }
774 774
775 775 /*
776 776 * If there's sense data, copy it first
777 777 */
778 778 if ((task->task_scsi_status == STATUS_CHECK) &&
779 779 task->task_sense_length) {
780 780 bcopy(task->task_sense_data, frm->frm_payload +
781 781 sizeof (fcoe_fcp_rsp_t), task->task_sense_length);
782 782 }
783 783
784 784 /*
785 785 * Fill fcp_rsp
786 786 */
787 787 ffr = (fcoe_fcp_rsp_t *)frm->frm_payload;
788 788 FCOE_V2B_4(0, ffr->ffr_retry_delay_timer);
789 789 FCOE_V2B_1(0, ffr->ffr_flags);
790 790 if (task->task_scsi_status == STATUS_CHECK || task->task_resid) {
791 791 if (task->task_scsi_status == STATUS_CHECK) {
792 792 ffr->ffr_flags[0] |= BIT_1;
793 793 }
794 794 if (task->task_status_ctrl == TASK_SCTRL_OVER) {
795 795 ffr->ffr_flags[0] |= BIT_2;
796 796 } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
797 797 ffr->ffr_flags[0] |= BIT_3;
798 798 }
799 799 }
800 800 FCOE_V2B_1(task->task_scsi_status, ffr->ffr_scsi_status);
801 801 FCOE_V2B_4(task->task_resid, ffr->ffr_resid);
802 802 FCOE_V2B_4(task->task_sense_length, ffr->ffr_sns_len);
803 803 FCOE_V2B_4(0, ffr->ffr_rsp_len);
804 804
805 805 /*
806 806 * Fill fc frame header
807 807 */
808 808 FFM_R_CTL(0x07, frm);
809 809 FRM2TFM(frm)->tfm_rctl = 0x07;
810 810 FFM_TYPE(0x08, frm);
811 811 FFM_F_CTL(0x990000, frm);
812 812 FFM_OXID(cmd->cmd_oxid, frm);
813 813 FFM_RXID(cmd->cmd_rxid, frm);
814 814 FFM_S_ID(cmd->cmd_lportid, frm);
815 815 FFM_D_ID(cmd->cmd_rportid, frm);
816 816 FFM_SEQ_ID(0x01, frm);
817 817 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
818 818
819 819 return (FCT_SUCCESS);
820 820 }
821 821
822 822 static fct_status_t
823 823 fcoet_send_els_response(fct_cmd_t *cmd)
824 824 {
825 825 fcoe_frame_t *frm;
826 826
827 827 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
828 828 CMD2ELS(cmd)->els_resp_size + FCFH_SIZE, NULL);
829 829 if (frm == NULL) {
830 830 ASSERT(0);
831 831 return (FCT_FAILURE);
832 832 } else {
833 833 fcoet_init_tfm(frm, CMD2XCH(cmd));
834 834 bzero(frm->frm_payload, frm->frm_payload_size);
835 835 /*
836 836 * lock the xchg to avoid being released (by abort)
837 837 * after sent out and before release
838 838 */
839 839 FCOET_BUSY_XCHG(CMD2XCH(cmd));
840 840 }
841 841
842 842 bcopy(CMD2ELS(cmd)->els_resp_payload, frm->frm_payload,
843 843 frm->frm_payload_size);
844 844 FFM_R_CTL(0x23, frm);
845 845 FRM2TFM(frm)->tfm_rctl = 0x23;
846 846 FFM_TYPE(0x01, frm);
847 847 FFM_F_CTL(0x980000, frm);
848 848 FFM_OXID(cmd->cmd_oxid, frm);
849 849 FFM_RXID(cmd->cmd_rxid, frm);
850 850 FFM_S_ID(cmd->cmd_lportid, frm);
851 851 FFM_D_ID(cmd->cmd_rportid, frm);
852 852 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
853 853
854 854 return (FCT_SUCCESS);
855 855 }
856 856
857 857 /* ARGSUSED */
858 858 static fct_status_t
859 859 fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags)
860 860 {
861 861 fcoe_frame_t *frm;
862 862 fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
863 863
864 864 /*
865 865 * The relevant fcoet_exchange has been released
866 866 */
867 867 cmd->cmd_fca_private = NULL;
868 868 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
869 869 12 + FCFH_SIZE, NULL);
870 870 if (frm == NULL) {
871 871 ASSERT(0);
872 872 return (FCT_FAILURE);
873 873 } else {
874 874 fcoet_init_tfm(frm, NULL);
875 875 }
876 876
877 877 bcopy(abts->abts_resp_payload, frm->frm_payload,
878 878 frm->frm_payload_size);
879 879 FFM_R_CTL(abts->abts_resp_rctl, frm);
880 880 FRM2TFM(frm)->tfm_rctl = abts->abts_resp_rctl;
881 881 FFM_TYPE(0x00, frm);
882 882 FFM_F_CTL(0x980000, frm);
883 883 FFM_OXID(cmd->cmd_oxid, frm);
884 884 FFM_RXID(cmd->cmd_rxid, frm);
885 885 FFM_S_ID(cmd->cmd_lportid, frm);
886 886 FFM_D_ID(cmd->cmd_rportid, frm);
887 887 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
888 888
889 889 return (FCT_SUCCESS);
890 890 }
891 891
892 892 /*
893 893 * enable/disable port is simple compared to physical FC HBAs
894 894 */
895 895 fct_status_t
896 896 fcoet_enable_port(fcoet_soft_state_t *ss)
897 897 {
898 898 FCOET_EXT_LOG(ss->ss_alias, "port is being enabled-%p", ss);
899 899 /* Call fcoe function to online the port */
900 900 if (ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0) ==
901 901 FCOE_FAILURE) {
902 902 return (FCT_FAILURE);
903 903 }
904 904
905 905 if ((ss->ss_flags & SS_FLAG_PORT_DISABLED) == SS_FLAG_PORT_DISABLED) {
906 906 atomic_and_32(&ss->ss_flags, ~SS_FLAG_PORT_DISABLED);
907 907 }
908 908
909 909 return (FCT_SUCCESS);
910 910 }
911 911
912 912 fct_status_t
913 913 fcoet_disable_port(fcoet_soft_state_t *ss)
914 914 {
915 915 fct_status_t status;
916 916
917 917 FCOET_EXT_LOG(ss->ss_alias, "port is being disabled-%p", ss);
918 918 /* Call fcoe function to offline the port */
919 919 status = fcoet_logo_fabric(ss);
920 920 ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0);
921 921 atomic_or_32(&ss->ss_flags, SS_FLAG_PORT_DISABLED);
922 922 return (status);
923 923 }
924 924
925 925 static fct_status_t
926 926 fcoet_logo_fabric(fcoet_soft_state_t *ss)
927 927 {
928 928 fcoe_frame_t *frm;
929 929 uint32_t req_payload_size = 16;
930 930 uint16_t xch_oxid, xch_rxid = 0xFFFF;
↓ open down ↓ |
613 lines elided |
↑ open up ↑ |
931 931
932 932 frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport,
933 933 req_payload_size + FCFH_SIZE, NULL);
934 934 if (frm == NULL) {
935 935 ASSERT(0);
936 936 return (FCT_FAILURE);
937 937 } else {
938 938 fcoet_init_tfm(frm, NULL);
939 939 bzero(frm->frm_payload, frm->frm_payload_size);
940 940 }
941 - xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
941 + xch_oxid = atomic_inc_16_nv(&ss->ss_next_sol_oxid);
942 942 if (xch_oxid == 0xFFFF) {
943 - xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1);
943 + xch_oxid = atomic_inc_16_nv(&ss->ss_next_sol_oxid);
944 944 }
945 945 FFM_R_CTL(0x22, frm);
946 946 FRM2TFM(frm)->tfm_rctl = 0x22;
947 947 FFM_TYPE(0x01, frm);
948 948 FFM_F_CTL(0x290000, frm);
949 949 FFM_OXID(xch_oxid, frm);
950 950 FFM_RXID(xch_rxid, frm);
951 951 FFM_S_ID(ss->ss_link_info.portid, frm);
952 952 FFM_D_ID(0xfffffe, frm);
953 953
954 954 FCOE_V2B_1(0x5, frm->frm_payload);
955 955 FCOE_V2B_3(ss->ss_link_info.portid, frm->frm_payload + 5);
956 956 bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload + 8, 8);
957 957 ss->ss_eport->eport_tx_frame(frm);
958 958
959 959 return (FCT_SUCCESS);
960 960
961 961 }
962 962
963 963 /*
964 964 * Called by: fcoet_register_remote_port
965 965 */
966 966 /* ARGSUSED */
967 967 static fct_status_t
968 968 fcoet_fill_plogi_req(fct_local_port_t *port, fct_remote_port_t *rp,
969 969 fct_cmd_t *login)
970 970 {
971 971 uint8_t *p;
972 972
973 973 p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
974 974 p[0] = ELS_OP_PLOGI;
975 975 p[4] = 0x20;
976 976 p[5] = 0x20;
977 977 p[7] = 3;
978 978 p[8] = 0x88;
979 979 p[10] = 8;
980 980 p[13] = 0xff; p[15] = 0x1f;
981 981 p[18] = 7; p[19] = 0xd0;
982 982
983 983 bcopy(port->port_pwwn, p + 20, 8);
984 984 bcopy(port->port_nwwn, p + 28, 8);
985 985
986 986 p[68] = 0x80;
987 987 p[74] = 8;
988 988 p[77] = 0xff;
989 989 p[81] = 1;
990 990
991 991 return (FCT_SUCCESS);
992 992 }
993 993
994 994 /*
995 995 * Called by: fcoet_register_remote_port
996 996 */
997 997 /* ARGSUSED */
998 998 static fct_status_t
999 999 fcoet_fill_plogi_resp(fct_local_port_t *port, fct_remote_port_t *rp,
1000 1000 fct_cmd_t *login)
1001 1001 {
1002 1002 uint8_t *p;
1003 1003 /*
1004 1004 * ACC
1005 1005 */
1006 1006 p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
1007 1007 p[0] = ELS_OP_ACC;
1008 1008 p[4] = 0x20;
1009 1009 p[5] = 0x20;
1010 1010 p[7] = 0x0A;
1011 1011 p[10] = 0x05;
1012 1012 p[11] = 0xAC;
1013 1013
1014 1014 bcopy(port->port_pwwn, p + 20, 8);
1015 1015 bcopy(port->port_nwwn, p + 28, 8);
1016 1016
1017 1017 p[68] = 0x88;
1018 1018 return (FCT_SUCCESS);
1019 1019 }
1020 1020
1021 1021 static fct_status_t
1022 1022 fcoet_send_good_status(fct_cmd_t *cmd)
1023 1023 {
1024 1024 fcoe_frame_t *frm;
1025 1025 int raw_frame_size;
1026 1026
1027 1027 raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t);
1028 1028 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport,
1029 1029 raw_frame_size, NULL);
1030 1030 if (frm == NULL) {
1031 1031 ASSERT(0);
1032 1032 return (FCT_FAILURE);
1033 1033 } else {
1034 1034 fcoet_init_tfm(frm, CMD2XCH(cmd));
1035 1035 bzero(frm->frm_payload, frm->frm_payload_size);
1036 1036 /*
1037 1037 * lock the xchg to avoid being released (by abort)
1038 1038 * after sent out and before release
1039 1039 */
1040 1040 FCOET_BUSY_XCHG(CMD2XCH(cmd));
1041 1041 }
1042 1042
1043 1043 /*
1044 1044 * Fill fc frame header
1045 1045 */
1046 1046 FFM_R_CTL(0x07, frm);
1047 1047 FRM2TFM(frm)->tfm_rctl = 0x07;
1048 1048 FFM_TYPE(0x08, frm);
1049 1049 FFM_F_CTL(0x990000, frm);
1050 1050 FFM_OXID(cmd->cmd_oxid, frm);
1051 1051 FFM_RXID(cmd->cmd_rxid, frm);
1052 1052 FFM_S_ID(cmd->cmd_lportid, frm);
1053 1053 FFM_D_ID(cmd->cmd_rportid, frm);
1054 1054 FFM_SEQ_ID(0x01, frm);
1055 1055
1056 1056 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm);
1057 1057
1058 1058 return (FCT_SUCCESS);
1059 1059 }
↓ open down ↓ |
106 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX