ctl_frontend_iscsi.c revision 256058
1/*- 2 * Copyright (c) 2012 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Edward Tomasz Napierala under sponsorship 6 * from the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: head/sys/cam/ctl/ctl_frontend_iscsi.c 256058 2013-10-04 19:31:41Z trasz $ 30 */ 31 32/* 33 * CTL frontend for the iSCSI protocol. 34 */ 35 36#include <sys/cdefs.h> 37__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_frontend_iscsi.c 256058 2013-10-04 19:31:41Z trasz $"); 38 39#include <sys/param.h> 40#include <sys/capability.h> 41#include <sys/condvar.h> 42#include <sys/file.h> 43#include <sys/kernel.h> 44#include <sys/kthread.h> 45#include <sys/lock.h> 46#include <sys/malloc.h> 47#include <sys/module.h> 48#include <sys/mutex.h> 49#include <sys/queue.h> 50#include <sys/sbuf.h> 51#include <sys/sysctl.h> 52#include <sys/systm.h> 53#include <sys/uio.h> 54#include <sys/unistd.h> 55#include <vm/uma.h> 56 57#include <cam/scsi/scsi_all.h> 58#include <cam/scsi/scsi_da.h> 59#include <cam/ctl/ctl_io.h> 60#include <cam/ctl/ctl.h> 61#include <cam/ctl/ctl_backend.h> 62#include <cam/ctl/ctl_frontend.h> 63#include <cam/ctl/ctl_frontend_internal.h> 64#include <cam/ctl/ctl_debug.h> 65#include <cam/ctl/ctl_ha.h> 66#include <cam/ctl/ctl_ioctl.h> 67#include <cam/ctl/ctl_private.h> 68 69#include "../../dev/iscsi/icl.h" 70#include "../../dev/iscsi/iscsi_proto.h" 71#include "ctl_frontend_iscsi.h" 72 73#ifdef ICL_KERNEL_PROXY 74#include <sys/socketvar.h> 75#endif 76 77static MALLOC_DEFINE(M_CFISCSI, "cfiscsi", "Memory used for CTL iSCSI frontend"); 78static uma_zone_t cfiscsi_data_wait_zone; 79 80SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, iscsi, CTLFLAG_RD, 0, 81 "CAM Target Layer iSCSI Frontend"); 82static int debug = 3; 83TUNABLE_INT("kern.cam.ctl.iscsi.debug", &debug); 84SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, debug, CTLFLAG_RW, 85 &debug, 1, "Enable debug messages"); 86static int ping_timeout = 5; 87TUNABLE_INT("kern.cam.ctl.iscsi.ping_timeout", &ping_timeout); 88SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, ping_timeout, CTLFLAG_RW, 89 &ping_timeout, 5, "Interval between ping (NOP-Out) requests, in seconds"); 90static int login_timeout = 60; 91TUNABLE_INT("kern.cam.ctl.iscsi.login_timeout", &login_timeout); 92SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, login_timeout, CTLFLAG_RW, 93 &login_timeout, 60, "Time to wait for ctld(8) to finish Login Phase, in seconds"); 94static int maxcmdsn_delta = 256; 95TUNABLE_INT("kern.cam.ctl.iscsi.maxcmdsn_delta", &maxcmdsn_delta); 96SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, maxcmdsn_delta, CTLFLAG_RW, 97 &maxcmdsn_delta, 256, "Number of commands the initiator can send " 98 "without confirmation"); 99 100#define CFISCSI_DEBUG(X, ...) \ 101 if (debug > 1) { \ 102 printf("%s: " X "\n", __func__, ## __VA_ARGS__);\ 103 } while (0) 104 105#define CFISCSI_WARN(X, ...) \ 106 if (debug > 0) { \ 107 printf("WARNING: %s: " X "\n", \ 108 __func__, ## __VA_ARGS__); \ 109 } while (0) 110 111#define CFISCSI_SESSION_DEBUG(S, X, ...) \ 112 if (debug > 1) { \ 113 printf("%s: %s (%s): " X "\n", \ 114 __func__, S->cs_initiator_addr, \ 115 S->cs_initiator_name, ## __VA_ARGS__); \ 116 } while (0) 117 118#define CFISCSI_SESSION_WARN(S, X, ...) \ 119 if (debug > 0) { \ 120 printf("WARNING: %s (%s): " X "\n", \ 121 S->cs_initiator_addr, \ 122 S->cs_initiator_name, ## __VA_ARGS__); \ 123 } while (0) 124 125#define CFISCSI_SESSION_LOCK(X) mtx_lock(&X->cs_lock) 126#define CFISCSI_SESSION_UNLOCK(X) mtx_unlock(&X->cs_lock) 127#define CFISCSI_SESSION_LOCK_ASSERT(X) mtx_assert(&X->cs_lock, MA_OWNED) 128 129#define CONN_SESSION(X) ((struct cfiscsi_session *)(X)->ic_prv0) 130#define PDU_SESSION(X) CONN_SESSION((X)->ip_conn) 131#define PDU_EXPDATASN(X) (X)->ip_prv0 132#define PDU_TOTAL_TRANSFER_LEN(X) (X)->ip_prv1 133#define PDU_R2TSN(X) (X)->ip_prv2 134 135int cfiscsi_init(void); 136static void cfiscsi_online(void *arg); 137static void cfiscsi_offline(void *arg); 138static int cfiscsi_targ_enable(void *arg, struct ctl_id targ_id); 139static int cfiscsi_targ_disable(void *arg, struct ctl_id targ_id); 140static int cfiscsi_lun_enable(void *arg, 141 struct ctl_id target_id, int lun_id); 142static int cfiscsi_lun_disable(void *arg, 143 struct ctl_id target_id, int lun_id); 144static int cfiscsi_ioctl(struct cdev *dev, 145 u_long cmd, caddr_t addr, int flag, struct thread *td); 146static int cfiscsi_devid(struct ctl_scsiio *ctsio, int alloc_len); 147static void cfiscsi_datamove(union ctl_io *io); 148static void cfiscsi_done(union ctl_io *io); 149static uint32_t cfiscsi_map_lun(void *arg, uint32_t lun); 150static bool cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request); 151static void cfiscsi_pdu_handle_nop_out(struct icl_pdu *request); 152static void cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request); 153static void cfiscsi_pdu_handle_task_request(struct icl_pdu *request); 154static void cfiscsi_pdu_handle_data_out(struct icl_pdu *request); 155static void cfiscsi_pdu_handle_logout_request(struct icl_pdu *request); 156static void cfiscsi_session_terminate(struct cfiscsi_session *cs); 157static struct cfiscsi_target *cfiscsi_target_find(struct cfiscsi_softc 158 *softc, const char *name); 159static void cfiscsi_target_release(struct cfiscsi_target *ct); 160static void cfiscsi_session_delete(struct cfiscsi_session *cs); 161 162static struct cfiscsi_softc cfiscsi_softc; 163extern struct ctl_softc *control_softc; 164 165static int cfiscsi_module_event_handler(module_t, int /*modeventtype_t*/, void *); 166 167static moduledata_t cfiscsi_moduledata = { 168 "ctlcfiscsi", 169 cfiscsi_module_event_handler, 170 NULL 171}; 172 173DECLARE_MODULE(ctlcfiscsi, cfiscsi_moduledata, SI_SUB_CONFIGURE, SI_ORDER_FOURTH); 174MODULE_VERSION(ctlcfiscsi, 1); 175MODULE_DEPEND(ctlcfiscsi, ctl, 1, 1, 1); 176MODULE_DEPEND(ctlcfiscsi, icl, 1, 1, 1); 177 178static struct icl_pdu * 179cfiscsi_pdu_new_response(struct icl_pdu *request, int flags) 180{ 181 182 return (icl_pdu_new_bhs(request->ip_conn, flags)); 183} 184 185static bool 186cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request) 187{ 188 const struct iscsi_bhs_scsi_command *bhssc; 189 struct cfiscsi_session *cs; 190 uint32_t cmdsn, expstatsn; 191 192 cs = PDU_SESSION(request); 193 194 /* 195 * Every incoming PDU - not just NOP-Out - resets the ping timer. 196 * The purpose of the timeout is to reset the connection when it stalls; 197 * we don't want this to happen when NOP-In or NOP-Out ends up delayed 198 * in some queue. 199 * 200 * XXX: Locking? 201 */ 202 cs->cs_timeout = 0; 203 204 /* 205 * Data-Out PDUs don't contain CmdSN. 206 */ 207 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) == 208 ISCSI_BHS_OPCODE_SCSI_DATA_OUT) 209 return (false); 210 211 /* 212 * We're only using fields common for all the request 213 * (initiator -> target) PDUs. 214 */ 215 bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs; 216 cmdsn = ntohl(bhssc->bhssc_cmdsn); 217 expstatsn = ntohl(bhssc->bhssc_expstatsn); 218 219 CFISCSI_SESSION_LOCK(cs); 220#if 0 221 if (expstatsn != cs->cs_statsn) { 222 CFISCSI_SESSION_DEBUG(cs, "received PDU with ExpStatSN %d, " 223 "while current StatSN is %d", expstatsn, 224 cs->cs_statsn); 225 } 226#endif 227 228 /* 229 * The target MUST silently ignore any non-immediate command outside 230 * of this range. 231 * 232 * XXX: ... or non-immediate duplicates within the range. 233 */ 234 if (cmdsn < cs->cs_cmdsn || cmdsn > cs->cs_cmdsn + maxcmdsn_delta) { 235 CFISCSI_SESSION_UNLOCK(cs); 236 CFISCSI_SESSION_WARN(cs, "received PDU with CmdSN %d, " 237 "while expected CmdSN was %d", cmdsn, cs->cs_cmdsn); 238 return (true); 239 } 240 241 if ((request->ip_bhs->bhs_opcode & ISCSI_BHS_OPCODE_IMMEDIATE) == 0) 242 cs->cs_cmdsn++; 243 244 CFISCSI_SESSION_UNLOCK(cs); 245 246 return (false); 247} 248 249static void 250cfiscsi_pdu_handle(struct icl_pdu *request) 251{ 252 struct cfiscsi_session *cs; 253 bool ignore; 254 255 cs = PDU_SESSION(request); 256 257 ignore = cfiscsi_pdu_update_cmdsn(request); 258 if (ignore) { 259 icl_pdu_free(request); 260 return; 261 } 262 263 /* 264 * Handle the PDU; this includes e.g. receiving the remaining 265 * part of PDU and submitting the SCSI command to CTL 266 * or queueing a reply. The handling routine is responsible 267 * for freeing the PDU when it's no longer needed. 268 */ 269 switch (request->ip_bhs->bhs_opcode & 270 ~ISCSI_BHS_OPCODE_IMMEDIATE) { 271 case ISCSI_BHS_OPCODE_NOP_OUT: 272 cfiscsi_pdu_handle_nop_out(request); 273 break; 274 case ISCSI_BHS_OPCODE_SCSI_COMMAND: 275 cfiscsi_pdu_handle_scsi_command(request); 276 break; 277 case ISCSI_BHS_OPCODE_TASK_REQUEST: 278 cfiscsi_pdu_handle_task_request(request); 279 break; 280 case ISCSI_BHS_OPCODE_SCSI_DATA_OUT: 281 cfiscsi_pdu_handle_data_out(request); 282 break; 283 case ISCSI_BHS_OPCODE_LOGOUT_REQUEST: 284 cfiscsi_pdu_handle_logout_request(request); 285 break; 286 default: 287 CFISCSI_SESSION_WARN(cs, "received PDU with unsupported " 288 "opcode 0x%x; dropping connection", 289 request->ip_bhs->bhs_opcode); 290 cfiscsi_session_terminate(cs); 291 icl_pdu_free(request); 292 } 293 294} 295 296static void 297cfiscsi_receive_callback(struct icl_pdu *request) 298{ 299 struct cfiscsi_session *cs; 300 301 cs = PDU_SESSION(request); 302 303#ifdef ICL_KERNEL_PROXY 304 if (cs->cs_waiting_for_ctld || cs->cs_login_phase) { 305 if (cs->cs_login_pdu == NULL) 306 cs->cs_login_pdu = request; 307 else 308 icl_pdu_free(request); 309 cv_signal(&cs->cs_login_cv); 310 return; 311 } 312#endif 313 314 cfiscsi_pdu_handle(request); 315} 316 317static void 318cfiscsi_error_callback(struct icl_conn *ic) 319{ 320 struct cfiscsi_session *cs; 321 322 cs = CONN_SESSION(ic); 323 324 CFISCSI_SESSION_WARN(cs, "connection error; dropping connection"); 325 cfiscsi_session_terminate(cs); 326} 327 328static int 329cfiscsi_pdu_prepare(struct icl_pdu *response) 330{ 331 struct cfiscsi_session *cs; 332 struct iscsi_bhs_scsi_response *bhssr; 333 bool advance_statsn = true; 334 335 cs = PDU_SESSION(response); 336 337 CFISCSI_SESSION_LOCK_ASSERT(cs); 338 339 /* 340 * We're only using fields common for all the response 341 * (target -> initiator) PDUs. 342 */ 343 bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs; 344 345 /* 346 * 10.8.3: "The StatSN for this connection is not advanced 347 * after this PDU is sent." 348 */ 349 if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_R2T) 350 advance_statsn = false; 351 352 /* 353 * 10.19.2: "However, when the Initiator Task Tag is set to 0xffffffff, 354 * StatSN for the connection is not advanced after this PDU is sent." 355 */ 356 if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_NOP_IN && 357 bhssr->bhssr_initiator_task_tag == 0xffffffff) 358 advance_statsn = false; 359 360 /* 361 * See the comment below - StatSN is not meaningful and must 362 * not be advanced. 363 */ 364 if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_SCSI_DATA_IN) 365 advance_statsn = false; 366 367 /* 368 * 10.7.3: "The fields StatSN, Status, and Residual Count 369 * only have meaningful content if the S bit is set to 1." 370 */ 371 if (bhssr->bhssr_opcode != ISCSI_BHS_OPCODE_SCSI_DATA_IN) 372 bhssr->bhssr_statsn = htonl(cs->cs_statsn); 373 bhssr->bhssr_expcmdsn = htonl(cs->cs_cmdsn); 374 bhssr->bhssr_maxcmdsn = htonl(cs->cs_cmdsn + maxcmdsn_delta); 375 376 if (advance_statsn) 377 cs->cs_statsn++; 378 379 return (0); 380} 381 382static void 383cfiscsi_pdu_queue(struct icl_pdu *response) 384{ 385 struct cfiscsi_session *cs; 386 387 cs = PDU_SESSION(response); 388 389 CFISCSI_SESSION_LOCK(cs); 390 cfiscsi_pdu_prepare(response); 391 icl_pdu_queue(response); 392 CFISCSI_SESSION_UNLOCK(cs); 393} 394 395static uint32_t 396cfiscsi_decode_lun(uint64_t encoded) 397{ 398 uint8_t lun[8]; 399 uint32_t result; 400 401 /* 402 * The LUN field in iSCSI PDUs may look like an ordinary 64 bit number, 403 * but is in fact an evil, multidimensional structure defined 404 * in SCSI Architecture Model 5 (SAM-5), section 4.6. 405 */ 406 memcpy(lun, &encoded, sizeof(lun)); 407 switch (lun[0] & 0xC0) { 408 case 0x00: 409 if ((lun[0] & 0x3f) != 0 || lun[2] != 0 || lun[3] != 0 || 410 lun[4] != 0 || lun[5] != 0 || lun[6] != 0 || lun[7] != 0) { 411 CFISCSI_WARN("malformed LUN " 412 "(peripheral device addressing method): 0x%jx", 413 (uintmax_t)encoded); 414 result = 0xffffffff; 415 break; 416 } 417 result = lun[1]; 418 break; 419 case 0x40: 420 if (lun[2] != 0 || lun[3] != 0 || lun[4] != 0 || lun[5] != 0 || 421 lun[6] != 0 || lun[7] != 0) { 422 CFISCSI_WARN("malformed LUN " 423 "(flat address space addressing method): 0x%jx", 424 (uintmax_t)encoded); 425 result = 0xffffffff; 426 break; 427 } 428 result = ((lun[0] & 0x3f) << 8) + lun[1]; 429 break; 430 case 0xC0: 431 if (lun[0] != 0xD2 || lun[4] != 0 || lun[5] != 0 || 432 lun[6] != 0 || lun[7] != 0) { 433 CFISCSI_WARN("malformed LUN (extended flat " 434 "address space addressing method): 0x%jx", 435 (uintmax_t)encoded); 436 result = 0xffffffff; 437 break; 438 } 439 result = (lun[1] << 16) + (lun[2] << 8) + lun[3]; 440 default: 441 CFISCSI_WARN("unsupported LUN format 0x%jx", 442 (uintmax_t)encoded); 443 result = 0xffffffff; 444 break; 445 } 446 447 return (result); 448} 449 450static void 451cfiscsi_pdu_handle_nop_out(struct icl_pdu *request) 452{ 453 struct cfiscsi_session *cs; 454 struct iscsi_bhs_nop_out *bhsno; 455 struct iscsi_bhs_nop_in *bhsni; 456 struct icl_pdu *response; 457 458 cs = PDU_SESSION(request); 459 bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs; 460 461 if (bhsno->bhsno_initiator_task_tag == 0xffffffff) { 462 /* 463 * Nothing to do, iscsi_pdu_update_statsn() already 464 * zeroed the timeout. 465 */ 466 icl_pdu_free(request); 467 return; 468 } 469 470 response = cfiscsi_pdu_new_response(request, M_NOWAIT); 471 if (response == NULL) { 472 icl_pdu_free(request); 473 return; 474 } 475 bhsni = (struct iscsi_bhs_nop_in *)response->ip_bhs; 476 bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN; 477 bhsni->bhsni_flags = 0x80; 478 bhsni->bhsni_initiator_task_tag = bhsno->bhsno_initiator_task_tag; 479 bhsni->bhsni_target_transfer_tag = 0xffffffff; 480 481#if 0 482 /* XXX */ 483 response->ip_data_len = request->ip_data_len; 484 response->ip_data_mbuf = request->ip_data_mbuf; 485 request->ip_data_len = 0; 486 request->ip_data_mbuf = NULL; 487#endif 488 489 icl_pdu_free(request); 490 cfiscsi_pdu_queue(response); 491} 492 493static void 494cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request) 495{ 496 struct iscsi_bhs_scsi_command *bhssc; 497 struct cfiscsi_session *cs; 498 union ctl_io *io; 499 int error; 500 501 cs = PDU_SESSION(request); 502 bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs; 503 //CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x", 504 // bhssc->bhssc_initiator_task_tag); 505 506 if (request->ip_data_len > 0 && cs->cs_immediate_data == false) { 507 CFISCSI_SESSION_WARN(cs, "unsolicited data with " 508 "ImmediateData=No; dropping connection"); 509 cfiscsi_session_terminate(cs); 510 icl_pdu_free(request); 511 return; 512 } 513 io = ctl_alloc_io(cs->cs_target->ct_softc->fe.ctl_pool_ref); 514 if (io == NULL) { 515 CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io"); 516 icl_pdu_free(request); 517 return; 518 } 519 ctl_zero_io(io); 520 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request; 521 io->io_hdr.io_type = CTL_IO_SCSI; 522 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid; 523 io->io_hdr.nexus.targ_port = cs->cs_target->ct_softc->fe.targ_port; 524 io->io_hdr.nexus.targ_target.id = 0; 525 io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhssc->bhssc_lun); 526 io->io_hdr.nexus.lun_map_fn = cfiscsi_map_lun; 527 io->io_hdr.nexus.lun_map_arg = cs; 528 io->scsiio.tag_num = bhssc->bhssc_initiator_task_tag; 529 switch ((bhssc->bhssc_flags & BHSSC_FLAGS_ATTR)) { 530 case BHSSC_FLAGS_ATTR_UNTAGGED: 531 io->scsiio.tag_type = CTL_TAG_UNTAGGED; 532 break; 533 case BHSSC_FLAGS_ATTR_SIMPLE: 534 io->scsiio.tag_type = CTL_TAG_SIMPLE; 535 break; 536 case BHSSC_FLAGS_ATTR_ORDERED: 537 io->scsiio.tag_type = CTL_TAG_ORDERED; 538 break; 539 case BHSSC_FLAGS_ATTR_HOQ: 540 io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE; 541 break; 542 case BHSSC_FLAGS_ATTR_ACA: 543 io->scsiio.tag_type = CTL_TAG_ACA; 544 break; 545 default: 546 io->scsiio.tag_type = CTL_TAG_UNTAGGED; 547 CFISCSI_SESSION_WARN(cs, "unhandled tag type %d", 548 bhssc->bhssc_flags & BHSSC_FLAGS_ATTR); 549 break; 550 } 551 io->scsiio.cdb_len = sizeof(bhssc->bhssc_cdb); /* Which is 16. */ 552 memcpy(io->scsiio.cdb, bhssc->bhssc_cdb, sizeof(bhssc->bhssc_cdb)); 553 refcount_acquire(&cs->cs_outstanding_ctl_pdus); 554 error = ctl_queue(io); 555 if (error != CTL_RETVAL_COMPLETE) { 556 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error); 557 ctl_free_io(io); 558 refcount_release(&cs->cs_outstanding_ctl_pdus); 559 icl_pdu_free(request); 560 } 561} 562 563static void 564cfiscsi_pdu_handle_task_request(struct icl_pdu *request) 565{ 566 struct iscsi_bhs_task_management_request *bhstmr; 567 struct iscsi_bhs_task_management_response *bhstmr2; 568 struct icl_pdu *response; 569 struct cfiscsi_session *cs; 570 union ctl_io *io; 571 int error; 572 573 cs = PDU_SESSION(request); 574 bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs; 575 io = ctl_alloc_io(cs->cs_target->ct_softc->fe.ctl_pool_ref); 576 if (io == NULL) { 577 CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io"); 578 icl_pdu_free(request); 579 return; 580 } 581 ctl_zero_io(io); 582 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = request; 583 io->io_hdr.io_type = CTL_IO_TASK; 584 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid; 585 io->io_hdr.nexus.targ_port = cs->cs_target->ct_softc->fe.targ_port; 586 io->io_hdr.nexus.targ_target.id = 0; 587 io->io_hdr.nexus.targ_lun = cfiscsi_decode_lun(bhstmr->bhstmr_lun); 588 io->io_hdr.nexus.lun_map_fn = cfiscsi_map_lun; 589 io->io_hdr.nexus.lun_map_arg = cs; 590 io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */ 591 592 switch (bhstmr->bhstmr_function & ~0x80) { 593 case BHSTMR_FUNCTION_ABORT_TASK: 594#if 0 595 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_ABORT_TASK"); 596#endif 597 io->taskio.task_action = CTL_TASK_ABORT_TASK; 598 io->taskio.tag_num = bhstmr->bhstmr_referenced_task_tag; 599 break; 600 case BHSTMR_FUNCTION_LOGICAL_UNIT_RESET: 601#if 0 602 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_LOGICAL_UNIT_RESET"); 603#endif 604 io->taskio.task_action = CTL_TASK_LUN_RESET; 605 break; 606 case BHSTMR_FUNCTION_TARGET_COLD_RESET: 607#if 0 608 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_TARGET_COLD_RESET"); 609#endif 610 io->taskio.task_action = CTL_TASK_BUS_RESET; 611 break; 612 default: 613 CFISCSI_SESSION_DEBUG(cs, "unsupported function 0x%x", 614 bhstmr->bhstmr_function & ~0x80); 615 ctl_free_io(io); 616 617 response = cfiscsi_pdu_new_response(request, M_NOWAIT); 618 if (response == NULL) { 619 icl_pdu_free(request); 620 return; 621 } 622 bhstmr2 = (struct iscsi_bhs_task_management_response *) 623 response->ip_bhs; 624 bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE; 625 bhstmr2->bhstmr_flags = 0x80; 626 bhstmr2->bhstmr_response = 627 BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED; 628 bhstmr2->bhstmr_initiator_task_tag = 629 bhstmr->bhstmr_initiator_task_tag; 630 icl_pdu_free(request); 631 cfiscsi_pdu_queue(response); 632 return; 633 } 634 635 refcount_acquire(&cs->cs_outstanding_ctl_pdus); 636 error = ctl_queue(io); 637 if (error != CTL_RETVAL_COMPLETE) { 638 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error); 639 ctl_free_io(io); 640 refcount_release(&cs->cs_outstanding_ctl_pdus); 641 icl_pdu_free(request); 642 } 643} 644 645static bool 646cfiscsi_handle_data_segment(struct icl_pdu *request, struct cfiscsi_data_wait *cdw) 647{ 648 struct iscsi_bhs_data_out *bhsdo; 649 struct cfiscsi_session *cs; 650 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 651 size_t copy_len, off, buffer_offset; 652 int ctl_sg_count; 653 union ctl_io *io; 654 655 cs = PDU_SESSION(request); 656 657 KASSERT((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) == 658 ISCSI_BHS_OPCODE_SCSI_DATA_OUT || 659 (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) == 660 ISCSI_BHS_OPCODE_SCSI_COMMAND, 661 ("bad opcode 0x%x", request->ip_bhs->bhs_opcode)); 662 663 /* 664 * We're only using fields common for Data Out and SCSI Command PDUs. 665 */ 666 bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs; 667 668 io = cdw->cdw_ctl_io; 669 KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN, 670 ("CTL_FLAG_DATA_IN")); 671 672#if 0 673 CFISCSI_SESSION_DEBUG(cs, "received %zd bytes out of %d", 674 request->ip_data_len, io->scsiio.kern_total_len); 675#endif 676 677 if (io->scsiio.kern_sg_entries > 0) { 678 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 679 ctl_sg_count = io->scsiio.kern_sg_entries; 680 } else { 681 ctl_sglist = &ctl_sg_entry; 682 ctl_sglist->addr = io->scsiio.kern_data_ptr; 683 ctl_sglist->len = io->scsiio.kern_data_len; 684 ctl_sg_count = 1; 685 } 686#if 0 687 if (ctl_sg_count > 1) 688 CFISCSI_SESSION_DEBUG(cs, "ctl_sg_count = %d", ctl_sg_count); 689#endif 690 691 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) == 692 ISCSI_BHS_OPCODE_SCSI_DATA_OUT) 693 buffer_offset = ntohl(bhsdo->bhsdo_buffer_offset); 694 else 695 buffer_offset = 0; 696 697 /* 698 * Make sure the offset, as sent by the initiator, matches the offset 699 * we're supposed to be at in the scatter-gather list. 700 */ 701 if (buffer_offset != io->scsiio.ext_data_filled) { 702 CFISCSI_SESSION_WARN(cs, "received bad buffer offset %zd, " 703 "expected %zd", buffer_offset, 704 (size_t)io->scsiio.ext_data_filled); 705 cfiscsi_session_terminate(cs); 706 return (true); 707 } 708 709 off = 0; 710 for (;;) { 711 KASSERT(cdw->cdw_sg_index < ctl_sg_count, 712 ("cdw->cdw_sg_index >= ctl_sg_count")); 713 if (cdw->cdw_sg_len == 0) { 714 cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr; 715 cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len; 716 } 717 copy_len = icl_pdu_data_segment_length(request) - off; 718 if (copy_len > cdw->cdw_sg_len) 719 copy_len = cdw->cdw_sg_len; 720 721 icl_pdu_get_data(request, off, cdw->cdw_sg_addr, copy_len); 722 cdw->cdw_sg_addr += copy_len; 723 cdw->cdw_sg_len -= copy_len; 724 off += copy_len; 725 io->scsiio.ext_data_filled += copy_len; 726 727 if (cdw->cdw_sg_len == 0) { 728 if (cdw->cdw_sg_index == ctl_sg_count - 1) 729 break; 730 cdw->cdw_sg_index++; 731 } 732 if (off == icl_pdu_data_segment_length(request)) 733 break; 734 } 735 736 if (off < icl_pdu_data_segment_length(request)) { 737 CFISCSI_SESSION_WARN(cs, "received too much data: got %zd bytes, " 738 "expected %zd", icl_pdu_data_segment_length(request), off); 739 cfiscsi_session_terminate(cs); 740 return (true); 741 } 742 743 if (bhsdo->bhsdo_flags & BHSDO_FLAGS_F || 744 io->scsiio.ext_data_filled == io->scsiio.kern_total_len) { 745 if ((bhsdo->bhsdo_flags & BHSDO_FLAGS_F) == 0) { 746 CFISCSI_SESSION_WARN(cs, "got the final packet without " 747 "the F flag; flags = 0x%x; dropping connection", 748 bhsdo->bhsdo_flags); 749 cfiscsi_session_terminate(cs); 750 return (true); 751 } 752 753 if (io->scsiio.ext_data_filled != io->scsiio.kern_total_len) { 754 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) == 755 ISCSI_BHS_OPCODE_SCSI_DATA_OUT) { 756 CFISCSI_SESSION_WARN(cs, "got the final packet, but the " 757 "transmitted size was %zd bytes instead of %d; " 758 "dropping connection", 759 (size_t)io->scsiio.ext_data_filled, 760 io->scsiio.kern_total_len); 761 cfiscsi_session_terminate(cs); 762 return (true); 763 } else { 764 /* 765 * For SCSI Command PDU, this just means we need to 766 * solicit more data by sending R2T. 767 */ 768 return (false); 769 } 770 } 771#if 0 772 CFISCSI_SESSION_DEBUG(cs, "no longer expecting Data-Out with target " 773 "transfer tag 0x%x", cdw->cdw_target_transfer_tag); 774#endif 775 776 return (true); 777 } 778 779 return (false); 780} 781 782static void 783cfiscsi_pdu_handle_data_out(struct icl_pdu *request) 784{ 785 struct iscsi_bhs_data_out *bhsdo; 786 struct cfiscsi_session *cs; 787 struct cfiscsi_data_wait *cdw = NULL; 788 union ctl_io *io; 789 bool done; 790 791 cs = PDU_SESSION(request); 792 bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs; 793 794 CFISCSI_SESSION_LOCK(cs); 795 TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next) { 796#if 0 797 CFISCSI_SESSION_DEBUG(cs, "have ttt 0x%x, itt 0x%x; looking for " 798 "ttt 0x%x, itt 0x%x", 799 bhsdo->bhsdo_target_transfer_tag, 800 bhsdo->bhsdo_initiator_task_tag, 801 cdw->cdw_target_transfer_tag, cdw->cdw_initiator_task_tag)); 802#endif 803 if (bhsdo->bhsdo_target_transfer_tag == 804 cdw->cdw_target_transfer_tag) 805 break; 806 } 807 CFISCSI_SESSION_UNLOCK(cs); 808 if (cdw == NULL) { 809 CFISCSI_SESSION_WARN(cs, "data transfer tag 0x%x, initiator task tag " 810 "0x%x, not found", bhsdo->bhsdo_target_transfer_tag, 811 bhsdo->bhsdo_initiator_task_tag); 812 icl_pdu_free(request); 813 cfiscsi_session_terminate(cs); 814 return; 815 } 816 817 io = cdw->cdw_ctl_io; 818 KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN, 819 ("CTL_FLAG_DATA_IN")); 820 821 done = cfiscsi_handle_data_segment(request, cdw); 822 if (done) { 823 CFISCSI_SESSION_LOCK(cs); 824 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next); 825 CFISCSI_SESSION_UNLOCK(cs); 826 uma_zfree(cfiscsi_data_wait_zone, cdw); 827 io->scsiio.be_move_done(io); 828 } 829 830 icl_pdu_free(request); 831} 832 833static void 834cfiscsi_pdu_handle_logout_request(struct icl_pdu *request) 835{ 836 struct iscsi_bhs_logout_request *bhslr; 837 struct iscsi_bhs_logout_response *bhslr2; 838 struct icl_pdu *response; 839 struct cfiscsi_session *cs; 840 841 cs = PDU_SESSION(request); 842 bhslr = (struct iscsi_bhs_logout_request *)request->ip_bhs; 843 switch (bhslr->bhslr_reason & 0x7f) { 844 case BHSLR_REASON_CLOSE_SESSION: 845 case BHSLR_REASON_CLOSE_CONNECTION: 846 response = cfiscsi_pdu_new_response(request, M_NOWAIT); 847 if (response == NULL) { 848 icl_pdu_free(request); 849 cfiscsi_session_terminate(cs); 850 return; 851 } 852 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs; 853 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE; 854 bhslr2->bhslr_flags = 0x80; 855 bhslr2->bhslr_response = BHSLR_RESPONSE_CLOSED_SUCCESSFULLY; 856 bhslr2->bhslr_initiator_task_tag = 857 bhslr->bhslr_initiator_task_tag; 858 icl_pdu_free(request); 859 cfiscsi_pdu_queue(response); 860 cfiscsi_session_terminate(cs); 861 break; 862 case BHSLR_REASON_REMOVE_FOR_RECOVERY: 863 response = cfiscsi_pdu_new_response(request, M_NOWAIT); 864 if (response == NULL) { 865 icl_pdu_free(request); 866 cfiscsi_session_terminate(cs); 867 return; 868 } 869 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs; 870 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE; 871 bhslr2->bhslr_flags = 0x80; 872 bhslr2->bhslr_response = BHSLR_RESPONSE_RECOVERY_NOT_SUPPORTED; 873 bhslr2->bhslr_initiator_task_tag = 874 bhslr->bhslr_initiator_task_tag; 875 icl_pdu_free(request); 876 cfiscsi_pdu_queue(response); 877 break; 878 default: 879 CFISCSI_SESSION_WARN(cs, "invalid reason 0%x; dropping connection", 880 bhslr->bhslr_reason); 881 icl_pdu_free(request); 882 cfiscsi_session_terminate(cs); 883 break; 884 } 885} 886 887static void 888cfiscsi_callout(void *context) 889{ 890 struct icl_pdu *cp; 891 struct iscsi_bhs_nop_in *bhsni; 892 struct cfiscsi_session *cs; 893 894 cs = context; 895 896 if (cs->cs_terminating) 897 return; 898 899 callout_schedule(&cs->cs_callout, 1 * hz); 900 901 CFISCSI_SESSION_LOCK(cs); 902 cs->cs_timeout++; 903 CFISCSI_SESSION_UNLOCK(cs); 904 905#ifdef ICL_KERNEL_PROXY 906 if (cs->cs_waiting_for_ctld || cs->cs_login_phase) { 907 if (cs->cs_timeout > login_timeout) { 908 CFISCSI_SESSION_WARN(cs, "login timed out after " 909 "%d seconds; dropping connection", cs->cs_timeout); 910 cfiscsi_session_terminate(cs); 911 } 912 return; 913 } 914#endif 915 916 if (cs->cs_timeout >= ping_timeout) { 917 CFISCSI_SESSION_WARN(cs, "no ping reply (NOP-Out) after %d seconds; " 918 "dropping connection", ping_timeout); 919 cfiscsi_session_terminate(cs); 920 return; 921 } 922 923 /* 924 * If the ping was reset less than one second ago - which means 925 * that we've received some PDU during the last second - assume 926 * the traffic flows correctly and don't bother sending a NOP-Out. 927 * 928 * (It's 2 - one for one second, and one for incrementing is_timeout 929 * earlier in this routine.) 930 */ 931 if (cs->cs_timeout < 2) 932 return; 933 934 cp = icl_pdu_new_bhs(cs->cs_conn, M_NOWAIT); 935 if (cp == NULL) { 936 CFISCSI_SESSION_WARN(cs, "failed to allocate PDU"); 937 return; 938 } 939 bhsni = (struct iscsi_bhs_nop_in *)cp->ip_bhs; 940 bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN; 941 bhsni->bhsni_flags = 0x80; 942 bhsni->bhsni_initiator_task_tag = 0xffffffff; 943 944 cfiscsi_pdu_queue(cp); 945} 946 947static void 948cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs) 949{ 950 struct cfiscsi_data_wait *cdw, *tmpcdw; 951 union ctl_io *io; 952 int error; 953 954#ifdef notyet 955 io = ctl_alloc_io(cs->cs_target->ct_softc->fe.ctl_pool_ref); 956 if (io == NULL) { 957 CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io"); 958 return; 959 } 960 ctl_zero_io(io); 961 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL; 962 io->io_hdr.io_type = CTL_IO_TASK; 963 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid; 964 io->io_hdr.nexus.targ_port = cs->cs_target->ct_softc->fe.targ_port; 965 io->io_hdr.nexus.targ_target.id = 0; 966 io->io_hdr.nexus.targ_lun = lun; 967 io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */ 968 io->taskio.task_action = CTL_TASK_ABORT_TASK_SET; 969 error = ctl_queue(io); 970 if (error != CTL_RETVAL_COMPLETE) { 971 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error); 972 ctl_free_io(io); 973 } 974#else 975 /* 976 * CTL doesn't currently support CTL_TASK_ABORT_TASK_SET, so instead 977 * just iterate over tasks that are waiting for something - data - and 978 * terminate those. 979 */ 980 CFISCSI_SESSION_LOCK(cs); 981 TAILQ_FOREACH_SAFE(cdw, 982 &cs->cs_waiting_for_data_out, cdw_next, tmpcdw) { 983 io = ctl_alloc_io(cs->cs_target->ct_softc->fe.ctl_pool_ref); 984 if (io == NULL) { 985 CFISCSI_SESSION_WARN(cs, "can't allocate ctl_io"); 986 return; 987 } 988 ctl_zero_io(io); 989 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL; 990 io->io_hdr.io_type = CTL_IO_TASK; 991 io->io_hdr.nexus.initid.id = cs->cs_ctl_initid; 992 io->io_hdr.nexus.targ_port = 993 cs->cs_target->ct_softc->fe.targ_port; 994 io->io_hdr.nexus.targ_target.id = 0; 995 //io->io_hdr.nexus.targ_lun = lun; /* Not needed? */ 996 io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */ 997 io->taskio.task_action = CTL_TASK_ABORT_TASK; 998 io->taskio.tag_num = cdw->cdw_initiator_task_tag; 999 error = ctl_queue(io); 1000 if (error != CTL_RETVAL_COMPLETE) { 1001 CFISCSI_SESSION_WARN(cs, "ctl_queue() failed; error %d", error); 1002 ctl_free_io(io); 1003 return; 1004 } 1005#if 0 1006 CFISCSI_SESSION_DEBUG(cs, "removing csw for initiator task tag " 1007 "0x%x", cdw->cdw_initiator_task_tag); 1008#endif 1009 cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io); 1010 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next); 1011 uma_zfree(cfiscsi_data_wait_zone, cdw); 1012 } 1013 CFISCSI_SESSION_UNLOCK(cs); 1014#endif 1015} 1016 1017static void 1018cfiscsi_maintenance_thread(void *arg) 1019{ 1020 struct cfiscsi_session *cs; 1021 1022 cs = arg; 1023 1024 for (;;) { 1025 CFISCSI_SESSION_LOCK(cs); 1026 if (cs->cs_terminating == false) 1027 cv_wait(&cs->cs_maintenance_cv, &cs->cs_lock); 1028 CFISCSI_SESSION_UNLOCK(cs); 1029 1030 if (cs->cs_terminating) { 1031 cfiscsi_session_terminate_tasks(cs); 1032 callout_drain(&cs->cs_callout); 1033 1034 icl_conn_shutdown(cs->cs_conn); 1035 icl_conn_close(cs->cs_conn); 1036 1037 cs->cs_terminating++; 1038 1039 /* 1040 * XXX: We used to wait up to 30 seconds to deliver queued PDUs 1041 * to the initiator. We also tried hard to deliver SCSI Responses 1042 * for the aborted PDUs. We don't do that anymore. We might need 1043 * to revisit that. 1044 */ 1045 1046 cfiscsi_session_delete(cs); 1047 kthread_exit(); 1048 return; 1049 } 1050 CFISCSI_SESSION_DEBUG(cs, "nothing to do"); 1051 } 1052} 1053 1054static void 1055cfiscsi_session_terminate(struct cfiscsi_session *cs) 1056{ 1057 1058 if (cs->cs_terminating != 0) 1059 return; 1060 cs->cs_terminating = 1; 1061 cv_signal(&cs->cs_maintenance_cv); 1062} 1063 1064static int 1065cfiscsi_session_register_initiator(struct cfiscsi_session *cs) 1066{ 1067 int error, i; 1068 struct cfiscsi_softc *softc; 1069 1070 KASSERT(cs->cs_ctl_initid == -1, ("already registered")); 1071 1072 softc = &cfiscsi_softc; 1073 1074 mtx_lock(&softc->lock); 1075 for (i = 0; i < softc->max_initiators; i++) { 1076 if (softc->ctl_initids[i] == 0) 1077 break; 1078 } 1079 if (i == softc->max_initiators) { 1080 CFISCSI_SESSION_WARN(cs, "too many concurrent sessions (%d)", 1081 softc->max_initiators); 1082 mtx_unlock(&softc->lock); 1083 return (1); 1084 } 1085 softc->ctl_initids[i] = 1; 1086 mtx_unlock(&softc->lock); 1087 1088#if 0 1089 CFISCSI_SESSION_DEBUG(cs, "adding initiator id %d, max %d", 1090 i, softc->max_initiators); 1091#endif 1092 cs->cs_ctl_initid = i; 1093 error = ctl_add_initiator(0x0, softc->fe.targ_port, cs->cs_ctl_initid); 1094 if (error != 0) { 1095 CFISCSI_SESSION_WARN(cs, "ctl_add_initiator failed with error %d", error); 1096 mtx_lock(&softc->lock); 1097 softc->ctl_initids[cs->cs_ctl_initid] = 0; 1098 mtx_unlock(&softc->lock); 1099 cs->cs_ctl_initid = -1; 1100 return (1); 1101 } 1102 1103 return (0); 1104} 1105 1106static void 1107cfiscsi_session_unregister_initiator(struct cfiscsi_session *cs) 1108{ 1109 int error; 1110 struct cfiscsi_softc *softc; 1111 1112 if (cs->cs_ctl_initid == -1) 1113 return; 1114 1115 softc = &cfiscsi_softc; 1116 1117 error = ctl_remove_initiator(softc->fe.targ_port, cs->cs_ctl_initid); 1118 if (error != 0) { 1119 CFISCSI_SESSION_WARN(cs, "ctl_remove_initiator failed with error %d", 1120 error); 1121 } 1122 mtx_lock(&softc->lock); 1123 softc->ctl_initids[cs->cs_ctl_initid] = 0; 1124 mtx_unlock(&softc->lock); 1125 cs->cs_ctl_initid = -1; 1126} 1127 1128static struct cfiscsi_session * 1129cfiscsi_session_new(struct cfiscsi_softc *softc) 1130{ 1131 struct cfiscsi_session *cs; 1132 int error; 1133 1134 cs = malloc(sizeof(*cs), M_CFISCSI, M_NOWAIT | M_ZERO); 1135 if (cs == NULL) { 1136 CFISCSI_WARN("malloc failed"); 1137 return (NULL); 1138 } 1139 cs->cs_ctl_initid = -1; 1140 1141 refcount_init(&cs->cs_outstanding_ctl_pdus, 0); 1142 TAILQ_INIT(&cs->cs_waiting_for_data_out); 1143 mtx_init(&cs->cs_lock, "cfiscsi_lock", NULL, MTX_DEF); 1144 cv_init(&cs->cs_maintenance_cv, "cfiscsi_mt"); 1145#ifdef ICL_KERNEL_PROXY 1146 cv_init(&cs->cs_login_cv, "cfiscsi_login"); 1147#endif 1148 1149 cs->cs_conn = icl_conn_new(); 1150 cs->cs_conn->ic_receive = cfiscsi_receive_callback; 1151 cs->cs_conn->ic_error = cfiscsi_error_callback; 1152 cs->cs_conn->ic_prv0 = cs; 1153 1154 error = kthread_add(cfiscsi_maintenance_thread, cs, NULL, NULL, 0, 0, "cfiscsimt"); 1155 if (error != 0) { 1156 CFISCSI_SESSION_WARN(cs, "kthread_add(9) failed with error %d", error); 1157 free(cs, M_CFISCSI); 1158 return (NULL); 1159 } 1160 1161 mtx_lock(&softc->lock); 1162 cs->cs_id = softc->last_session_id + 1; 1163 softc->last_session_id++; 1164 mtx_unlock(&softc->lock); 1165 1166 mtx_lock(&softc->lock); 1167 TAILQ_INSERT_TAIL(&softc->sessions, cs, cs_next); 1168 mtx_unlock(&softc->lock); 1169 1170 /* 1171 * Start pinging the initiator. 1172 */ 1173 callout_init(&cs->cs_callout, 1); 1174 callout_reset(&cs->cs_callout, 1 * hz, cfiscsi_callout, cs); 1175 1176 return (cs); 1177} 1178 1179static void 1180cfiscsi_session_delete(struct cfiscsi_session *cs) 1181{ 1182 struct cfiscsi_softc *softc; 1183 1184 softc = &cfiscsi_softc; 1185 1186 KASSERT(cs->cs_outstanding_ctl_pdus == 0, 1187 ("destroying session with outstanding CTL pdus")); 1188 KASSERT(TAILQ_EMPTY(&cs->cs_waiting_for_data_out), 1189 ("destroying session with non-empty queue")); 1190 1191 cfiscsi_session_unregister_initiator(cs); 1192 if (cs->cs_target != NULL) 1193 cfiscsi_target_release(cs->cs_target); 1194 icl_conn_close(cs->cs_conn); 1195 icl_conn_free(cs->cs_conn); 1196 1197 mtx_lock(&softc->lock); 1198 TAILQ_REMOVE(&softc->sessions, cs, cs_next); 1199 mtx_unlock(&softc->lock); 1200 1201 free(cs, M_CFISCSI); 1202} 1203 1204int 1205cfiscsi_init(void) 1206{ 1207 struct cfiscsi_softc *softc; 1208 struct ctl_frontend *fe; 1209 int retval; 1210 1211 softc = &cfiscsi_softc; 1212 retval = 0; 1213 bzero(softc, sizeof(*softc)); 1214 mtx_init(&softc->lock, "cfiscsi", NULL, MTX_DEF); 1215 1216#ifdef ICL_KERNEL_PROXY 1217 cv_init(&softc->accept_cv, "cfiscsi_accept"); 1218#endif 1219 TAILQ_INIT(&softc->sessions); 1220 TAILQ_INIT(&softc->targets); 1221 1222 fe = &softc->fe; 1223 fe->port_type = CTL_PORT_ISCSI; 1224 /* XXX KDM what should the real number be here? */ 1225 fe->num_requested_ctl_io = 4096; 1226 snprintf(softc->port_name, sizeof(softc->port_name), "iscsi"); 1227 fe->port_name = softc->port_name; 1228 fe->port_online = cfiscsi_online; 1229 fe->port_offline = cfiscsi_offline; 1230 fe->onoff_arg = softc; 1231 fe->targ_enable = cfiscsi_targ_enable; 1232 fe->targ_disable = cfiscsi_targ_disable; 1233 fe->lun_enable = cfiscsi_lun_enable; 1234 fe->lun_disable = cfiscsi_lun_disable; 1235 fe->targ_lun_arg = softc; 1236 fe->ioctl = cfiscsi_ioctl; 1237 fe->devid = cfiscsi_devid; 1238 fe->fe_datamove = cfiscsi_datamove; 1239 fe->fe_done = cfiscsi_done; 1240 1241 /* XXX KDM what should we report here? */ 1242 /* XXX These should probably be fetched from CTL. */ 1243 fe->max_targets = 1; 1244 fe->max_target_id = 15; 1245 1246 retval = ctl_frontend_register(fe, /*master_SC*/ 1); 1247 if (retval != 0) { 1248 CFISCSI_WARN("ctl_frontend_register() failed with error %d", 1249 retval); 1250 retval = 1; 1251 goto bailout; 1252 } 1253 1254 softc->max_initiators = fe->max_initiators; 1255 1256 cfiscsi_data_wait_zone = uma_zcreate("cfiscsi_data_wait", 1257 sizeof(struct cfiscsi_data_wait), NULL, NULL, NULL, NULL, 1258 UMA_ALIGN_PTR, 0); 1259 1260 return (0); 1261 1262bailout: 1263 return (retval); 1264} 1265 1266static int 1267cfiscsi_module_event_handler(module_t mod, int what, void *arg) 1268{ 1269 1270 switch (what) { 1271 case MOD_LOAD: 1272 return (cfiscsi_init()); 1273 case MOD_UNLOAD: 1274 return (EBUSY); 1275 default: 1276 return (EOPNOTSUPP); 1277 } 1278} 1279 1280#ifdef ICL_KERNEL_PROXY 1281static void 1282cfiscsi_accept(struct socket *so) 1283{ 1284 struct cfiscsi_session *cs; 1285 1286 cs = cfiscsi_session_new(&cfiscsi_softc); 1287 if (cs == NULL) { 1288 CFISCSI_WARN("failed to create session"); 1289 return; 1290 } 1291 1292 icl_conn_handoff_sock(cs->cs_conn, so); 1293 cs->cs_waiting_for_ctld = true; 1294 cv_signal(&cfiscsi_softc.accept_cv); 1295} 1296#endif 1297 1298static void 1299cfiscsi_online(void *arg) 1300{ 1301 struct cfiscsi_softc *softc; 1302 1303 softc = (struct cfiscsi_softc *)arg; 1304 1305 softc->online = 1; 1306#ifdef ICL_KERNEL_PROXY 1307 if (softc->listener != NULL) 1308 icl_listen_free(softc->listener); 1309 softc->listener = icl_listen_new(cfiscsi_accept); 1310#endif 1311} 1312 1313static void 1314cfiscsi_offline(void *arg) 1315{ 1316 struct cfiscsi_softc *softc; 1317 struct cfiscsi_session *cs; 1318 1319 softc = (struct cfiscsi_softc *)arg; 1320 1321 softc->online = 0; 1322 1323 mtx_lock(&softc->lock); 1324 TAILQ_FOREACH(cs, &softc->sessions, cs_next) 1325 cfiscsi_session_terminate(cs); 1326 mtx_unlock(&softc->lock); 1327 1328#ifdef ICL_KERNEL_PROXY 1329 icl_listen_free(softc->listener); 1330 softc->listener = NULL; 1331#endif 1332} 1333 1334static int 1335cfiscsi_targ_enable(void *arg, struct ctl_id targ_id) 1336{ 1337 1338 return (0); 1339} 1340 1341static int 1342cfiscsi_targ_disable(void *arg, struct ctl_id targ_id) 1343{ 1344 1345 return (0); 1346} 1347 1348static void 1349cfiscsi_ioctl_handoff(struct ctl_iscsi *ci) 1350{ 1351 struct cfiscsi_softc *softc; 1352 struct cfiscsi_session *cs; 1353 struct cfiscsi_target *ct; 1354 struct ctl_iscsi_handoff_params *cihp; 1355#ifndef ICL_KERNEL_PROXY 1356 int error; 1357#endif 1358 1359 cihp = (struct ctl_iscsi_handoff_params *)&(ci->data); 1360 softc = &cfiscsi_softc; 1361 1362 CFISCSI_DEBUG("new connection from %s (%s) to %s", 1363 cihp->initiator_name, cihp->initiator_addr, 1364 cihp->target_name); 1365 1366 if (softc->online == 0) { 1367 ci->status = CTL_ISCSI_ERROR; 1368 snprintf(ci->error_str, sizeof(ci->error_str), 1369 "%s: port offline", __func__); 1370 return; 1371 } 1372 1373 ct = cfiscsi_target_find(softc, cihp->target_name); 1374 if (ct == NULL) { 1375 ci->status = CTL_ISCSI_ERROR; 1376 snprintf(ci->error_str, sizeof(ci->error_str), 1377 "%s: target not found", __func__); 1378 return; 1379 } 1380 1381#ifdef ICL_KERNEL_PROXY 1382 mtx_lock(&cfiscsi_softc.lock); 1383 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) { 1384 if (cs->cs_id == cihp->socket) 1385 break; 1386 } 1387 if (cs == NULL) { 1388 mtx_unlock(&cfiscsi_softc.lock); 1389 snprintf(ci->error_str, sizeof(ci->error_str), "connection not found"); 1390 ci->status = CTL_ISCSI_ERROR; 1391 return; 1392 } 1393 mtx_unlock(&cfiscsi_softc.lock); 1394#else 1395 cs = cfiscsi_session_new(softc); 1396 if (cs == NULL) { 1397 ci->status = CTL_ISCSI_ERROR; 1398 snprintf(ci->error_str, sizeof(ci->error_str), 1399 "%s: cfiscsi_session_new failed", __func__); 1400 cfiscsi_target_release(ct); 1401 return; 1402 } 1403#endif 1404 cs->cs_target = ct; 1405 1406 /* 1407 * First PDU of Full Feature phase has the same CmdSN as the last 1408 * PDU from the Login Phase received from the initiator. Thus, 1409 * the -1 below. 1410 */ 1411 cs->cs_portal_group_tag = cihp->portal_group_tag; 1412 cs->cs_cmdsn = cihp->cmdsn; 1413 cs->cs_statsn = cihp->statsn; 1414 cs->cs_max_data_segment_length = cihp->max_recv_data_segment_length; 1415 cs->cs_max_burst_length = cihp->max_burst_length; 1416 cs->cs_immediate_data = !!cihp->immediate_data; 1417 if (cihp->header_digest == CTL_ISCSI_DIGEST_CRC32C) 1418 cs->cs_conn->ic_header_crc32c = true; 1419 if (cihp->data_digest == CTL_ISCSI_DIGEST_CRC32C) 1420 cs->cs_conn->ic_data_crc32c = true; 1421 1422 strlcpy(cs->cs_initiator_name, 1423 cihp->initiator_name, sizeof(cs->cs_initiator_name)); 1424 strlcpy(cs->cs_initiator_addr, 1425 cihp->initiator_addr, sizeof(cs->cs_initiator_addr)); 1426 strlcpy(cs->cs_initiator_alias, 1427 cihp->initiator_alias, sizeof(cs->cs_initiator_alias)); 1428 1429#ifdef ICL_KERNEL_PROXY 1430 cs->cs_login_phase = false; 1431#else 1432 error = icl_conn_handoff(cs->cs_conn, cihp->socket); 1433 if (error != 0) { 1434 cfiscsi_session_delete(cs); 1435 ci->status = CTL_ISCSI_ERROR; 1436 snprintf(ci->error_str, sizeof(ci->error_str), 1437 "%s: icl_conn_handoff failed with error %d", 1438 __func__, error); 1439 return; 1440 } 1441#endif 1442 1443 /* 1444 * Register initiator with CTL. 1445 */ 1446 cfiscsi_session_register_initiator(cs); 1447 1448#ifdef ICL_KERNEL_PROXY 1449 /* 1450 * First PDU of the Full Feature phase has likely already arrived. 1451 * We have to pick it up and execute properly. 1452 */ 1453 if (cs->cs_login_pdu != NULL) { 1454 CFISCSI_SESSION_DEBUG(cs, "picking up first PDU"); 1455 cfiscsi_pdu_handle(cs->cs_login_pdu); 1456 cs->cs_login_pdu = NULL; 1457 } 1458#endif 1459 1460 ci->status = CTL_ISCSI_OK; 1461} 1462 1463static void 1464cfiscsi_ioctl_list(struct ctl_iscsi *ci) 1465{ 1466 struct ctl_iscsi_list_params *cilp; 1467 struct cfiscsi_session *cs; 1468 struct cfiscsi_softc *softc; 1469 struct sbuf *sb; 1470 int error; 1471 1472 cilp = (struct ctl_iscsi_list_params *)&(ci->data); 1473 softc = &cfiscsi_softc; 1474 1475 sb = sbuf_new(NULL, NULL, cilp->alloc_len, SBUF_FIXEDLEN); 1476 if (sb == NULL) { 1477 ci->status = CTL_ISCSI_ERROR; 1478 snprintf(ci->error_str, sizeof(ci->error_str), 1479 "Unable to allocate %d bytes for iSCSI session list", 1480 cilp->alloc_len); 1481 return; 1482 } 1483 1484 sbuf_printf(sb, "<ctlislist>\n"); 1485 mtx_lock(&softc->lock); 1486 TAILQ_FOREACH(cs, &softc->sessions, cs_next) { 1487#ifdef ICL_KERNEL_PROXY 1488 if (cs->cs_target == NULL) 1489 continue; 1490#endif 1491 error = sbuf_printf(sb, "<connection id=\"%d\">" 1492 "<initiator>%s</initiator>" 1493 "<initiator_addr>%s</initiator_addr>" 1494 "<initiator_alias>%s</initiator_alias>" 1495 "<target>%s</target>" 1496 "<target_alias>%s</target_alias>" 1497 "<header_digest>%s</header_digest>" 1498 "<data_digest>%s</data_digest>" 1499 "<max_data_segment_length>%zd</max_data_segment_length>" 1500 "<immediate_data>%d</immediate_data>" 1501 "<iser>%d</iser>" 1502 "</connection>\n", 1503 cs->cs_id, 1504 cs->cs_initiator_name, cs->cs_initiator_addr, cs->cs_initiator_alias, 1505 cs->cs_target->ct_name, cs->cs_target->ct_alias, 1506 cs->cs_conn->ic_header_crc32c ? "CRC32C" : "None", 1507 cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None", 1508 cs->cs_max_data_segment_length, 1509 cs->cs_immediate_data, 1510 cs->cs_conn->ic_iser); 1511 if (error != 0) 1512 break; 1513 } 1514 mtx_unlock(&softc->lock); 1515 error = sbuf_printf(sb, "</ctlislist>\n"); 1516 if (error != 0) { 1517 sbuf_delete(sb); 1518 ci->status = CTL_ISCSI_LIST_NEED_MORE_SPACE; 1519 snprintf(ci->error_str, sizeof(ci->error_str), 1520 "Out of space, %d bytes is too small", cilp->alloc_len); 1521 return; 1522 } 1523 sbuf_finish(sb); 1524 1525 error = copyout(sbuf_data(sb), cilp->conn_xml, sbuf_len(sb) + 1); 1526 cilp->fill_len = sbuf_len(sb) + 1; 1527 ci->status = CTL_ISCSI_OK; 1528 sbuf_delete(sb); 1529} 1530 1531static void 1532cfiscsi_ioctl_terminate(struct ctl_iscsi *ci) 1533{ 1534 struct icl_pdu *response; 1535 struct iscsi_bhs_asynchronous_message *bhsam; 1536 struct ctl_iscsi_terminate_params *citp; 1537 struct cfiscsi_session *cs; 1538 struct cfiscsi_softc *softc; 1539 int found = 0; 1540 1541 citp = (struct ctl_iscsi_terminate_params *)&(ci->data); 1542 softc = &cfiscsi_softc; 1543 1544 mtx_lock(&softc->lock); 1545 TAILQ_FOREACH(cs, &softc->sessions, cs_next) { 1546 if (citp->all == 0 && cs->cs_id != citp->connection_id && 1547 strcmp(cs->cs_initiator_name, citp->initiator_name) != 0 && 1548 strcmp(cs->cs_initiator_addr, citp->initiator_addr) != 0) 1549 continue; 1550 1551 response = icl_pdu_new_bhs(cs->cs_conn, M_NOWAIT); 1552 if (response == NULL) { 1553 /* 1554 * Oh well. Just terminate the connection. 1555 */ 1556 } else { 1557 bhsam = (struct iscsi_bhs_asynchronous_message *) 1558 response->ip_bhs; 1559 bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE; 1560 bhsam->bhsam_flags = 0x80; 1561 bhsam->bhsam_0xffffffff = 0xffffffff; 1562 bhsam->bhsam_async_event = 1563 BHSAM_EVENT_TARGET_TERMINATES_SESSION; 1564 cfiscsi_pdu_queue(response); 1565 } 1566 cfiscsi_session_terminate(cs); 1567 found++; 1568 } 1569 mtx_unlock(&softc->lock); 1570 1571 if (found == 0) { 1572 ci->status = CTL_ISCSI_SESSION_NOT_FOUND; 1573 snprintf(ci->error_str, sizeof(ci->error_str), 1574 "No matching connections found"); 1575 return; 1576 } 1577 1578 ci->status = CTL_ISCSI_OK; 1579} 1580 1581static void 1582cfiscsi_ioctl_logout(struct ctl_iscsi *ci) 1583{ 1584 struct icl_pdu *response; 1585 struct iscsi_bhs_asynchronous_message *bhsam; 1586 struct ctl_iscsi_logout_params *cilp; 1587 struct cfiscsi_session *cs; 1588 struct cfiscsi_softc *softc; 1589 int found = 0; 1590 1591 cilp = (struct ctl_iscsi_logout_params *)&(ci->data); 1592 softc = &cfiscsi_softc; 1593 1594 mtx_lock(&softc->lock); 1595 TAILQ_FOREACH(cs, &softc->sessions, cs_next) { 1596 if (cilp->all == 0 && cs->cs_id != cilp->connection_id && 1597 strcmp(cs->cs_initiator_name, cilp->initiator_name) != 0 && 1598 strcmp(cs->cs_initiator_addr, cilp->initiator_addr) != 0) 1599 continue; 1600 1601 response = icl_pdu_new_bhs(cs->cs_conn, M_NOWAIT); 1602 if (response == NULL) { 1603 ci->status = CTL_ISCSI_ERROR; 1604 snprintf(ci->error_str, sizeof(ci->error_str), 1605 "Unable to allocate memory"); 1606 mtx_unlock(&softc->lock); 1607 return; 1608 } 1609 bhsam = 1610 (struct iscsi_bhs_asynchronous_message *)response->ip_bhs; 1611 bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE; 1612 bhsam->bhsam_flags = 0x80; 1613 bhsam->bhsam_async_event = BHSAM_EVENT_TARGET_REQUESTS_LOGOUT; 1614 bhsam->bhsam_parameter3 = htons(10); 1615 cfiscsi_pdu_queue(response); 1616 found++; 1617 } 1618 mtx_unlock(&softc->lock); 1619 1620 if (found == 0) { 1621 ci->status = CTL_ISCSI_SESSION_NOT_FOUND; 1622 snprintf(ci->error_str, sizeof(ci->error_str), 1623 "No matching connections found"); 1624 return; 1625 } 1626 1627 ci->status = CTL_ISCSI_OK; 1628} 1629 1630#ifdef ICL_KERNEL_PROXY 1631static void 1632cfiscsi_ioctl_listen(struct ctl_iscsi *ci) 1633{ 1634 struct ctl_iscsi_listen_params *cilp; 1635 struct sockaddr *sa; 1636 int error; 1637 1638 cilp = (struct ctl_iscsi_listen_params *)&(ci->data); 1639 1640 if (cfiscsi_softc.listener == NULL) { 1641 CFISCSI_DEBUG("no listener"); 1642 snprintf(ci->error_str, sizeof(ci->error_str), "no listener"); 1643 ci->status = CTL_ISCSI_ERROR; 1644 return; 1645 } 1646 1647 error = getsockaddr(&sa, (void *)cilp->addr, cilp->addrlen); 1648 if (error != 0) { 1649 CFISCSI_DEBUG("getsockaddr, error %d", error); 1650 snprintf(ci->error_str, sizeof(ci->error_str), "getsockaddr failed"); 1651 ci->status = CTL_ISCSI_ERROR; 1652 return; 1653 } 1654 1655 error = icl_listen_add(cfiscsi_softc.listener, cilp->iser, cilp->domain, 1656 cilp->socktype, cilp->protocol, sa); 1657 if (error != 0) { 1658 free(sa, M_SONAME); 1659 CFISCSI_DEBUG("icl_listen_add, error %d", error); 1660 snprintf(ci->error_str, sizeof(ci->error_str), 1661 "icl_listen_add failed, error %d", error); 1662 ci->status = CTL_ISCSI_ERROR; 1663 return; 1664 } 1665 1666 ci->status = CTL_ISCSI_OK; 1667} 1668 1669static void 1670cfiscsi_ioctl_accept(struct ctl_iscsi *ci) 1671{ 1672 struct ctl_iscsi_accept_params *ciap; 1673 struct cfiscsi_session *cs; 1674 int error; 1675 1676 ciap = (struct ctl_iscsi_accept_params *)&(ci->data); 1677 1678 mtx_lock(&cfiscsi_softc.lock); 1679 for (;;) { 1680 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) { 1681 if (cs->cs_waiting_for_ctld) 1682 break; 1683 } 1684 if (cs != NULL) 1685 break; 1686 error = cv_wait_sig(&cfiscsi_softc.accept_cv, &cfiscsi_softc.lock); 1687 if (error != 0) { 1688 mtx_unlock(&cfiscsi_softc.lock); 1689 snprintf(ci->error_str, sizeof(ci->error_str), "interrupted"); 1690 ci->status = CTL_ISCSI_ERROR; 1691 return; 1692 } 1693 } 1694 mtx_unlock(&cfiscsi_softc.lock); 1695 1696 cs->cs_waiting_for_ctld = false; 1697 cs->cs_login_phase = true; 1698 1699 ciap->connection_id = cs->cs_id; 1700 ci->status = CTL_ISCSI_OK; 1701} 1702 1703static void 1704cfiscsi_ioctl_send(struct ctl_iscsi *ci) 1705{ 1706 struct ctl_iscsi_send_params *cisp; 1707 struct cfiscsi_session *cs; 1708 struct icl_pdu *ip; 1709 size_t datalen; 1710 void *data; 1711 int error; 1712 1713 cisp = (struct ctl_iscsi_send_params *)&(ci->data); 1714 1715 mtx_lock(&cfiscsi_softc.lock); 1716 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) { 1717 if (cs->cs_id == cisp->connection_id) 1718 break; 1719 } 1720 if (cs == NULL) { 1721 mtx_unlock(&cfiscsi_softc.lock); 1722 snprintf(ci->error_str, sizeof(ci->error_str), "connection not found"); 1723 ci->status = CTL_ISCSI_ERROR; 1724 return; 1725 } 1726 mtx_unlock(&cfiscsi_softc.lock); 1727 1728#if 0 1729 if (cs->cs_login_phase == false) 1730 return (EBUSY); 1731#endif 1732 1733 if (cs->cs_terminating) { 1734 snprintf(ci->error_str, sizeof(ci->error_str), "connection is terminating"); 1735 ci->status = CTL_ISCSI_ERROR; 1736 return; 1737 } 1738 1739 datalen = cisp->data_segment_len; 1740 /* 1741 * XXX 1742 */ 1743 //if (datalen > CFISCSI_MAX_DATA_SEGMENT_LENGTH) { 1744 if (datalen > 65535) { 1745 snprintf(ci->error_str, sizeof(ci->error_str), "data segment too big"); 1746 ci->status = CTL_ISCSI_ERROR; 1747 return; 1748 } 1749 if (datalen > 0) { 1750 data = malloc(datalen, M_CFISCSI, M_WAITOK); 1751 error = copyin(cisp->data_segment, data, datalen); 1752 if (error != 0) { 1753 free(data, M_CFISCSI); 1754 snprintf(ci->error_str, sizeof(ci->error_str), "copyin error %d", error); 1755 ci->status = CTL_ISCSI_ERROR; 1756 return; 1757 } 1758 } 1759 1760 ip = icl_pdu_new_bhs(cs->cs_conn, M_WAITOK); 1761 memcpy(ip->ip_bhs, cisp->bhs, sizeof(*ip->ip_bhs)); 1762 if (datalen > 0) { 1763 icl_pdu_append_data(ip, data, datalen, M_WAITOK); 1764 free(data, M_CFISCSI); 1765 } 1766 icl_pdu_queue(ip); 1767 ci->status = CTL_ISCSI_OK; 1768} 1769 1770static void 1771cfiscsi_ioctl_receive(struct ctl_iscsi *ci) 1772{ 1773 struct ctl_iscsi_receive_params *cirp; 1774 struct cfiscsi_session *cs; 1775 struct icl_pdu *ip; 1776 void *data; 1777 1778 cirp = (struct ctl_iscsi_receive_params *)&(ci->data); 1779 1780 mtx_lock(&cfiscsi_softc.lock); 1781 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) { 1782 if (cs->cs_id == cirp->connection_id) 1783 break; 1784 } 1785 if (cs == NULL) { 1786 mtx_unlock(&cfiscsi_softc.lock); 1787 snprintf(ci->error_str, sizeof(ci->error_str), "connection not found"); 1788 ci->status = CTL_ISCSI_ERROR; 1789 return; 1790 } 1791 mtx_unlock(&cfiscsi_softc.lock); 1792 1793#if 0 1794 if (is->is_login_phase == false) 1795 return (EBUSY); 1796#endif 1797 1798 CFISCSI_SESSION_LOCK(cs); 1799 while (cs->cs_login_pdu == NULL && 1800 cs->cs_terminating == false) 1801 cv_wait(&cs->cs_login_cv, &cs->cs_lock); 1802 if (cs->cs_terminating) { 1803 CFISCSI_SESSION_UNLOCK(cs); 1804 snprintf(ci->error_str, sizeof(ci->error_str), "connection terminating"); 1805 ci->status = CTL_ISCSI_ERROR; 1806 return; 1807 } 1808 ip = cs->cs_login_pdu; 1809 cs->cs_login_pdu = NULL; 1810 CFISCSI_SESSION_UNLOCK(cs); 1811 1812 if (ip->ip_data_len > cirp->data_segment_len) { 1813 icl_pdu_free(ip); 1814 snprintf(ci->error_str, sizeof(ci->error_str), "data segment too big"); 1815 ci->status = CTL_ISCSI_ERROR; 1816 return; 1817 } 1818 1819 copyout(ip->ip_bhs, cirp->bhs, sizeof(*ip->ip_bhs)); 1820 if (ip->ip_data_len > 0) { 1821 data = malloc(ip->ip_data_len, M_CFISCSI, M_WAITOK); 1822 icl_pdu_get_data(ip, 0, data, ip->ip_data_len); 1823 copyout(data, cirp->data_segment, ip->ip_data_len); 1824 free(data, M_CFISCSI); 1825 } 1826 1827 icl_pdu_free(ip); 1828 ci->status = CTL_ISCSI_OK; 1829} 1830 1831static void 1832cfiscsi_ioctl_close(struct ctl_iscsi *ci) 1833{ 1834 /* 1835 * XXX 1836 */ 1837} 1838#endif /* !ICL_KERNEL_PROXY */ 1839 1840static int 1841cfiscsi_ioctl(struct cdev *dev, 1842 u_long cmd, caddr_t addr, int flag, struct thread *td) 1843{ 1844 struct ctl_iscsi *ci; 1845 1846 if (cmd != CTL_ISCSI) 1847 return (ENOTTY); 1848 1849 ci = (struct ctl_iscsi *)addr; 1850 switch (ci->type) { 1851 case CTL_ISCSI_HANDOFF: 1852 cfiscsi_ioctl_handoff(ci); 1853 break; 1854 case CTL_ISCSI_LIST: 1855 cfiscsi_ioctl_list(ci); 1856 break; 1857 case CTL_ISCSI_TERMINATE: 1858 cfiscsi_ioctl_terminate(ci); 1859 break; 1860 case CTL_ISCSI_LOGOUT: 1861 cfiscsi_ioctl_logout(ci); 1862 break; 1863#ifdef ICL_KERNEL_PROXY 1864 case CTL_ISCSI_LISTEN: 1865 cfiscsi_ioctl_listen(ci); 1866 break; 1867 case CTL_ISCSI_ACCEPT: 1868 cfiscsi_ioctl_accept(ci); 1869 break; 1870 case CTL_ISCSI_SEND: 1871 cfiscsi_ioctl_send(ci); 1872 break; 1873 case CTL_ISCSI_RECEIVE: 1874 cfiscsi_ioctl_receive(ci); 1875 break; 1876 case CTL_ISCSI_CLOSE: 1877 cfiscsi_ioctl_close(ci); 1878 break; 1879#endif /* ICL_KERNEL_PROXY */ 1880 default: 1881 ci->status = CTL_ISCSI_ERROR; 1882 snprintf(ci->error_str, sizeof(ci->error_str), 1883 "%s: invalid iSCSI request type %d", __func__, ci->type); 1884 break; 1885 } 1886 1887 return (0); 1888} 1889 1890static int 1891cfiscsi_devid(struct ctl_scsiio *ctsio, int alloc_len) 1892{ 1893 struct cfiscsi_session *cs; 1894 struct scsi_vpd_device_id *devid_ptr; 1895 struct scsi_vpd_id_descriptor *desc, *desc1; 1896 struct scsi_vpd_id_descriptor *desc2, *desc3; /* for types 4h and 5h */ 1897 struct scsi_vpd_id_t10 *t10id; 1898 struct ctl_lun *lun; 1899 const struct icl_pdu *request; 1900 size_t devid_len, wwpn_len; 1901 1902 lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; 1903 request = ctsio->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 1904 cs = PDU_SESSION(request); 1905 1906 wwpn_len = strlen(cs->cs_target->ct_name); 1907 wwpn_len += strlen(",t,0x01"); 1908 wwpn_len += 1; /* '\0' */ 1909 if ((wwpn_len % 4) != 0) 1910 wwpn_len += (4 - (wwpn_len % 4)); 1911 1912 devid_len = sizeof(struct scsi_vpd_device_id) + 1913 sizeof(struct scsi_vpd_id_descriptor) + 1914 sizeof(struct scsi_vpd_id_t10) + CTL_DEVID_LEN + 1915 sizeof(struct scsi_vpd_id_descriptor) + wwpn_len + 1916 sizeof(struct scsi_vpd_id_descriptor) + 1917 sizeof(struct scsi_vpd_id_rel_trgt_port_id) + 1918 sizeof(struct scsi_vpd_id_descriptor) + 1919 sizeof(struct scsi_vpd_id_trgt_port_grp_id); 1920 1921 ctsio->kern_data_ptr = malloc(devid_len, M_CTL, M_WAITOK | M_ZERO); 1922 devid_ptr = (struct scsi_vpd_device_id *)ctsio->kern_data_ptr; 1923 ctsio->kern_sg_entries = 0; 1924 1925 if (devid_len < alloc_len) { 1926 ctsio->residual = alloc_len - devid_len; 1927 ctsio->kern_data_len = devid_len; 1928 ctsio->kern_total_len = devid_len; 1929 } else { 1930 ctsio->residual = 0; 1931 ctsio->kern_data_len = alloc_len; 1932 ctsio->kern_total_len = alloc_len; 1933 } 1934 ctsio->kern_data_resid = 0; 1935 ctsio->kern_rel_offset = 0; 1936 ctsio->kern_sg_entries = 0; 1937 1938 desc = (struct scsi_vpd_id_descriptor *)devid_ptr->desc_list; 1939 t10id = (struct scsi_vpd_id_t10 *)&desc->identifier[0]; 1940 desc1 = (struct scsi_vpd_id_descriptor *)(&desc->identifier[0] + 1941 sizeof(struct scsi_vpd_id_t10) + CTL_DEVID_LEN); 1942 desc2 = (struct scsi_vpd_id_descriptor *)(&desc1->identifier[0] + 1943 wwpn_len); 1944 desc3 = (struct scsi_vpd_id_descriptor *)(&desc2->identifier[0] + 1945 sizeof(struct scsi_vpd_id_rel_trgt_port_id)); 1946 1947 if (lun != NULL) 1948 devid_ptr->device = (SID_QUAL_LU_CONNECTED << 5) | 1949 lun->be_lun->lun_type; 1950 else 1951 devid_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT; 1952 1953 devid_ptr->page_code = SVPD_DEVICE_ID; 1954 1955 scsi_ulto2b(devid_len - 4, devid_ptr->length); 1956 1957 /* 1958 * We're using a LUN association here. i.e., this device ID is a 1959 * per-LUN identifier. 1960 */ 1961 desc->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_ASCII; 1962 desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_LUN | SVPD_ID_TYPE_T10; 1963 desc->length = sizeof(*t10id) + CTL_DEVID_LEN; 1964 strncpy((char *)t10id->vendor, CTL_VENDOR, sizeof(t10id->vendor)); 1965 1966 /* 1967 * If we've actually got a backend, copy the device id from the 1968 * per-LUN data. Otherwise, set it to all spaces. 1969 */ 1970 if (lun != NULL) { 1971 /* 1972 * Copy the backend's LUN ID. 1973 */ 1974 strncpy((char *)t10id->vendor_spec_id, 1975 (char *)lun->be_lun->device_id, CTL_DEVID_LEN); 1976 } else { 1977 /* 1978 * No backend, set this to spaces. 1979 */ 1980 memset(t10id->vendor_spec_id, 0x20, CTL_DEVID_LEN); 1981 } 1982 1983 /* 1984 * desc1 is for the WWPN which is a port asscociation. 1985 */ 1986 desc1->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8; 1987 desc1->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT | 1988 SVPD_ID_TYPE_SCSI_NAME; 1989 desc1->length = wwpn_len; 1990 snprintf(desc1->identifier, wwpn_len, "%s,t,0x%x", 1991 cs->cs_target->ct_name, cs->cs_portal_group_tag); 1992 1993 /* 1994 * desc2 is for the Relative Target Port(type 4h) identifier 1995 */ 1996 desc2->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_BINARY; 1997 desc2->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT | 1998 SVPD_ID_TYPE_RELTARG; 1999 desc2->length = 4; 2000 desc2->identifier[3] = 1; 2001 2002 /* 2003 * desc3 is for the Target Port Group(type 5h) identifier 2004 */ 2005 desc3->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_BINARY; 2006 desc3->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT | 2007 SVPD_ID_TYPE_TPORTGRP; 2008 desc3->length = 4; 2009 desc3->identifier[3] = 1; 2010 2011 ctsio->scsi_status = SCSI_STATUS_OK; 2012 2013 ctsio->be_move_done = ctl_config_move_done; 2014 ctl_datamove((union ctl_io *)ctsio); 2015 2016 return (CTL_RETVAL_COMPLETE); 2017} 2018 2019static void 2020cfiscsi_target_hold(struct cfiscsi_target *ct) 2021{ 2022 2023 refcount_acquire(&ct->ct_refcount); 2024} 2025 2026static void 2027cfiscsi_target_release(struct cfiscsi_target *ct) 2028{ 2029 int old; 2030 struct cfiscsi_softc *softc; 2031 2032 softc = ct->ct_softc; 2033 2034 old = ct->ct_refcount; 2035 if (old > 1 && atomic_cmpset_int(&ct->ct_refcount, old, old - 1)) 2036 return; 2037 2038 mtx_lock(&softc->lock); 2039 if (refcount_release(&ct->ct_refcount)) { 2040 TAILQ_REMOVE(&softc->targets, ct, ct_next); 2041 mtx_unlock(&softc->lock); 2042 free(ct, M_CFISCSI); 2043 2044 return; 2045 } 2046 mtx_unlock(&softc->lock); 2047} 2048 2049static struct cfiscsi_target * 2050cfiscsi_target_find(struct cfiscsi_softc *softc, const char *name) 2051{ 2052 struct cfiscsi_target *ct; 2053 2054 mtx_lock(&softc->lock); 2055 TAILQ_FOREACH(ct, &softc->targets, ct_next) { 2056 if (strcmp(name, ct->ct_name) != 0) 2057 continue; 2058 cfiscsi_target_hold(ct); 2059 mtx_unlock(&softc->lock); 2060 return (ct); 2061 } 2062 mtx_unlock(&softc->lock); 2063 2064 return (NULL); 2065} 2066 2067static struct cfiscsi_target * 2068cfiscsi_target_find_or_create(struct cfiscsi_softc *softc, const char *name, 2069 const char *alias) 2070{ 2071 struct cfiscsi_target *ct, *newct; 2072 int i; 2073 2074 if (name[0] == '\0' || strlen(name) >= CTL_ISCSI_NAME_LEN) 2075 return (NULL); 2076 2077 newct = malloc(sizeof(*newct), M_CFISCSI, M_WAITOK | M_ZERO); 2078 2079 mtx_lock(&softc->lock); 2080 TAILQ_FOREACH(ct, &softc->targets, ct_next) { 2081 if (strcmp(name, ct->ct_name) != 0) 2082 continue; 2083 cfiscsi_target_hold(ct); 2084 mtx_unlock(&softc->lock); 2085 free(newct, M_CFISCSI); 2086 return (ct); 2087 } 2088 2089 for (i = 0; i < CTL_MAX_LUNS; i++) 2090 newct->ct_luns[i] = -1; 2091 2092 strlcpy(newct->ct_name, name, sizeof(newct->ct_name)); 2093 if (alias != NULL) 2094 strlcpy(newct->ct_alias, alias, sizeof(newct->ct_alias)); 2095 refcount_init(&newct->ct_refcount, 1); 2096 newct->ct_softc = softc; 2097 TAILQ_INSERT_TAIL(&softc->targets, newct, ct_next); 2098 mtx_unlock(&softc->lock); 2099 2100 return (newct); 2101} 2102 2103/* 2104 * Takes LUN from the target space and returns LUN from the CTL space. 2105 */ 2106static uint32_t 2107cfiscsi_map_lun(void *arg, uint32_t lun) 2108{ 2109 struct cfiscsi_session *cs; 2110 2111 cs = arg; 2112 2113 if (lun >= CTL_MAX_LUNS) { 2114 CFISCSI_DEBUG("requested lun number %d is higher " 2115 "than maximum %d", lun, CTL_MAX_LUNS - 1); 2116 return (0xffffffff); 2117 } 2118 2119 if (cs->cs_target->ct_luns[lun] < 0) 2120 return (0xffffffff); 2121 2122 return (cs->cs_target->ct_luns[lun]); 2123} 2124 2125static int 2126cfiscsi_target_set_lun(struct cfiscsi_target *ct, 2127 unsigned long lun_id, unsigned long ctl_lun_id) 2128{ 2129 2130 if (lun_id >= CTL_MAX_LUNS) { 2131 CFISCSI_WARN("requested lun number %ld is higher " 2132 "than maximum %d", lun_id, CTL_MAX_LUNS - 1); 2133 return (-1); 2134 } 2135 2136 if (ct->ct_luns[lun_id] >= 0) { 2137 /* 2138 * CTL calls cfiscsi_lun_enable() twice for each LUN - once 2139 * when the LUN is created, and a second time just before 2140 * the port is brought online; don't emit warnings 2141 * for that case. 2142 */ 2143 if (ct->ct_luns[lun_id] == ctl_lun_id) 2144 return (0); 2145 CFISCSI_WARN("lun %ld already allocated", lun_id); 2146 return (-1); 2147 } 2148 2149#if 0 2150 CFISCSI_DEBUG("adding mapping for lun %ld, target %s " 2151 "to ctl lun %ld", lun_id, ct->ct_name, ctl_lun_id); 2152#endif 2153 2154 ct->ct_luns[lun_id] = ctl_lun_id; 2155 cfiscsi_target_hold(ct); 2156 2157 return (0); 2158} 2159 2160static int 2161cfiscsi_target_unset_lun(struct cfiscsi_target *ct, unsigned long lun_id) 2162{ 2163 2164 if (ct->ct_luns[lun_id] < 0) { 2165 CFISCSI_WARN("lun %ld not allocated", lun_id); 2166 return (-1); 2167 } 2168 2169 ct->ct_luns[lun_id] = -1; 2170 cfiscsi_target_release(ct); 2171 2172 return (0); 2173} 2174 2175static int 2176cfiscsi_lun_enable(void *arg, struct ctl_id target_id, int lun_id) 2177{ 2178 struct cfiscsi_softc *softc; 2179 struct cfiscsi_target *ct; 2180 struct ctl_be_lun_option *opt; 2181 const char *target = NULL, *target_alias = NULL; 2182 const char *lun = NULL; 2183 unsigned long tmp; 2184 2185 softc = (struct cfiscsi_softc *)arg; 2186 2187 STAILQ_FOREACH(opt, 2188 &control_softc->ctl_luns[lun_id]->be_lun->options, links) { 2189 if (strcmp(opt->name, "cfiscsi_target") == 0) 2190 target = opt->value; 2191 else if (strcmp(opt->name, "cfiscsi_target_alias") == 0) 2192 target_alias = opt->value; 2193 else if (strcmp(opt->name, "cfiscsi_lun") == 0) 2194 lun = opt->value; 2195 } 2196 2197 if (target == NULL && lun == NULL) 2198 return (0); 2199 2200 if (target == NULL || lun == NULL) { 2201 CFISCSI_WARN("lun added with cfiscsi_target, but without " 2202 "cfiscsi_lun, or the other way around; ignoring"); 2203 return (0); 2204 } 2205 2206 ct = cfiscsi_target_find_or_create(softc, target, target_alias); 2207 if (ct == NULL) { 2208 CFISCSI_WARN("failed to create target \"%s\"", target); 2209 return (0); 2210 } 2211 2212 tmp = strtoul(lun, NULL, 10); 2213 cfiscsi_target_set_lun(ct, tmp, lun_id); 2214 return (0); 2215} 2216 2217static int 2218cfiscsi_lun_disable(void *arg, struct ctl_id target_id, int lun_id) 2219{ 2220 struct cfiscsi_softc *softc; 2221 struct cfiscsi_target *ct; 2222 int i; 2223 2224 softc = (struct cfiscsi_softc *)arg; 2225 2226 mtx_lock(&softc->lock); 2227 TAILQ_FOREACH(ct, &softc->targets, ct_next) { 2228 for (i = 0; i < CTL_MAX_LUNS; i++) { 2229 if (ct->ct_luns[i] < 0) 2230 continue; 2231 if (ct->ct_luns[i] != lun_id) 2232 continue; 2233 cfiscsi_target_unset_lun(ct, i); 2234 break; 2235 } 2236 } 2237 mtx_unlock(&softc->lock); 2238 return (0); 2239} 2240 2241static void 2242cfiscsi_datamove(union ctl_io *io) 2243{ 2244 struct cfiscsi_session *cs; 2245 struct icl_pdu *request, *response; 2246 const struct iscsi_bhs_scsi_command *bhssc; 2247 struct iscsi_bhs_data_in *bhsdi; 2248 struct iscsi_bhs_r2t *bhsr2t; 2249 struct cfiscsi_data_wait *cdw; 2250 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 2251 size_t copy_len, len, off; 2252 const char *addr; 2253 int ctl_sg_count, error, i; 2254 uint32_t target_transfer_tag; 2255 bool done; 2256 2257 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 2258 cs = PDU_SESSION(request); 2259 2260 bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs; 2261 KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) == 2262 ISCSI_BHS_OPCODE_SCSI_COMMAND, 2263 ("bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_COMMAND")); 2264 2265 if (io->scsiio.kern_sg_entries > 0) { 2266 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 2267 ctl_sg_count = io->scsiio.kern_sg_entries; 2268 } else { 2269 ctl_sglist = &ctl_sg_entry; 2270 ctl_sglist->addr = io->scsiio.kern_data_ptr; 2271 ctl_sglist->len = io->scsiio.kern_data_len; 2272 ctl_sg_count = 1; 2273 } 2274 2275 /* 2276 * We need to record it so that we can properly report 2277 * underflow/underflow. 2278 */ 2279 PDU_TOTAL_TRANSFER_LEN(request) = io->scsiio.kern_total_len; 2280 2281 if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) { 2282#if 0 2283 if (ctl_sg_count > 1) 2284 CFISCSI_SESSION_DEBUG(cs, "ctl_sg_count = %d", ctl_sg_count); 2285#endif 2286 2287 /* 2288 * This is the offset within the current SCSI command; 2289 * i.e. for the first call of datamove(), it will be 0, 2290 * and for subsequent ones it will be the sum of lengths 2291 * of previous ones. 2292 */ 2293 off = htonl(io->scsiio.kern_rel_offset); 2294 if (off > 1) 2295 CFISCSI_SESSION_DEBUG(cs, "off = %zd", off); 2296 2297 i = 0; 2298 addr = NULL; 2299 len = 0; 2300 response = NULL; 2301 bhsdi = NULL; 2302 for (;;) { 2303 KASSERT(i < ctl_sg_count, ("i >= ctl_sg_count")); 2304 if (response == NULL) { 2305 response = 2306 cfiscsi_pdu_new_response(request, M_NOWAIT); 2307 if (response == NULL) { 2308 CFISCSI_SESSION_WARN(cs, "failed to " 2309 "allocate memory; dropping connection"); 2310 icl_pdu_free(request); 2311 cfiscsi_session_terminate(cs); 2312 return; 2313 } 2314 bhsdi = (struct iscsi_bhs_data_in *) 2315 response->ip_bhs; 2316 bhsdi->bhsdi_opcode = 2317 ISCSI_BHS_OPCODE_SCSI_DATA_IN; 2318 bhsdi->bhsdi_initiator_task_tag = 2319 bhssc->bhssc_initiator_task_tag; 2320 bhsdi->bhsdi_datasn = 2321 htonl(PDU_EXPDATASN(request)); 2322 PDU_EXPDATASN(request)++; 2323 bhsdi->bhsdi_buffer_offset = htonl(off); 2324 } 2325 2326 if (len == 0) { 2327 addr = ctl_sglist[i].addr; 2328 len = ctl_sglist[i].len; 2329 KASSERT(len > 0, ("len <= 0")); 2330 } 2331 2332 copy_len = len; 2333 if (response->ip_data_len + copy_len > 2334 cs->cs_max_data_segment_length) 2335 copy_len = cs->cs_max_data_segment_length - 2336 response->ip_data_len; 2337 KASSERT(copy_len <= len, ("copy_len > len")); 2338 error = icl_pdu_append_data(response, addr, copy_len, M_NOWAIT); 2339 if (error != 0) { 2340 CFISCSI_SESSION_WARN(cs, "failed to " 2341 "allocate memory; dropping connection"); 2342 icl_pdu_free(request); 2343 icl_pdu_free(response); 2344 cfiscsi_session_terminate(cs); 2345 return; 2346 } 2347 addr += copy_len; 2348 len -= copy_len; 2349 off += copy_len; 2350 io->scsiio.ext_data_filled += copy_len; 2351 2352 if (len == 0) { 2353 /* 2354 * End of scatter-gather segment; 2355 * proceed to the next one... 2356 */ 2357 if (i == ctl_sg_count - 1) { 2358 /* 2359 * ... unless this was the last one. 2360 */ 2361 break; 2362 } 2363 i++; 2364 } 2365 2366 if (response->ip_data_len == 2367 cs->cs_max_data_segment_length) { 2368 /* 2369 * Can't stuff more data into the current PDU; 2370 * queue it. Note that's not enough to check 2371 * for kern_data_resid == 0 instead; there 2372 * may be several Data-In PDUs for the final 2373 * call to cfiscsi_datamove(), and we want 2374 * to set the F flag only on the last of them. 2375 */ 2376 if (off == io->scsiio.kern_total_len) 2377 bhsdi->bhsdi_flags |= BHSDI_FLAGS_F; 2378 KASSERT(response->ip_data_len > 0, 2379 ("sending empty Data-In")); 2380 cfiscsi_pdu_queue(response); 2381 response = NULL; 2382 bhsdi = NULL; 2383 } 2384 } 2385 KASSERT(i == ctl_sg_count - 1, ("missed SG segment")); 2386 KASSERT(len == 0, ("missed data from SG segment")); 2387 if (response != NULL) { 2388 if (off == io->scsiio.kern_total_len) { 2389 bhsdi->bhsdi_flags |= BHSDI_FLAGS_F; 2390 } else { 2391 CFISCSI_SESSION_DEBUG(cs, "not setting the F flag; " 2392 "have %zd, need %zd", off, 2393 (size_t)io->scsiio.kern_total_len); 2394 } 2395 KASSERT(response->ip_data_len > 0, 2396 ("sending empty Data-In")); 2397 cfiscsi_pdu_queue(response); 2398 } 2399 2400 io->scsiio.be_move_done(io); 2401 } else { 2402 CFISCSI_SESSION_LOCK(cs); 2403 target_transfer_tag = cs->cs_target_transfer_tag; 2404 cs->cs_target_transfer_tag++; 2405 CFISCSI_SESSION_UNLOCK(cs); 2406 2407#if 0 2408 CFISCSI_SESSION_DEBUG(cs, "expecting Data-Out with initiator " 2409 "task tag 0x%x, target transfer tag 0x%x", 2410 bhssc->bhssc_initiator_task_tag, target_transfer_tag); 2411#endif 2412 cdw = uma_zalloc(cfiscsi_data_wait_zone, M_NOWAIT | M_ZERO); 2413 if (cdw == NULL) { 2414 CFISCSI_SESSION_WARN(cs, "failed to " 2415 "allocate memory; dropping connection"); 2416 icl_pdu_free(request); 2417 cfiscsi_session_terminate(cs); 2418 } 2419 cdw->cdw_ctl_io = io; 2420 cdw->cdw_target_transfer_tag = htonl(target_transfer_tag); 2421 cdw->cdw_initiator_task_tag = bhssc->bhssc_initiator_task_tag; 2422 2423 if (cs->cs_immediate_data && 2424 icl_pdu_data_segment_length(request) > 0) { 2425 done = cfiscsi_handle_data_segment(request, cdw); 2426 if (done) { 2427 uma_zfree(cfiscsi_data_wait_zone, cdw); 2428 io->scsiio.be_move_done(io); 2429 return; 2430 } 2431 2432#if 0 2433 if (io->scsiio.ext_data_filled != 0) 2434 CFISCSI_SESSION_DEBUG(cs, "got %zd bytes of immediate data, need %zd", 2435 io->scsiio.ext_data_filled, io->scsiio.kern_data_len); 2436#endif 2437 } 2438 2439 CFISCSI_SESSION_LOCK(cs); 2440 TAILQ_INSERT_TAIL(&cs->cs_waiting_for_data_out, cdw, cdw_next); 2441 CFISCSI_SESSION_UNLOCK(cs); 2442 2443 /* 2444 * XXX: We should limit the number of outstanding R2T PDUs 2445 * per task to MaxOutstandingR2T. 2446 */ 2447 response = cfiscsi_pdu_new_response(request, M_NOWAIT); 2448 if (response == NULL) { 2449 CFISCSI_SESSION_WARN(cs, "failed to " 2450 "allocate memory; dropping connection"); 2451 icl_pdu_free(request); 2452 cfiscsi_session_terminate(cs); 2453 } 2454 bhsr2t = (struct iscsi_bhs_r2t *)response->ip_bhs; 2455 bhsr2t->bhsr2t_opcode = ISCSI_BHS_OPCODE_R2T; 2456 bhsr2t->bhsr2t_flags = 0x80; 2457 bhsr2t->bhsr2t_lun = bhssc->bhssc_lun; 2458 bhsr2t->bhsr2t_initiator_task_tag = 2459 bhssc->bhssc_initiator_task_tag; 2460 bhsr2t->bhsr2t_target_transfer_tag = 2461 htonl(target_transfer_tag); 2462 /* 2463 * XXX: Here we assume that cfiscsi_datamove() won't ever 2464 * be running concurrently on several CPUs for a given 2465 * command. 2466 */ 2467 bhsr2t->bhsr2t_r2tsn = htonl(PDU_R2TSN(request)); 2468 PDU_R2TSN(request)++; 2469 /* 2470 * This is the offset within the current SCSI command; 2471 * i.e. for the first call of datamove(), it will be 0, 2472 * and for subsequent ones it will be the sum of lengths 2473 * of previous ones. 2474 * 2475 * The ext_data_filled is to account for unsolicited 2476 * (immediate) data that might have already arrived. 2477 */ 2478 bhsr2t->bhsr2t_buffer_offset = 2479 htonl(io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled); 2480 /* 2481 * This is the total length (sum of S/G lengths) this call 2482 * to cfiscsi_datamove() is supposed to handle. 2483 * 2484 * XXX: Limit it to MaxBurstLength. 2485 */ 2486 bhsr2t->bhsr2t_desired_data_transfer_length = 2487 htonl(io->scsiio.kern_data_len - io->scsiio.ext_data_filled); 2488 cfiscsi_pdu_queue(response); 2489 } 2490} 2491 2492static void 2493cfiscsi_scsi_command_done(union ctl_io *io) 2494{ 2495 struct icl_pdu *request, *response; 2496 struct iscsi_bhs_scsi_command *bhssc; 2497 struct iscsi_bhs_scsi_response *bhssr; 2498#ifdef DIAGNOSTIC 2499 struct cfiscsi_data_wait *cdw; 2500#endif 2501 struct cfiscsi_session *cs; 2502 uint16_t sense_length; 2503 2504 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 2505 cs = PDU_SESSION(request); 2506 bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs; 2507 KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) == 2508 ISCSI_BHS_OPCODE_SCSI_COMMAND, 2509 ("replying to wrong opcode 0x%x", bhssc->bhssc_opcode)); 2510 2511 //CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x", 2512 // bhssc->bhssc_initiator_task_tag); 2513 2514#ifdef DIAGNOSTIC 2515 CFISCSI_SESSION_LOCK(cs); 2516 TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next) 2517 KASSERT(bhssc->bhssc_initiator_task_tag != 2518 cdw->cdw_initiator_task_tag, ("dangling cdw")); 2519 CFISCSI_SESSION_UNLOCK(cs); 2520#endif 2521 2522 response = cfiscsi_pdu_new_response(request, M_WAITOK); 2523 bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs; 2524 bhssr->bhssr_opcode = ISCSI_BHS_OPCODE_SCSI_RESPONSE; 2525 bhssr->bhssr_flags = 0x80; 2526 /* 2527 * XXX: We don't deal with bidirectional under/overflows; 2528 * does anything actually support those? 2529 */ 2530 if (PDU_TOTAL_TRANSFER_LEN(request) < 2531 ntohl(bhssc->bhssc_expected_data_transfer_length)) { 2532 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_UNDERFLOW; 2533 bhssr->bhssr_residual_count = 2534 htonl(ntohl(bhssc->bhssc_expected_data_transfer_length) - 2535 PDU_TOTAL_TRANSFER_LEN(request)); 2536 //CFISCSI_SESSION_DEBUG(cs, "underflow; residual count %d", 2537 // ntohl(bhssr->bhssr_residual_count)); 2538 } else if (PDU_TOTAL_TRANSFER_LEN(request) > 2539 ntohl(bhssc->bhssc_expected_data_transfer_length)) { 2540 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_OVERFLOW; 2541 bhssr->bhssr_residual_count = 2542 htonl(PDU_TOTAL_TRANSFER_LEN(request) - 2543 ntohl(bhssc->bhssc_expected_data_transfer_length)); 2544 //CFISCSI_SESSION_DEBUG(cs, "overflow; residual count %d", 2545 // ntohl(bhssr->bhssr_residual_count)); 2546 } 2547 bhssr->bhssr_response = BHSSR_RESPONSE_COMMAND_COMPLETED; 2548 bhssr->bhssr_status = io->scsiio.scsi_status; 2549 bhssr->bhssr_initiator_task_tag = bhssc->bhssc_initiator_task_tag; 2550 bhssr->bhssr_expdatasn = htonl(PDU_EXPDATASN(request)); 2551 2552 if (io->scsiio.sense_len > 0) { 2553#if 0 2554 CFISCSI_SESSION_DEBUG(cs, "returning %d bytes of sense data", 2555 io->scsiio.sense_len); 2556#endif 2557 sense_length = htons(io->scsiio.sense_len); 2558 icl_pdu_append_data(response, 2559 &sense_length, sizeof(sense_length), M_WAITOK); 2560 icl_pdu_append_data(response, 2561 &io->scsiio.sense_data, io->scsiio.sense_len, M_WAITOK); 2562 } 2563 2564 ctl_free_io(io); 2565 icl_pdu_free(request); 2566 cfiscsi_pdu_queue(response); 2567} 2568 2569static void 2570cfiscsi_task_management_done(union ctl_io *io) 2571{ 2572 struct icl_pdu *request, *response; 2573 struct iscsi_bhs_task_management_request *bhstmr; 2574 struct iscsi_bhs_task_management_response *bhstmr2; 2575 struct cfiscsi_data_wait *cdw, *tmpcdw; 2576 struct cfiscsi_session *cs; 2577 2578 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 2579 cs = PDU_SESSION(request); 2580 bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs; 2581 KASSERT((bhstmr->bhstmr_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) == 2582 ISCSI_BHS_OPCODE_TASK_REQUEST, 2583 ("replying to wrong opcode 0x%x", bhstmr->bhstmr_opcode)); 2584 2585#if 0 2586 CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x; referenced task tag 0x%x", 2587 bhstmr->bhstmr_initiator_task_tag, 2588 bhstmr->bhstmr_referenced_task_tag); 2589#endif 2590 2591 if ((bhstmr->bhstmr_function & ~0x80) == 2592 BHSTMR_FUNCTION_ABORT_TASK) { 2593 /* 2594 * Make sure we no longer wait for Data-Out for this command. 2595 */ 2596 CFISCSI_SESSION_LOCK(cs); 2597 TAILQ_FOREACH_SAFE(cdw, 2598 &cs->cs_waiting_for_data_out, cdw_next, tmpcdw) { 2599 if (bhstmr->bhstmr_referenced_task_tag != 2600 cdw->cdw_initiator_task_tag) 2601 continue; 2602 2603#if 0 2604 CFISCSI_SESSION_DEBUG(cs, "removing csw for initiator task " 2605 "tag 0x%x", bhstmr->bhstmr_initiator_task_tag); 2606#endif 2607 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, 2608 cdw, cdw_next); 2609 cdw->cdw_ctl_io->scsiio.be_move_done(cdw->cdw_ctl_io); 2610 uma_zfree(cfiscsi_data_wait_zone, cdw); 2611 } 2612 CFISCSI_SESSION_UNLOCK(cs); 2613 } 2614 2615 response = cfiscsi_pdu_new_response(request, M_WAITOK); 2616 bhstmr2 = (struct iscsi_bhs_task_management_response *) 2617 response->ip_bhs; 2618 bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE; 2619 bhstmr2->bhstmr_flags = 0x80; 2620 if (io->io_hdr.status == CTL_SUCCESS) { 2621 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_COMPLETE; 2622 } else { 2623 /* 2624 * XXX: How to figure out what exactly went wrong? iSCSI spec 2625 * expects us to provide detailed error, e.g. "Task does 2626 * not exist" or "LUN does not exist". 2627 */ 2628 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED"); 2629 bhstmr2->bhstmr_response = 2630 BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED; 2631 } 2632 bhstmr2->bhstmr_initiator_task_tag = bhstmr->bhstmr_initiator_task_tag; 2633 2634 ctl_free_io(io); 2635 icl_pdu_free(request); 2636 cfiscsi_pdu_queue(response); 2637} 2638 2639static void 2640cfiscsi_done(union ctl_io *io) 2641{ 2642 struct icl_pdu *request; 2643 struct cfiscsi_session *cs; 2644 2645 KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE), 2646 ("invalid CTL status %#x", io->io_hdr.status)); 2647 2648 request = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 2649 if (request == NULL) { 2650 /* 2651 * Implicit task termination has just completed; nothing to do. 2652 */ 2653 return; 2654 } 2655 2656 cs = PDU_SESSION(request); 2657 refcount_release(&cs->cs_outstanding_ctl_pdus); 2658 2659 switch (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) { 2660 case ISCSI_BHS_OPCODE_SCSI_COMMAND: 2661 cfiscsi_scsi_command_done(io); 2662 break; 2663 case ISCSI_BHS_OPCODE_TASK_REQUEST: 2664 cfiscsi_task_management_done(io); 2665 break; 2666 default: 2667 panic("cfiscsi_done called with wrong opcode 0x%x", 2668 request->ip_bhs->bhs_opcode); 2669 } 2670} 2671