📄 iscsi.c
字号:
if (cmnd == req) continue; if (all) __cmnd_abort(cmnd); else if (translate_lun(cmnd_hdr(cmnd)->lun) == lun) __cmnd_abort(cmnd); } } } return 0;}static void task_set_abort(struct iscsi_cmnd *req){ struct iscsi_session *session = req->conn->session; struct iscsi_conn *conn; struct iscsi_cmnd *cmnd, *tmp; list_for_each_entry(conn, &session->conn_list, list) { list_for_each_entry_safe(cmnd, tmp, &conn->pdu_list, conn_list) { if (cmnd != req) __cmnd_abort(cmnd); } }}static void execute_task_management(struct iscsi_cmnd *req){ struct iscsi_conn *conn = req->conn; struct iscsi_target *target = conn->session->target; struct iscsi_cmnd *rsp; struct iscsi_task_mgt_hdr *req_hdr = (struct iscsi_task_mgt_hdr *)&req->pdu.bhs; struct iscsi_task_rsp_hdr *rsp_hdr; u32 lun; int err, function = req_hdr->function & ISCSI_FUNCTION_MASK; rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); rsp_hdr = (struct iscsi_task_rsp_hdr *)&rsp->pdu.bhs; rsp_hdr->opcode = ISCSI_OP_SCSI_TASK_MGT_RSP; rsp_hdr->flags = ISCSI_FLG_FINAL; rsp_hdr->itt = req_hdr->itt; rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_COMPLETE; eprintk("%x %d %x\n", cmnd_itt(req), function, req_hdr->rtt); switch (function) { case ISCSI_FUNCTION_ABORT_TASK: case ISCSI_FUNCTION_ABORT_TASK_SET: case ISCSI_FUNCTION_CLEAR_ACA: case ISCSI_FUNCTION_CLEAR_TASK_SET: case ISCSI_FUNCTION_LOGICAL_UNIT_RESET: lun = translate_lun(req_hdr->lun); if (!volume_lookup(target, lun)) { rsp_hdr->response = ISCSI_RESPONSE_UNKNOWN_LUN; goto out; } } switch (function) { case ISCSI_FUNCTION_ABORT_TASK: if ((err = cmnd_abort(conn->session, req_hdr->rtt)) < 0) rsp_hdr->response = -err; break; case ISCSI_FUNCTION_ABORT_TASK_SET: task_set_abort(req); break; case ISCSI_FUNCTION_CLEAR_ACA: rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_UNSUPPORTED; break; case ISCSI_FUNCTION_CLEAR_TASK_SET: rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_UNSUPPORTED; break; case ISCSI_FUNCTION_LOGICAL_UNIT_RESET: target_reset(req, translate_lun(req_hdr->lun), 0); break; case ISCSI_FUNCTION_TARGET_WARM_RESET: case ISCSI_FUNCTION_TARGET_COLD_RESET: target_reset(req, 0, 1); if (function == ISCSI_FUNCTION_TARGET_COLD_RESET) set_cmnd_close(rsp); break; case ISCSI_FUNCTION_TASK_REASSIGN: rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_UNSUPPORTED; break; default: rsp_hdr->response = ISCSI_RESPONSE_FUNCTION_REJECTED; break; }out: iscsi_cmnd_init_write(rsp);}static void noop_out_exec(struct iscsi_cmnd *req){ struct iscsi_cmnd *rsp; struct iscsi_nop_in_hdr *rsp_hdr; if (cmnd_itt(req) != cpu_to_be32(ISCSI_RESERVED_TAG)) { rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); rsp_hdr = (struct iscsi_nop_in_hdr *)&rsp->pdu.bhs; rsp_hdr->opcode = ISCSI_OP_NOOP_IN; rsp_hdr->flags = ISCSI_FLG_FINAL; rsp_hdr->itt = req->pdu.bhs.itt; rsp_hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); if (req->pdu.datasize) assert(req->tio); else assert(!req->tio); if (req->tio) { tio_get(req->tio); rsp->tio = req->tio; } assert(get_pgcnt(req->pdu.datasize, 0) < ISCSI_CONN_IOV_MAX); rsp->pdu.datasize = req->pdu.datasize; iscsi_cmnd_init_write(rsp); } else iscsi_cmnd_remove(req);}static void logout_exec(struct iscsi_cmnd *req){ struct iscsi_logout_req_hdr *req_hdr; struct iscsi_cmnd *rsp; struct iscsi_logout_rsp_hdr *rsp_hdr; req_hdr = (struct iscsi_logout_req_hdr *)&req->pdu.bhs; rsp = iscsi_cmnd_create_rsp_cmnd(req, 1); rsp_hdr = (struct iscsi_logout_rsp_hdr *)&rsp->pdu.bhs; rsp_hdr->opcode = ISCSI_OP_LOGOUT_RSP; rsp_hdr->flags = ISCSI_FLG_FINAL; rsp_hdr->itt = req_hdr->itt; set_cmnd_close(rsp); iscsi_cmnd_init_write(rsp);}static void iscsi_cmnd_exec(struct iscsi_cmnd *cmnd){ dprintk(D_GENERIC, "%p,%x,%u\n", cmnd, cmnd_opcode(cmnd), cmnd->pdu.bhs.sn); switch (cmnd_opcode(cmnd)) { case ISCSI_OP_NOOP_OUT: noop_out_exec(cmnd); break; case ISCSI_OP_SCSI_CMD: scsi_cmnd_exec(cmnd); break; case ISCSI_OP_SCSI_TASK_MGT_MSG: execute_task_management(cmnd); break; case ISCSI_OP_LOGOUT_CMD: logout_exec(cmnd); break; case ISCSI_OP_SCSI_REJECT: iscsi_cmnd_init_write(get_rsp_cmnd(cmnd)); break; case ISCSI_OP_TEXT_CMD: case ISCSI_OP_SNACK_CMD: break; default: eprintk("unexpected cmnd op %x\n", cmnd_opcode(cmnd)); break; }}static void __cmnd_send_pdu(struct iscsi_conn *conn, struct tio *tio, u32 offset, u32 size){ dprintk(D_GENERIC, "%p %u,%u\n", tio, offset, size); offset += tio->offset; assert(offset <= tio->offset + tio->size); assert(offset + size <= tio->offset + tio->size); conn->write_tcmnd = tio; conn->write_offset = offset; conn->write_size += size;}static void cmnd_send_pdu(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd){ u32 size; struct tio *tio; if (!cmnd->pdu.datasize) return; size = (cmnd->pdu.datasize + 3) & -4; tio = cmnd->tio; assert(tio); assert(tio->size == size); __cmnd_send_pdu(conn, tio, 0, size);}static void set_cork(struct socket *sock, int on){ int opt = on; mm_segment_t oldfs; oldfs = get_fs(); set_fs(get_ds()); sock->ops->setsockopt(sock, SOL_TCP, TCP_CORK, (void *)&opt, sizeof(opt)); set_fs(oldfs);}void cmnd_release(struct iscsi_cmnd *cmnd, int force){ struct iscsi_cmnd *req, *rsp; int is_last = 0; if (!cmnd) return;/* eprintk("%x %lx %d\n", cmnd_opcode(cmnd), cmnd->flags, force); */ req = cmnd->req; is_last = cmnd_final(cmnd); if (force) { while (!list_empty(&cmnd->pdu_list)) { rsp = list_entry(cmnd->pdu_list.next, struct iscsi_cmnd, pdu_list); list_del_init(&rsp->list); list_del(&rsp->pdu_list); iscsi_cmnd_remove(rsp); } list_del_init(&cmnd->list); } else if (cmnd_queued(cmnd)) iscsi_scsi_dequeuecmnd(cmnd); if (cmnd_hashed(cmnd)) cmnd_remove_hash(cmnd); if (cmnd_lunit(cmnd)) { assert(cmnd->lun); volume_put(cmnd->lun); } list_del_init(&cmnd->pdu_list); iscsi_cmnd_remove(cmnd); if (is_last) { assert(!force); assert(req); cmnd_release(req, 0); } return;}void cmnd_tx_start(struct iscsi_cmnd *cmnd){ struct iscsi_conn *conn = cmnd->conn; struct iovec *iop; dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd)); assert(cmnd); iscsi_cmnd_set_length(&cmnd->pdu); set_cork(conn->sock, 1); conn->write_iop = iop = conn->write_iov; iop->iov_base = &cmnd->pdu.bhs; iop->iov_len = sizeof(cmnd->pdu.bhs); iop++; conn->write_size = sizeof(cmnd->pdu.bhs); switch (cmnd_opcode(cmnd)) { case ISCSI_OP_NOOP_IN: cmnd_set_sn(cmnd, 1); cmnd_send_pdu(conn, cmnd); break; case ISCSI_OP_SCSI_RSP: cmnd_set_sn(cmnd, 1); cmnd_send_pdu(conn, cmnd); break; case ISCSI_OP_SCSI_TASK_MGT_RSP: cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_TEXT_RSP: cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_SCSI_DATA_IN: { struct iscsi_data_in_hdr *rsp = (struct iscsi_data_in_hdr *)&cmnd->pdu.bhs; u32 offset; cmnd_set_sn(cmnd, (rsp->flags & ISCSI_FLG_FINAL) ? 1 : 0); offset = rsp->buffer_offset; rsp->buffer_offset = cpu_to_be32(offset); __cmnd_send_pdu(conn, cmnd->tio, offset, cmnd->pdu.datasize); break; } case ISCSI_OP_LOGOUT_RSP: cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_R2T: cmnd_set_sn(cmnd, 0); cmnd->pdu.bhs.sn = cpu_to_be32(conn->stat_sn); break; case ISCSI_OP_ASYNC_MSG: cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_REJECT: cmnd_set_sn(cmnd, 1); cmnd_send_pdu(conn, cmnd); break; default: eprintk("unexpected cmnd op %x\n", cmnd_opcode(cmnd)); break; } iop->iov_len = 0; // move this? conn->write_size = (conn->write_size + 3) & -4; iscsi_dump_pdu(&cmnd->pdu);}void cmnd_tx_end(struct iscsi_cmnd *cmnd){ struct iscsi_conn *conn = cmnd->conn; dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd)); switch (cmnd_opcode(cmnd)) { case ISCSI_OP_NOOP_IN: case ISCSI_OP_SCSI_RSP: case ISCSI_OP_SCSI_TASK_MGT_RSP: case ISCSI_OP_TEXT_RSP: case ISCSI_OP_R2T: case ISCSI_OP_ASYNC_MSG: case ISCSI_OP_REJECT: case ISCSI_OP_SCSI_DATA_IN: case ISCSI_OP_LOGOUT_RSP: break; default: eprintk("unexpected cmnd op %x\n", cmnd_opcode(cmnd)); assert(0); break; } if (cmnd_close(cmnd)) conn_close(conn); list_del_init(&cmnd->list); set_cork(cmnd->conn->sock, 0);}/** * Push the command for execution. * This functions reorders the commands. * Called from the read thread. * * iscsi_session_push_cmnd - * @cmnd: ptr to command */static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd){ struct iscsi_session *session = cmnd->conn->session; struct list_head *entry; u32 cmd_sn; dprintk(D_GENERIC, "%p:%x %u,%u\n", cmnd, cmnd_opcode(cmnd), cmnd->pdu.bhs.sn, session->exp_cmd_sn); if (cmnd->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE) { iscsi_cmnd_exec(cmnd); return; } cmd_sn = cmnd->pdu.bhs.sn; if (cmd_sn == session->exp_cmd_sn) { while (1) { session->exp_cmd_sn = ++cmd_sn; iscsi_cmnd_exec(cmnd); if (list_empty(&session->pending_list)) break; cmnd = list_entry(session->pending_list.next, struct iscsi_cmnd, list); if (cmnd->pdu.bhs.sn != cmd_sn) break;/* eprintk("find out-of-order %x %u %u\n", *//* cmnd_itt(cmnd), cmd_sn, cmnd->pdu.bhs.sn); */ list_del_init(&cmnd->list); clear_cmnd_pending(cmnd); } } else {/* eprintk("out-of-order %x %u %u\n", *//* cmnd_itt(cmnd), cmd_sn, session->exp_cmd_sn); */ set_cmnd_pending(cmnd); if (before(cmd_sn, session->exp_cmd_sn)) /* close the conn */ eprintk("unexpected cmd_sn (%u,%u)\n", cmd_sn, session->exp_cmd_sn); if (after(cmd_sn, session->exp_cmd_sn + session->max_queued_cmnds)) eprintk("too large cmd_sn (%u,%u)\n", cmd_sn, session->exp_cmd_sn); list_for_each(entry, &session->pending_list) { struct iscsi_cmnd *tmp = list_entry(entry, struct iscsi_cmnd, list); if (before(cmd_sn, tmp->pdu.bhs.sn)) break; } assert(list_empty(&cmnd->list)); list_add_tail(&cmnd->list, entry); }}static int check_segment_length(struct iscsi_cmnd *cmnd){ struct iscsi_conn *conn = cmnd->conn; struct iscsi_sess_param *param = &conn->session->param; if (cmnd->pdu.datasize > param->max_recv_data_length) { eprintk("too lond data %x %u %u\n", cmnd_itt(cmnd), cmnd->pdu.datasize, param->max_recv_data_length); if (get_pgcnt(cmnd->pdu.datasize, 0) > ISCSI_CONN_IOV_MAX) { conn_close(conn); return -EINVAL; } } return 0;}void cmnd_rx_start(struct iscsi_cmnd *cmnd){ struct iscsi_conn *conn = cmnd->conn; int err = 0; iscsi_dump_pdu(&cmnd->pdu); if (check_segment_length(cmnd) < 0) return; switch (cmnd_opcode(cmnd)) { case ISCSI_OP_NOOP_OUT: err = noop_out_start(conn, cmnd); break; case ISCSI_OP_SCSI_CMD: if (!(err = cmnd_insert_hash(cmnd))) scsi_cmnd_start(conn, cmnd); break; case ISCSI_OP_SCSI_TASK_MGT_MSG: err = cmnd_insert_hash(cmnd); break; case ISCSI_OP_SCSI_DATA_OUT: data_out_start(conn, cmnd); break; case ISCSI_OP_LOGOUT_CMD: err = cmnd_insert_hash(cmnd); break; case ISCSI_OP_TEXT_CMD: case ISCSI_OP_SNACK_CMD: err = -ISCSI_REASON_UNSUPPORTED_COMMAND; break; default: err = -ISCSI_REASON_UNSUPPORTED_COMMAND; break; } if (err < 0) { eprintk("%x %x %d\n", cmnd_opcode(cmnd), cmnd_itt(cmnd), err); iscsi_cmnd_reject(cmnd, -err); }}void cmnd_rx_end(struct iscsi_cmnd *cmnd){ struct iscsi_conn *conn = cmnd->conn; dprintk(D_GENERIC, "%p:%x\n", cmnd, cmnd_opcode(cmnd)); switch (cmnd_opcode(cmnd)) { case ISCSI_OP_SCSI_REJECT: case ISCSI_OP_NOOP_OUT: case ISCSI_OP_SCSI_CMD: case ISCSI_OP_SCSI_TASK_MGT_MSG: case ISCSI_OP_TEXT_CMD: case ISCSI_OP_LOGOUT_CMD: iscsi_session_push_cmnd(cmnd); break; case ISCSI_OP_SCSI_DATA_OUT: data_out_end(conn, cmnd); break; case ISCSI_OP_SNACK_CMD: break; case ISCSI_OP_PDU_REJECT: iscsi_cmnd_init_write(get_rsp_cmnd(cmnd)); break; case ISCSI_OP_DATA_REJECT: cmnd_release(cmnd, 0); break; default: eprintk("unexpected cmnd op %x\n", cmnd_opcode(cmnd)); BUG(); break; }}static void iscsi_exit(void){ unregister_chrdev(ctr_major, ctr_name); iet_procfs_exit(); event_exit(); tio_exit(); iotype_exit(); if (iscsi_cmnd_cache) kmem_cache_destroy(iscsi_cmnd_cache);}static int iscsi_init(void){ int err = -ENOMEM; printk("iSCSI Enterprise Target Software - version %s\n", IET_VERSION_STRING); if ((ctr_major = register_chrdev(0, ctr_name, &ctr_fops)) < 0) { eprintk("failed to register the control device %d\n", ctr_major); return ctr_major; } if ((err = iet_procfs_init()) < 0) goto err; if ((err = event_init()) < 0) goto err; iscsi_cmnd_cache = kmem_cache_create("iscsi_cmnd", sizeof(struct iscsi_cmnd), 0, 0, NULL, NULL); if (!iscsi_cmnd_cache) goto err; if ((err = tio_init()) < 0) goto err; if ((err = iotype_init()) < 0) goto err; return 0;err: iscsi_exit(); return err;}module_param(debug_enable_flags, ulong, S_IRUGO);module_init(iscsi_init);module_exit(iscsi_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -