diff options
| -rw-r--r-- | drivers/infiniband/ulp/iser/iscsi_iser.c | 169 |
1 files changed, 160 insertions, 9 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index decf696e7ea5..8c04c2d3cfd9 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c | |||
| @@ -102,9 +102,19 @@ MODULE_PARM_DESC(pi_guard, "T10-PI guard_type, 0:CRC|1:IP_CSUM (default:CRC)"); | |||
| 102 | static struct workqueue_struct *release_wq; | 102 | static struct workqueue_struct *release_wq; |
| 103 | struct iser_global ig; | 103 | struct iser_global ig; |
| 104 | 104 | ||
| 105 | /* | ||
| 106 | * iscsi_iser_recv() - Process a successfull recv completion | ||
| 107 | * @conn: iscsi connection | ||
| 108 | * @hdr: iscsi header | ||
| 109 | * @rx_data: buffer containing receive data payload | ||
| 110 | * @rx_data_len: length of rx_data | ||
| 111 | * | ||
| 112 | * Notes: In case of data length errors or iscsi PDU completion failures | ||
| 113 | * this routine will signal iscsi layer of connection failure. | ||
| 114 | */ | ||
| 105 | void | 115 | void |
| 106 | iscsi_iser_recv(struct iscsi_conn *conn, | 116 | iscsi_iser_recv(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
| 107 | struct iscsi_hdr *hdr, char *rx_data, int rx_data_len) | 117 | char *rx_data, int rx_data_len) |
| 108 | { | 118 | { |
| 109 | int rc = 0; | 119 | int rc = 0; |
| 110 | int datalen; | 120 | int datalen; |
| @@ -135,12 +145,22 @@ error: | |||
| 135 | iscsi_conn_failure(conn, rc); | 145 | iscsi_conn_failure(conn, rc); |
| 136 | } | 146 | } |
| 137 | 147 | ||
| 138 | static int iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode) | 148 | /** |
| 149 | * iscsi_iser_pdu_alloc() - allocate an iscsi-iser PDU | ||
| 150 | * @task: iscsi task | ||
| 151 | * @opcode: iscsi command opcode | ||
| 152 | * | ||
| 153 | * Netes: This routine can't fail, just assign iscsi task | ||
| 154 | * hdr and max hdr size. | ||
| 155 | */ | ||
| 156 | static int | ||
| 157 | iscsi_iser_pdu_alloc(struct iscsi_task *task, uint8_t opcode) | ||
| 139 | { | 158 | { |
| 140 | struct iscsi_iser_task *iser_task = task->dd_data; | 159 | struct iscsi_iser_task *iser_task = task->dd_data; |
| 141 | 160 | ||
| 142 | task->hdr = (struct iscsi_hdr *)&iser_task->desc.iscsi_header; | 161 | task->hdr = (struct iscsi_hdr *)&iser_task->desc.iscsi_header; |
| 143 | task->hdr_max = sizeof(iser_task->desc.iscsi_header); | 162 | task->hdr_max = sizeof(iser_task->desc.iscsi_header); |
| 163 | |||
| 144 | return 0; | 164 | return 0; |
| 145 | } | 165 | } |
| 146 | 166 | ||
| @@ -165,11 +185,15 @@ int iser_initialize_task_headers(struct iscsi_task *task, | |||
| 165 | iser_task->iser_conn = iser_conn; | 185 | iser_task->iser_conn = iser_conn; |
| 166 | return 0; | 186 | return 0; |
| 167 | } | 187 | } |
| 188 | |||
| 168 | /** | 189 | /** |
| 169 | * iscsi_iser_task_init - Initialize task | 190 | * iscsi_iser_task_init() - Initialize iscsi-iser task |
| 170 | * @task: iscsi task | 191 | * @task: iscsi task |
| 171 | * | 192 | * |
| 172 | * Initialize the task for the scsi command or mgmt command. | 193 | * Initialize the task for the scsi command or mgmt command. |
| 194 | * | ||
| 195 | * Return: Returns zero on success or -ENOMEM when failing | ||
| 196 | * to init task headers (dma mapping error). | ||
| 173 | */ | 197 | */ |
| 174 | static int | 198 | static int |
| 175 | iscsi_iser_task_init(struct iscsi_task *task) | 199 | iscsi_iser_task_init(struct iscsi_task *task) |
| @@ -191,7 +215,7 @@ iscsi_iser_task_init(struct iscsi_task *task) | |||
| 191 | } | 215 | } |
| 192 | 216 | ||
| 193 | /** | 217 | /** |
| 194 | * iscsi_iser_mtask_xmit - xmit management(immediate) task | 218 | * iscsi_iser_mtask_xmit() - xmit management (immediate) task |
| 195 | * @conn: iscsi connection | 219 | * @conn: iscsi connection |
| 196 | * @task: task management task | 220 | * @task: task management task |
| 197 | * | 221 | * |
| @@ -249,6 +273,12 @@ iscsi_iser_task_xmit_unsol_data_exit: | |||
| 249 | return error; | 273 | return error; |
| 250 | } | 274 | } |
| 251 | 275 | ||
| 276 | /** | ||
| 277 | * iscsi_iser_task_xmit() - xmit iscsi-iser task | ||
| 278 | * @task: iscsi task | ||
| 279 | * | ||
| 280 | * Return: zero on success or escalates $error on failure. | ||
| 281 | */ | ||
| 252 | static int | 282 | static int |
| 253 | iscsi_iser_task_xmit(struct iscsi_task *task) | 283 | iscsi_iser_task_xmit(struct iscsi_task *task) |
| 254 | { | 284 | { |
| @@ -286,6 +316,14 @@ iscsi_iser_task_xmit(struct iscsi_task *task) | |||
| 286 | return error; | 316 | return error; |
| 287 | } | 317 | } |
| 288 | 318 | ||
| 319 | /** | ||
| 320 | * iscsi_iser_cleanup_task() - cleanup an iscsi-iser task | ||
| 321 | * @task: iscsi task | ||
| 322 | * | ||
| 323 | * Notes: In case the RDMA device is already NULL (might have | ||
| 324 | * been removed in DEVICE_REMOVAL CM event it will bail-out | ||
| 325 | * without doing dma unmapping. | ||
| 326 | */ | ||
| 289 | static void iscsi_iser_cleanup_task(struct iscsi_task *task) | 327 | static void iscsi_iser_cleanup_task(struct iscsi_task *task) |
| 290 | { | 328 | { |
| 291 | struct iscsi_iser_task *iser_task = task->dd_data; | 329 | struct iscsi_iser_task *iser_task = task->dd_data; |
| @@ -310,7 +348,20 @@ static void iscsi_iser_cleanup_task(struct iscsi_task *task) | |||
| 310 | } | 348 | } |
| 311 | } | 349 | } |
| 312 | 350 | ||
| 313 | static u8 iscsi_iser_check_protection(struct iscsi_task *task, sector_t *sector) | 351 | /** |
| 352 | * iscsi_iser_check_protection() - check protection information status of task. | ||
| 353 | * @task: iscsi task | ||
| 354 | * @sector: error sector if exsists (output) | ||
| 355 | * | ||
| 356 | * Return: zero if no data-integrity errors have occured | ||
| 357 | * 0x1: data-integrity error occured in the guard-block | ||
| 358 | * 0x2: data-integrity error occured in the reference tag | ||
| 359 | * 0x3: data-integrity error occured in the application tag | ||
| 360 | * | ||
| 361 | * In addition the error sector is marked. | ||
| 362 | */ | ||
| 363 | static u8 | ||
| 364 | iscsi_iser_check_protection(struct iscsi_task *task, sector_t *sector) | ||
| 314 | { | 365 | { |
| 315 | struct iscsi_iser_task *iser_task = task->dd_data; | 366 | struct iscsi_iser_task *iser_task = task->dd_data; |
| 316 | 367 | ||
| @@ -322,8 +373,17 @@ static u8 iscsi_iser_check_protection(struct iscsi_task *task, sector_t *sector) | |||
| 322 | sector); | 373 | sector); |
| 323 | } | 374 | } |
| 324 | 375 | ||
| 376 | /** | ||
| 377 | * iscsi_iser_conn_create() - create a new iscsi-iser connection | ||
| 378 | * @cls_session: iscsi class connection | ||
| 379 | * @conn_idx: connection index within the session (for MCS) | ||
| 380 | * | ||
| 381 | * Return: iscsi_cls_conn when iscsi_conn_setup succeeds or NULL | ||
| 382 | * otherwise. | ||
| 383 | */ | ||
| 325 | static struct iscsi_cls_conn * | 384 | static struct iscsi_cls_conn * |
| 326 | iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | 385 | iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, |
| 386 | uint32_t conn_idx) | ||
| 327 | { | 387 | { |
| 328 | struct iscsi_conn *conn; | 388 | struct iscsi_conn *conn; |
| 329 | struct iscsi_cls_conn *cls_conn; | 389 | struct iscsi_cls_conn *cls_conn; |
| @@ -342,9 +402,21 @@ iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
| 342 | return cls_conn; | 402 | return cls_conn; |
| 343 | } | 403 | } |
| 344 | 404 | ||
| 405 | /** | ||
| 406 | * iscsi_iser_conn_bind() - bind iscsi and iser connection structures | ||
| 407 | * @cls_session: iscsi class session | ||
| 408 | * @cls_conn: iscsi class connection | ||
| 409 | * @transport_eph: transport end-point handle | ||
| 410 | * @is_leading: indicate if this is the session leading connection (MCS) | ||
| 411 | * | ||
| 412 | * Return: zero on success, $error if iscsi_conn_bind fails and | ||
| 413 | * -EINVAL in case end-point doesn't exsits anymore or iser connection | ||
| 414 | * state is not UP (teardown already started). | ||
| 415 | */ | ||
| 345 | static int | 416 | static int |
| 346 | iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, | 417 | iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session, |
| 347 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, | 418 | struct iscsi_cls_conn *cls_conn, |
| 419 | uint64_t transport_eph, | ||
| 348 | int is_leading) | 420 | int is_leading) |
| 349 | { | 421 | { |
| 350 | struct iscsi_conn *conn = cls_conn->dd_data; | 422 | struct iscsi_conn *conn = cls_conn->dd_data; |
| @@ -391,6 +463,14 @@ out: | |||
| 391 | return error; | 463 | return error; |
| 392 | } | 464 | } |
| 393 | 465 | ||
| 466 | /** | ||
| 467 | * iscsi_iser_conn_start() - start iscsi-iser connection | ||
| 468 | * @cls_conn: iscsi class connection | ||
| 469 | * | ||
| 470 | * Notes: Here iser intialize (or re-initialize) stop_completion as | ||
| 471 | * from this point iscsi must call conn_stop in session/connection | ||
| 472 | * teardown so iser transport must wait for it. | ||
| 473 | */ | ||
| 394 | static int | 474 | static int |
| 395 | iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) | 475 | iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) |
| 396 | { | 476 | { |
| @@ -404,6 +484,16 @@ iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn) | |||
| 404 | return iscsi_conn_start(cls_conn); | 484 | return iscsi_conn_start(cls_conn); |
| 405 | } | 485 | } |
| 406 | 486 | ||
| 487 | /** | ||
| 488 | * iscsi_iser_conn_stop() - stop iscsi-iser connection | ||
| 489 | * @cls_conn: iscsi class connection | ||
| 490 | * @flag: indicate if recover or terminate (passed as is) | ||
| 491 | * | ||
| 492 | * Notes: Calling iscsi_conn_stop might theoretically race with | ||
| 493 | * DEVICE_REMOVAL event and dereference a previously freed RDMA device | ||
| 494 | * handle, so we call it under iser the state lock to protect against | ||
| 495 | * this kind of race. | ||
| 496 | */ | ||
| 407 | static void | 497 | static void |
| 408 | iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 498 | iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |
| 409 | { | 499 | { |
| @@ -432,7 +522,14 @@ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | |||
| 432 | } | 522 | } |
| 433 | } | 523 | } |
| 434 | 524 | ||
| 435 | static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) | 525 | /** |
| 526 | * iscsi_iser_session_destroy() - destroy iscsi-iser session | ||
| 527 | * @cls_session: iscsi class session | ||
| 528 | * | ||
| 529 | * Removes and free iscsi host. | ||
| 530 | */ | ||
| 531 | static void | ||
| 532 | iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session) | ||
| 436 | { | 533 | { |
| 437 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | 534 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); |
| 438 | 535 | ||
| @@ -452,6 +549,16 @@ iser_dif_prot_caps(int prot_caps) | |||
| 452 | SHOST_DIX_TYPE3_PROTECTION : 0); | 549 | SHOST_DIX_TYPE3_PROTECTION : 0); |
| 453 | } | 550 | } |
| 454 | 551 | ||
| 552 | /** | ||
| 553 | * iscsi_iser_session_create() - create an iscsi-iser session | ||
| 554 | * @ep: iscsi end-point handle | ||
| 555 | * @cmds_max: maximum commands in this session | ||
| 556 | * @qdepth: session command queue depth | ||
| 557 | * @initial_cmdsn: initiator command sequnce number | ||
| 558 | * | ||
| 559 | * Allocates and adds a scsi host, expose DIF supprot if | ||
| 560 | * exists, and sets up an iscsi session. | ||
| 561 | */ | ||
| 455 | static struct iscsi_cls_session * | 562 | static struct iscsi_cls_session * |
| 456 | iscsi_iser_session_create(struct iscsi_endpoint *ep, | 563 | iscsi_iser_session_create(struct iscsi_endpoint *ep, |
| 457 | uint16_t cmds_max, uint16_t qdepth, | 564 | uint16_t cmds_max, uint16_t qdepth, |
| @@ -564,6 +671,13 @@ iscsi_iser_set_param(struct iscsi_cls_conn *cls_conn, | |||
| 564 | return 0; | 671 | return 0; |
| 565 | } | 672 | } |
| 566 | 673 | ||
| 674 | /** | ||
| 675 | * iscsi_iser_set_param() - set class connection parameter | ||
| 676 | * @cls_conn: iscsi class connection | ||
| 677 | * @stats: iscsi stats to output | ||
| 678 | * | ||
| 679 | * Output connection statistics. | ||
| 680 | */ | ||
| 567 | static void | 681 | static void |
| 568 | iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) | 682 | iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) |
| 569 | { | 683 | { |
| @@ -612,6 +726,21 @@ static int iscsi_iser_get_ep_param(struct iscsi_endpoint *ep, | |||
| 612 | return len; | 726 | return len; |
| 613 | } | 727 | } |
| 614 | 728 | ||
| 729 | /** | ||
| 730 | * iscsi_iser_ep_connect() - Initiate iSER connection establishment | ||
| 731 | * @shost: scsi_host | ||
| 732 | * @dst_addr: destination address | ||
| 733 | * @non-blocking: indicate if routine can block | ||
| 734 | * | ||
| 735 | * Allocate an iscsi endpoint, an iser_conn structure and bind them. | ||
| 736 | * After that start RDMA connection establishment via rdma_cm. We | ||
| 737 | * don't allocate iser_conn embedded in iscsi_endpoint since in teardown | ||
| 738 | * the endpoint will be destroyed at ep_disconnect while iser_conn will | ||
| 739 | * cleanup its resources asynchronuously. | ||
| 740 | * | ||
| 741 | * Return: iscsi_endpoint created by iscsi layer or ERR_PTR(error) | ||
| 742 | * if fails. | ||
| 743 | */ | ||
| 615 | static struct iscsi_endpoint * | 744 | static struct iscsi_endpoint * |
| 616 | iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, | 745 | iscsi_iser_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, |
| 617 | int non_blocking) | 746 | int non_blocking) |
| @@ -644,6 +773,19 @@ failure: | |||
| 644 | return ERR_PTR(err); | 773 | return ERR_PTR(err); |
| 645 | } | 774 | } |
| 646 | 775 | ||
| 776 | /** | ||
| 777 | * iscsi_iser_ep_poll() - poll for iser connection establishment to complete | ||
| 778 | * @ep: iscsi endpoint (created at ep_connect) | ||
| 779 | * @timeout_ms: polling timeout allowed in ms. | ||
| 780 | * | ||
| 781 | * This routine boils down to waiting for up_completion signaling | ||
| 782 | * that cma_id got CONNECTED event. | ||
| 783 | * | ||
| 784 | * Return: 1 if succeeded in connection establishment, 0 if timeout expired | ||
| 785 | * (libiscsi will retry will kick in) or -1 if interrupted by signal | ||
| 786 | * or more likely iser connection state transitioned to TEMINATING or | ||
| 787 | * DOWN during the wait period. | ||
| 788 | */ | ||
| 647 | static int | 789 | static int |
| 648 | iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) | 790 | iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) |
| 649 | { | 791 | { |
| @@ -672,6 +814,15 @@ iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) | |||
| 672 | return rc; /* signal */ | 814 | return rc; /* signal */ |
| 673 | } | 815 | } |
| 674 | 816 | ||
| 817 | /** | ||
| 818 | * iscsi_iser_ep_disconnect() - Initiate connection teardown process | ||
| 819 | * @ep: iscsi endpoint handle | ||
| 820 | * | ||
| 821 | * This routine is not blocked by iser and RDMA termination process | ||
| 822 | * completion as we queue a deffered work for iser/RDMA destruction | ||
| 823 | * and cleanup or actually call it immediately in case we didn't pass | ||
| 824 | * iscsi conn bind/start stage, thus it is safe. | ||
| 825 | */ | ||
| 675 | static void | 826 | static void |
| 676 | iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) | 827 | iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) |
| 677 | { | 828 | { |
