···5959 char *text_buf,6060 int text_length)6161{6262- int length, tx_sent;6262+ int length, tx_sent, iov_cnt = 1;6363 struct kvec iov[2];64646565 length = (ISCSI_HDR_LEN + text_length);···6767 memset(&iov[0], 0, 2 * sizeof(struct kvec));6868 iov[0].iov_len = ISCSI_HDR_LEN;6969 iov[0].iov_base = pdu_buf;7070- iov[1].iov_len = text_length;7171- iov[1].iov_base = text_buf;7070+7171+ if (text_buf && text_length) {7272+ iov[1].iov_len = text_length;7373+ iov[1].iov_base = text_buf;7474+ iov_cnt++;7575+ }72767377 /*7478 * Initial Marker-less Interval.···8177 */8278 conn->if_marker += length;83798484- tx_sent = tx_data(conn, &iov[0], 2, length);8080+ tx_sent = tx_data(conn, &iov[0], iov_cnt, length);8581 if (tx_sent != length) {8682 pr_err("tx_data returned %d, expecting %d.\n",8783 tx_sent, length);···433429 TYPERANGE_MARKINT, USE_INITIAL_ONLY);434430 if (!param)435431 goto out;432432+ /*433433+ * Extra parameters for ISER from RFC-5046434434+ */435435+ param = iscsi_set_default_param(pl, RDMAEXTENTIONS, INITIAL_RDMAEXTENTIONS,436436+ PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,437437+ TYPERANGE_BOOL_AND, USE_LEADING_ONLY);438438+ if (!param)439439+ goto out;440440+441441+ param = iscsi_set_default_param(pl, INITIATORRECVDATASEGMENTLENGTH,442442+ INITIAL_INITIATORRECVDATASEGMENTLENGTH,443443+ PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,444444+ TYPERANGE_512_TO_16777215, USE_ALL);445445+ if (!param)446446+ goto out;447447+448448+ param = iscsi_set_default_param(pl, TARGETRECVDATASEGMENTLENGTH,449449+ INITIAL_TARGETRECVDATASEGMENTLENGTH,450450+ PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,451451+ TYPERANGE_512_TO_16777215, USE_ALL);452452+ if (!param)453453+ goto out;436454437455 *param_list_ptr = pl;438456 return 0;···464438}465439466440int iscsi_set_keys_to_negotiate(467467- int sessiontype,468468- struct iscsi_param_list *param_list)441441+ struct iscsi_param_list *param_list,442442+ bool iser)469443{470444 struct iscsi_param *param;445445+446446+ param_list->iser = iser;471447472448 list_for_each_entry(param, ¶m_list->param_list, p_list) {473449 param->state = 0;474450 if (!strcmp(param->name, AUTHMETHOD)) {475451 SET_PSTATE_NEGOTIATE(param);476452 } else if (!strcmp(param->name, HEADERDIGEST)) {477477- SET_PSTATE_NEGOTIATE(param);453453+ if (iser == false)454454+ SET_PSTATE_NEGOTIATE(param);478455 } else if (!strcmp(param->name, DATADIGEST)) {479479- SET_PSTATE_NEGOTIATE(param);456456+ if (iser == false)457457+ SET_PSTATE_NEGOTIATE(param);480458 } else if (!strcmp(param->name, MAXCONNECTIONS)) {481459 SET_PSTATE_NEGOTIATE(param);482460 } else if (!strcmp(param->name, TARGETNAME)) {···499469 } else if (!strcmp(param->name, IMMEDIATEDATA)) {500470 SET_PSTATE_NEGOTIATE(param);501471 } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {502502- SET_PSTATE_NEGOTIATE(param);472472+ if (iser == false)473473+ SET_PSTATE_NEGOTIATE(param);503474 } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {504475 continue;505476 } else if (!strcmp(param->name, MAXBURSTLENGTH)) {···529498 SET_PSTATE_NEGOTIATE(param);530499 } else if (!strcmp(param->name, OFMARKINT)) {531500 SET_PSTATE_NEGOTIATE(param);501501+ } else if (!strcmp(param->name, RDMAEXTENTIONS)) {502502+ if (iser == true)503503+ SET_PSTATE_NEGOTIATE(param);504504+ } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {505505+ if (iser == true)506506+ SET_PSTATE_NEGOTIATE(param);507507+ } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) {508508+ if (iser == true)509509+ SET_PSTATE_NEGOTIATE(param);532510 }533511 }534512···579539 else if (!strcmp(param->name, IFMARKINT))580540 param->state &= ~PSTATE_NEGOTIATE;581541 else if (!strcmp(param->name, OFMARKINT))542542+ param->state &= ~PSTATE_NEGOTIATE;543543+ else if (!strcmp(param->name, RDMAEXTENTIONS))544544+ param->state &= ~PSTATE_NEGOTIATE;545545+ else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH))546546+ param->state &= ~PSTATE_NEGOTIATE;547547+ else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH))582548 param->state &= ~PSTATE_NEGOTIATE;583549 }584550···18011755 * this key is not sent over the wire.18021756 */18031757 if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {17581758+ if (param_list->iser == true)17591759+ continue;17601760+18041761 ops->MaxXmitDataSegmentLength =18051762 simple_strtoul(param->value, &tmpptr, 0);18061763 pr_debug("MaxXmitDataSegmentLength: %s\n",···18491800 simple_strtoul(param->value, &tmpptr, 0);18501801 pr_debug("IFMarkInt: %s\n",18511802 param->value);18031803+ } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {18041804+ ops->InitiatorRecvDataSegmentLength =18051805+ simple_strtoul(param->value, &tmpptr, 0);18061806+ pr_debug("InitiatorRecvDataSegmentLength: %s\n",18071807+ param->value);18081808+ ops->MaxRecvDataSegmentLength =18091809+ ops->InitiatorRecvDataSegmentLength;18101810+ pr_debug("Set MRDSL from InitiatorRecvDataSegmentLength\n");18111811+ } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) {18121812+ ops->TargetRecvDataSegmentLength =18131813+ simple_strtoul(param->value, &tmpptr, 0);18141814+ pr_debug("TargetRecvDataSegmentLength: %s\n",18151815+ param->value);18161816+ ops->MaxXmitDataSegmentLength =18171817+ ops->TargetRecvDataSegmentLength;18181818+ pr_debug("Set MXDSL from TargetRecvDataSegmentLength\n");18521819 }18531820 }18541821 pr_debug("----------------------------------------------------"···19761911 } else if (!strcmp(param->name, SESSIONTYPE)) {19771912 ops->SessionType = !strcmp(param->value, DISCOVERY);19781913 pr_debug("SessionType: %s\n",19141914+ param->value);19151915+ } else if (!strcmp(param->name, RDMAEXTENTIONS)) {19161916+ ops->RDMAExtensions = !strcmp(param->value, YES);19171917+ pr_debug("RDMAExtensions: %s\n",19791918 param->value);19801919 }19811920 }
+15-1
drivers/target/iscsi/iscsi_target_parameters.h
···2727extern void iscsi_dump_sess_ops(struct iscsi_sess_ops *);2828extern void iscsi_print_params(struct iscsi_param_list *);2929extern int iscsi_create_default_params(struct iscsi_param_list **);3030-extern int iscsi_set_keys_to_negotiate(int, struct iscsi_param_list *);3030+extern int iscsi_set_keys_to_negotiate(struct iscsi_param_list *, bool);3131extern int iscsi_set_keys_irrelevant_for_discovery(struct iscsi_param_list *);3232extern int iscsi_copy_param_list(struct iscsi_param_list **,3333 struct iscsi_param_list *, int);···8989#define X_EXTENSIONKEY_CISCO_OLD "X-com.cisco.iscsi.draft"90909191/*9292+ * Parameter names of iSCSI Extentions for RDMA (iSER). See RFC-50469393+ */9494+#define RDMAEXTENTIONS "RDMAExtensions"9595+#define INITIATORRECVDATASEGMENTLENGTH "InitiatorRecvDataSegmentLength"9696+#define TARGETRECVDATASEGMENTLENGTH "TargetRecvDataSegmentLength"9797+9898+/*9299 * For AuthMethod.93100 */94101#define KRB5 "KRB5"···138131#define INITIAL_OFMARKER NO139132#define INITIAL_IFMARKINT "2048~65535"140133#define INITIAL_OFMARKINT "2048~65535"134134+135135+/*136136+ * Initial values for iSER parameters following RFC-5046 Section 6137137+ */138138+#define INITIAL_RDMAEXTENTIONS NO139139+#define INITIAL_INITIATORRECVDATASEGMENTLENGTH "262144"140140+#define INITIAL_TARGETRECVDATASEGMENTLENGTH "8192"141141142142/*143143 * For [Header,Data]Digests.
+3-1
drivers/target/iscsi/iscsi_target_tmr.c
···2323#include <scsi/iscsi_proto.h>2424#include <target/target_core_base.h>2525#include <target/target_core_fabric.h>2626+#include <target/iscsi/iscsi_transport.h>26272728#include "iscsi_target_core.h"2829#include "iscsi_target_seq_pdu_list.h"···302301 /*303302 * iscsit_build_r2ts_for_cmd() can handle the rest from here.304303 */305305- return iscsit_build_r2ts_for_cmd(cmd, conn, true);304304+ return conn->conn_transport->iscsit_get_dataout(conn, cmd, true);306305}307306308307static int iscsit_task_reassign_complete_read(···472471473472 return 0;474473}474474+EXPORT_SYMBOL(iscsit_tmr_post_handler);475475476476/*477477 * Nothing to do here, but leave it for good measure. :-)
···6666 * TODO: debug and remove the workaround.6767 */6868enum {6969- VHOST_SCSI_FEATURES = VHOST_FEATURES & (~VIRTIO_RING_F_EVENT_IDX)6969+ VHOST_SCSI_FEATURES = (VHOST_FEATURES & (~VIRTIO_RING_F_EVENT_IDX)) |7070+ (1ULL << VIRTIO_SCSI_F_HOTPLUG)7071};71727273#define VHOST_SCSI_MAX_TARGET 2567374#define VHOST_SCSI_MAX_VQ 1287575+#define VHOST_SCSI_MAX_EVENT 12874767577struct vhost_scsi {7678 /* Protected by vhost_scsi->dev.mutex */···84828583 struct vhost_work vs_completion_work; /* cmd completion work item */8684 struct llist_head vs_completion_list; /* cmd completion queue */8585+8686+ struct vhost_work vs_event_work; /* evt injection work item */8787+ struct llist_head vs_event_list; /* evt injection queue */8888+8989+ bool vs_events_missed; /* any missed events, protected by vq->mutex */9090+ int vs_events_nr; /* num of pending events, protected by vq->mutex */8791};88928993/* Local pointer to allocated TCM configfs fabric module */···357349 return 0;358350}359351352352+static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)353353+{354354+ vs->vs_events_nr--;355355+ kfree(evt);356356+}357357+358358+static struct tcm_vhost_evt *tcm_vhost_allocate_evt(struct vhost_scsi *vs,359359+ u32 event, u32 reason)360360+{361361+ struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT];362362+ struct tcm_vhost_evt *evt;363363+364364+ if (vs->vs_events_nr > VHOST_SCSI_MAX_EVENT) {365365+ vs->vs_events_missed = true;366366+ return NULL;367367+ }368368+369369+ evt = kzalloc(sizeof(*evt), GFP_KERNEL);370370+ if (!evt) {371371+ vq_err(vq, "Failed to allocate tcm_vhost_evt\n");372372+ vs->vs_events_missed = true;373373+ return NULL;374374+ }375375+376376+ evt->event.event = event;377377+ evt->event.reason = reason;378378+ vs->vs_events_nr++;379379+380380+ return evt;381381+}382382+360383static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd)361384{362385 struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;···404365 }405366406367 kfree(tv_cmd);368368+}369369+370370+static void tcm_vhost_do_evt_work(struct vhost_scsi *vs,371371+ struct tcm_vhost_evt *evt)372372+{373373+ struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT];374374+ struct virtio_scsi_event *event = &evt->event;375375+ struct virtio_scsi_event __user *eventp;376376+ unsigned out, in;377377+ int head, ret;378378+379379+ if (!vq->private_data) {380380+ vs->vs_events_missed = true;381381+ return;382382+ }383383+384384+again:385385+ vhost_disable_notify(&vs->dev, vq);386386+ head = vhost_get_vq_desc(&vs->dev, vq, vq->iov,387387+ ARRAY_SIZE(vq->iov), &out, &in,388388+ NULL, NULL);389389+ if (head < 0) {390390+ vs->vs_events_missed = true;391391+ return;392392+ }393393+ if (head == vq->num) {394394+ if (vhost_enable_notify(&vs->dev, vq))395395+ goto again;396396+ vs->vs_events_missed = true;397397+ return;398398+ }399399+400400+ if ((vq->iov[out].iov_len != sizeof(struct virtio_scsi_event))) {401401+ vq_err(vq, "Expecting virtio_scsi_event, got %zu bytes\n",402402+ vq->iov[out].iov_len);403403+ vs->vs_events_missed = true;404404+ return;405405+ }406406+407407+ if (vs->vs_events_missed) {408408+ event->event |= VIRTIO_SCSI_T_EVENTS_MISSED;409409+ vs->vs_events_missed = false;410410+ }411411+412412+ eventp = vq->iov[out].iov_base;413413+ ret = __copy_to_user(eventp, event, sizeof(*event));414414+ if (!ret)415415+ vhost_add_used_and_signal(&vs->dev, vq, head, 0);416416+ else417417+ vq_err(vq, "Faulted on tcm_vhost_send_event\n");418418+}419419+420420+static void tcm_vhost_evt_work(struct vhost_work *work)421421+{422422+ struct vhost_scsi *vs = container_of(work, struct vhost_scsi,423423+ vs_event_work);424424+ struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT];425425+ struct tcm_vhost_evt *evt;426426+ struct llist_node *llnode;427427+428428+ mutex_lock(&vq->mutex);429429+ llnode = llist_del_all(&vs->vs_event_list);430430+ while (llnode) {431431+ evt = llist_entry(llnode, struct tcm_vhost_evt, list);432432+ llnode = llist_next(llnode);433433+ tcm_vhost_do_evt_work(vs, evt);434434+ tcm_vhost_free_evt(vs, evt);435435+ }436436+ mutex_unlock(&vq->mutex);407437}408438409439/* Fill in status and signal that we are done processing this command···885777 pr_debug("%s: The handling func for control queue.\n", __func__);886778}887779780780+static void tcm_vhost_send_evt(struct vhost_scsi *vs, struct tcm_vhost_tpg *tpg,781781+ struct se_lun *lun, u32 event, u32 reason)782782+{783783+ struct tcm_vhost_evt *evt;784784+785785+ evt = tcm_vhost_allocate_evt(vs, event, reason);786786+ if (!evt)787787+ return;788788+789789+ if (tpg && lun) {790790+ /* TODO: share lun setup code with virtio-scsi.ko */791791+ /*792792+ * Note: evt->event is zeroed when we allocate it and793793+ * lun[4-7] need to be zero according to virtio-scsi spec.794794+ */795795+ evt->event.lun[0] = 0x01;796796+ evt->event.lun[1] = tpg->tport_tpgt & 0xFF;797797+ if (lun->unpacked_lun >= 256)798798+ evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ;799799+ evt->event.lun[3] = lun->unpacked_lun & 0xFF;800800+ }801801+802802+ llist_add(&evt->list, &vs->vs_event_list);803803+ vhost_work_queue(&vs->dev, &vs->vs_event_work);804804+}805805+888806static void vhost_scsi_evt_handle_kick(struct vhost_work *work)889807{890890- pr_debug("%s: The handling func for event queue.\n", __func__);808808+ struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,809809+ poll.work);810810+ struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);811811+812812+ mutex_lock(&vq->mutex);813813+ if (!vq->private_data)814814+ goto out;815815+816816+ if (vs->vs_events_missed)817817+ tcm_vhost_send_evt(vs, NULL, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);818818+out:819819+ mutex_unlock(&vq->mutex);891820}892821893822static void vhost_scsi_handle_kick(struct vhost_work *work)···948803 for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)949804 vhost_scsi_flush_vq(vs, i);950805 vhost_work_flush(&vs->dev, &vs->vs_completion_work);806806+ vhost_work_flush(&vs->dev, &vs->vs_event_work);951807}952808953809/*954810 * Called from vhost_scsi_ioctl() context to walk the list of available955811 * tcm_vhost_tpg with an active struct tcm_vhost_nexus812812+ *813813+ * The lock nesting rule is:814814+ * tcm_vhost_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex956815 */957816static int vhost_scsi_set_endpoint(958817 struct vhost_scsi *vs,···969820 int index, ret, i, len;970821 bool match = false;971822823823+ mutex_lock(&tcm_vhost_mutex);972824 mutex_lock(&vs->dev.mutex);825825+973826 /* Verify that ring has been setup correctly. */974827 for (index = 0; index < vs->dev.nvqs; ++index) {975828 /* Verify that ring has been setup correctly. */976829 if (!vhost_vq_access_ok(&vs->vqs[index])) {977977- mutex_unlock(&vs->dev.mutex);978978- return -EFAULT;830830+ ret = -EFAULT;831831+ goto out;979832 }980833 }981834982835 len = sizeof(vs_tpg[0]) * VHOST_SCSI_MAX_TARGET;983836 vs_tpg = kzalloc(len, GFP_KERNEL);984837 if (!vs_tpg) {985985- mutex_unlock(&vs->dev.mutex);986986- return -ENOMEM;838838+ ret = -ENOMEM;839839+ goto out;987840 }988841 if (vs->vs_tpg)989842 memcpy(vs_tpg, vs->vs_tpg, len);990843991991- mutex_lock(&tcm_vhost_mutex);992844 list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) {993845 mutex_lock(&tv_tpg->tv_tpg_mutex);994846 if (!tv_tpg->tpg_nexus) {···10048541005855 if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) {1006856 if (vs->vs_tpg && vs->vs_tpg[tv_tpg->tport_tpgt]) {10071007- mutex_unlock(&tv_tpg->tv_tpg_mutex);10081008- mutex_unlock(&tcm_vhost_mutex);10091009- mutex_unlock(&vs->dev.mutex);1010857 kfree(vs_tpg);10111011- return -EEXIST;858858+ mutex_unlock(&tv_tpg->tv_tpg_mutex);859859+ ret = -EEXIST;860860+ goto out;1012861 }1013862 tv_tpg->tv_tpg_vhost_count++;863863+ tv_tpg->vhost_scsi = vs;1014864 vs_tpg[tv_tpg->tport_tpgt] = tv_tpg;1015865 smp_mb__after_atomic_inc();1016866 match = true;1017867 }1018868 mutex_unlock(&tv_tpg->tv_tpg_mutex);1019869 }10201020- mutex_unlock(&tcm_vhost_mutex);10218701022871 if (match) {1023872 memcpy(vs->vs_vhost_wwpn, t->vhost_wwpn,···1042893 kfree(vs->vs_tpg);1043894 vs->vs_tpg = vs_tpg;1044895896896+out:1045897 mutex_unlock(&vs->dev.mutex);898898+ mutex_unlock(&tcm_vhost_mutex);1046899 return ret;1047900}1048901···1059908 int index, ret, i;1060909 u8 target;1061910911911+ mutex_lock(&tcm_vhost_mutex);1062912 mutex_lock(&vs->dev.mutex);1063913 /* Verify that ring has been setup correctly. */1064914 for (index = 0; index < vs->dev.nvqs; ++index) {···1070918 }10719191072920 if (!vs->vs_tpg) {10731073- mutex_unlock(&vs->dev.mutex);10741074- return 0;921921+ ret = 0;922922+ goto err_dev;1075923 }10769241077925 for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) {···1096944 goto err_tpg;1097945 }1098946 tv_tpg->tv_tpg_vhost_count--;947947+ tv_tpg->vhost_scsi = NULL;1099948 vs->vs_tpg[target] = NULL;1100949 match = true;1101950 mutex_unlock(&tv_tpg->tv_tpg_mutex);···1117964 vhost_scsi_flush(vs);1118965 kfree(vs->vs_tpg);1119966 vs->vs_tpg = NULL;967967+ WARN_ON(vs->vs_events_nr);1120968 mutex_unlock(&vs->dev.mutex);11211121-969969+ mutex_unlock(&tcm_vhost_mutex);1122970 return 0;11239711124972err_tpg:1125973 mutex_unlock(&tv_tpg->tv_tpg_mutex);1126974err_dev:1127975 mutex_unlock(&vs->dev.mutex);976976+ mutex_unlock(&tcm_vhost_mutex);1128977 return ret;1129978}1130979···11581003 return -ENOMEM;1159100411601005 vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work);10061006+ vhost_work_init(&s->vs_event_work, tcm_vhost_evt_work);10071007+10081008+ s->vs_events_nr = 0;10091009+ s->vs_events_missed = false;1161101011621011 s->vqs[VHOST_SCSI_VQ_CTL].handle_kick = vhost_scsi_ctl_handle_kick;11631012 s->vqs[VHOST_SCSI_VQ_EVT].handle_kick = vhost_scsi_evt_handle_kick;···11881029 vhost_scsi_clear_endpoint(s, &t);11891030 vhost_dev_stop(&s->dev);11901031 vhost_dev_cleanup(&s->dev, false);10321032+ /* Jobs can re-queue themselves in evt kick handler. Do extra flush. */10331033+ vhost_scsi_flush(s);11911034 kfree(s);11921035 return 0;11931036}···12011040 struct vhost_scsi_target backend;12021041 void __user *argp = (void __user *)arg;12031042 u64 __user *featurep = argp;10431043+ u32 __user *eventsp = argp;10441044+ u32 events_missed;12041045 u64 features;12051046 int r, abi_version = VHOST_SCSI_ABI_VERSION;10471047+ struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT];1206104812071049 switch (ioctl) {12081050 case VHOST_SCSI_SET_ENDPOINT:···12241060 return vhost_scsi_clear_endpoint(vs, &backend);12251061 case VHOST_SCSI_GET_ABI_VERSION:12261062 if (copy_to_user(argp, &abi_version, sizeof abi_version))10631063+ return -EFAULT;10641064+ return 0;10651065+ case VHOST_SCSI_SET_EVENTS_MISSED:10661066+ if (get_user(events_missed, eventsp))10671067+ return -EFAULT;10681068+ mutex_lock(&vq->mutex);10691069+ vs->vs_events_missed = events_missed;10701070+ mutex_unlock(&vq->mutex);10711071+ return 0;10721072+ case VHOST_SCSI_GET_EVENTS_MISSED:10731073+ mutex_lock(&vq->mutex);10741074+ events_missed = vs->vs_events_missed;10751075+ mutex_unlock(&vq->mutex);10761076+ if (put_user(events_missed, eventsp))12271077 return -EFAULT;12281078 return 0;12291079 case VHOST_GET_FEATURES:···13111133 return "Unknown";13121134}1313113511361136+static void tcm_vhost_do_plug(struct tcm_vhost_tpg *tpg,11371137+ struct se_lun *lun, bool plug)11381138+{11391139+11401140+ struct vhost_scsi *vs = tpg->vhost_scsi;11411141+ struct vhost_virtqueue *vq;11421142+ u32 reason;11431143+11441144+ if (!vs)11451145+ return;11461146+11471147+ mutex_lock(&vs->dev.mutex);11481148+ if (!vhost_has_feature(&vs->dev, VIRTIO_SCSI_F_HOTPLUG)) {11491149+ mutex_unlock(&vs->dev.mutex);11501150+ return;11511151+ }11521152+11531153+ if (plug)11541154+ reason = VIRTIO_SCSI_EVT_RESET_RESCAN;11551155+ else11561156+ reason = VIRTIO_SCSI_EVT_RESET_REMOVED;11571157+11581158+ vq = &vs->vqs[VHOST_SCSI_VQ_EVT];11591159+ mutex_lock(&vq->mutex);11601160+ tcm_vhost_send_evt(vs, tpg, lun,11611161+ VIRTIO_SCSI_T_TRANSPORT_RESET, reason);11621162+ mutex_unlock(&vq->mutex);11631163+ mutex_unlock(&vs->dev.mutex);11641164+}11651165+11661166+static void tcm_vhost_hotplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)11671167+{11681168+ tcm_vhost_do_plug(tpg, lun, true);11691169+}11701170+11711171+static void tcm_vhost_hotunplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)11721172+{11731173+ tcm_vhost_do_plug(tpg, lun, false);11741174+}11751175+13141176static int tcm_vhost_port_link(struct se_portal_group *se_tpg,13151177 struct se_lun *lun)13161178{13171179 struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,13181180 struct tcm_vhost_tpg, se_tpg);1319118111821182+ mutex_lock(&tcm_vhost_mutex);11831183+13201184 mutex_lock(&tv_tpg->tv_tpg_mutex);13211185 tv_tpg->tv_tpg_port_count++;13221186 mutex_unlock(&tv_tpg->tv_tpg_mutex);11871187+11881188+ tcm_vhost_hotplug(tv_tpg, lun);11891189+11901190+ mutex_unlock(&tcm_vhost_mutex);1323119113241192 return 0;13251193}1326119413271195static void tcm_vhost_port_unlink(struct se_portal_group *se_tpg,13281328- struct se_lun *se_lun)11961196+ struct se_lun *lun)13291197{13301198 struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,13311199 struct tcm_vhost_tpg, se_tpg);1332120012011201+ mutex_lock(&tcm_vhost_mutex);12021202+13331203 mutex_lock(&tv_tpg->tv_tpg_mutex);13341204 tv_tpg->tv_tpg_port_count--;13351205 mutex_unlock(&tv_tpg->tv_tpg_mutex);12061206+12071207+ tcm_vhost_hotunplug(tv_tpg, lun);12081208+12091209+ mutex_unlock(&tcm_vhost_mutex);13361210}1337121113381212static struct se_node_acl *tcm_vhost_make_nodeacl(
+13
drivers/vhost/tcm_vhost.h
···5353 struct se_node_acl se_node_acl;5454};55555656+struct vhost_scsi;5657struct tcm_vhost_tpg {5758 /* Vhost port target portal group tag for TCM */5859 u16 tport_tpgt;···7170 struct tcm_vhost_tport *tport;7271 /* Returned by tcm_vhost_make_tpg() */7372 struct se_portal_group se_tpg;7373+ /* Pointer back to vhost_scsi, protected by tv_tpg_mutex */7474+ struct vhost_scsi *vhost_scsi;7475};75767677struct tcm_vhost_tport {···8481 char tport_name[TCM_VHOST_NAMELEN];8582 /* Returned by tcm_vhost_make_tport() */8683 struct se_wwn tport_wwn;8484+};8585+8686+struct tcm_vhost_evt {8787+ /* event to be sent to guest */8888+ struct virtio_scsi_event event;8989+ /* event list, serviced from vhost worker thread */9090+ struct llist_node list;8791};88928993/*···123113#define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target)124114/* Changing this breaks userspace. */125115#define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, int)116116+/* Set and get the events missed flag */117117+#define VHOST_SCSI_SET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x43, __u32)118118+#define VHOST_SCSI_GET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x44, __u32)