162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Target based USB-Gadget
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * UAS protocol handling, target callbacks, configfs handling,
562306a36Sopenharmony_ci * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/types.h>
1262306a36Sopenharmony_ci#include <linux/string.h>
1362306a36Sopenharmony_ci#include <linux/configfs.h>
1462306a36Sopenharmony_ci#include <linux/ctype.h>
1562306a36Sopenharmony_ci#include <linux/usb/ch9.h>
1662306a36Sopenharmony_ci#include <linux/usb/composite.h>
1762306a36Sopenharmony_ci#include <linux/usb/gadget.h>
1862306a36Sopenharmony_ci#include <linux/usb/storage.h>
1962306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
2062306a36Sopenharmony_ci#include <target/target_core_base.h>
2162306a36Sopenharmony_ci#include <target/target_core_fabric.h>
2262306a36Sopenharmony_ci#include <asm/unaligned.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "tcm.h"
2562306a36Sopenharmony_ci#include "u_tcm.h"
2662306a36Sopenharmony_ci#include "configfs.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define TPG_INSTANCES		1
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct tpg_instance {
3162306a36Sopenharmony_ci	struct usb_function_instance	*func_inst;
3262306a36Sopenharmony_ci	struct usbg_tpg			*tpg;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic struct tpg_instance tpg_instances[TPG_INSTANCES];
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic DEFINE_MUTEX(tpg_instances_lock);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic inline struct f_uas *to_f_uas(struct usb_function *f)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	return container_of(f, struct f_uas, function);
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* Start bot.c code */
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int bot_enqueue_cmd_cbw(struct f_uas *fu)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	int ret;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (fu->flags & USBG_BOT_CMD_PEND)
5162306a36Sopenharmony_ci		return 0;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
5462306a36Sopenharmony_ci	if (!ret)
5562306a36Sopenharmony_ci		fu->flags |= USBG_BOT_CMD_PEND;
5662306a36Sopenharmony_ci	return ret;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct usbg_cmd *cmd = req->context;
6262306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	transport_generic_free_cmd(&cmd->se_cmd, 0);
6562306a36Sopenharmony_ci	if (req->status < 0) {
6662306a36Sopenharmony_ci		pr_err("ERR %s(%d)\n", __func__, __LINE__);
6762306a36Sopenharmony_ci		return;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* CSW completed, wait for next CBW */
7162306a36Sopenharmony_ci	bot_enqueue_cmd_cbw(fu);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
7762306a36Sopenharmony_ci	int ret;
7862306a36Sopenharmony_ci	unsigned int csw_stat;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	csw_stat = cmd->csw_code;
8162306a36Sopenharmony_ci	csw->Tag = cmd->bot_tag;
8262306a36Sopenharmony_ci	csw->Status = csw_stat;
8362306a36Sopenharmony_ci	fu->bot_status.req->context = cmd;
8462306a36Sopenharmony_ci	ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
8562306a36Sopenharmony_ci	if (ret)
8662306a36Sopenharmony_ci		pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct usbg_cmd *cmd = req->context;
9262306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (req->status < 0)
9562306a36Sopenharmony_ci		pr_err("ERR %s(%d)\n", __func__, __LINE__);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (cmd->data_len) {
9862306a36Sopenharmony_ci		if (cmd->data_len > ep->maxpacket) {
9962306a36Sopenharmony_ci			req->length = ep->maxpacket;
10062306a36Sopenharmony_ci			cmd->data_len -= ep->maxpacket;
10162306a36Sopenharmony_ci		} else {
10262306a36Sopenharmony_ci			req->length = cmd->data_len;
10362306a36Sopenharmony_ci			cmd->data_len = 0;
10462306a36Sopenharmony_ci		}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		usb_ep_queue(ep, req, GFP_ATOMIC);
10762306a36Sopenharmony_ci		return;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci	bot_enqueue_sense_code(fu, cmd);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void bot_send_bad_status(struct usbg_cmd *cmd)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
11562306a36Sopenharmony_ci	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
11662306a36Sopenharmony_ci	struct usb_request *req;
11762306a36Sopenharmony_ci	struct usb_ep *ep;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	csw->Residue = cpu_to_le32(cmd->data_len);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (cmd->data_len) {
12262306a36Sopenharmony_ci		if (cmd->is_read) {
12362306a36Sopenharmony_ci			ep = fu->ep_in;
12462306a36Sopenharmony_ci			req = fu->bot_req_in;
12562306a36Sopenharmony_ci		} else {
12662306a36Sopenharmony_ci			ep = fu->ep_out;
12762306a36Sopenharmony_ci			req = fu->bot_req_out;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		if (cmd->data_len > fu->ep_in->maxpacket) {
13162306a36Sopenharmony_ci			req->length = ep->maxpacket;
13262306a36Sopenharmony_ci			cmd->data_len -= ep->maxpacket;
13362306a36Sopenharmony_ci		} else {
13462306a36Sopenharmony_ci			req->length = cmd->data_len;
13562306a36Sopenharmony_ci			cmd->data_len = 0;
13662306a36Sopenharmony_ci		}
13762306a36Sopenharmony_ci		req->complete = bot_err_compl;
13862306a36Sopenharmony_ci		req->context = cmd;
13962306a36Sopenharmony_ci		req->buf = fu->cmd.buf;
14062306a36Sopenharmony_ci		usb_ep_queue(ep, req, GFP_KERNEL);
14162306a36Sopenharmony_ci	} else {
14262306a36Sopenharmony_ci		bot_enqueue_sense_code(fu, cmd);
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
14962306a36Sopenharmony_ci	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
15062306a36Sopenharmony_ci	int ret;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
15362306a36Sopenharmony_ci		if (!moved_data && cmd->data_len) {
15462306a36Sopenharmony_ci			/*
15562306a36Sopenharmony_ci			 * the host wants to move data, we don't. Fill / empty
15662306a36Sopenharmony_ci			 * the pipe and then send the csw with reside set.
15762306a36Sopenharmony_ci			 */
15862306a36Sopenharmony_ci			cmd->csw_code = US_BULK_STAT_OK;
15962306a36Sopenharmony_ci			bot_send_bad_status(cmd);
16062306a36Sopenharmony_ci			return 0;
16162306a36Sopenharmony_ci		}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci		csw->Tag = cmd->bot_tag;
16462306a36Sopenharmony_ci		csw->Residue = cpu_to_le32(0);
16562306a36Sopenharmony_ci		csw->Status = US_BULK_STAT_OK;
16662306a36Sopenharmony_ci		fu->bot_status.req->context = cmd;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
16962306a36Sopenharmony_ci		if (ret)
17062306a36Sopenharmony_ci			pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
17162306a36Sopenharmony_ci	} else {
17262306a36Sopenharmony_ci		cmd->csw_code = US_BULK_STAT_FAIL;
17362306a36Sopenharmony_ci		bot_send_bad_status(cmd);
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci	return 0;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/*
17962306a36Sopenharmony_ci * Called after command (no data transfer) or after the write (to device)
18062306a36Sopenharmony_ci * operation is completed
18162306a36Sopenharmony_ci */
18262306a36Sopenharmony_cistatic int bot_send_status_response(struct usbg_cmd *cmd)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	bool moved_data = false;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (!cmd->is_read)
18762306a36Sopenharmony_ci		moved_data = true;
18862306a36Sopenharmony_ci	return bot_send_status(cmd, moved_data);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/* Read request completed, now we have to send the CSW */
19262306a36Sopenharmony_cistatic void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct usbg_cmd *cmd = req->context;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (req->status < 0)
19762306a36Sopenharmony_ci		pr_err("ERR %s(%d)\n", __func__, __LINE__);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	bot_send_status(cmd, true);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic int bot_send_read_response(struct usbg_cmd *cmd)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
20562306a36Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
20662306a36Sopenharmony_ci	struct usb_gadget *gadget = fuas_to_gadget(fu);
20762306a36Sopenharmony_ci	int ret;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (!cmd->data_len) {
21062306a36Sopenharmony_ci		cmd->csw_code = US_BULK_STAT_PHASE;
21162306a36Sopenharmony_ci		bot_send_bad_status(cmd);
21262306a36Sopenharmony_ci		return 0;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (!gadget->sg_supported) {
21662306a36Sopenharmony_ci		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
21762306a36Sopenharmony_ci		if (!cmd->data_buf)
21862306a36Sopenharmony_ci			return -ENOMEM;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		sg_copy_to_buffer(se_cmd->t_data_sg,
22162306a36Sopenharmony_ci				se_cmd->t_data_nents,
22262306a36Sopenharmony_ci				cmd->data_buf,
22362306a36Sopenharmony_ci				se_cmd->data_length);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		fu->bot_req_in->buf = cmd->data_buf;
22662306a36Sopenharmony_ci	} else {
22762306a36Sopenharmony_ci		fu->bot_req_in->buf = NULL;
22862306a36Sopenharmony_ci		fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
22962306a36Sopenharmony_ci		fu->bot_req_in->sg = se_cmd->t_data_sg;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	fu->bot_req_in->complete = bot_read_compl;
23362306a36Sopenharmony_ci	fu->bot_req_in->length = se_cmd->data_length;
23462306a36Sopenharmony_ci	fu->bot_req_in->context = cmd;
23562306a36Sopenharmony_ci	ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
23662306a36Sopenharmony_ci	if (ret)
23762306a36Sopenharmony_ci		pr_err("%s(%d)\n", __func__, __LINE__);
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
24262306a36Sopenharmony_cistatic int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int bot_send_write_request(struct usbg_cmd *cmd)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
24762306a36Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
24862306a36Sopenharmony_ci	struct usb_gadget *gadget = fuas_to_gadget(fu);
24962306a36Sopenharmony_ci	int ret;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	init_completion(&cmd->write_complete);
25262306a36Sopenharmony_ci	cmd->fu = fu;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (!cmd->data_len) {
25562306a36Sopenharmony_ci		cmd->csw_code = US_BULK_STAT_PHASE;
25662306a36Sopenharmony_ci		return -EINVAL;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (!gadget->sg_supported) {
26062306a36Sopenharmony_ci		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
26162306a36Sopenharmony_ci		if (!cmd->data_buf)
26262306a36Sopenharmony_ci			return -ENOMEM;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		fu->bot_req_out->buf = cmd->data_buf;
26562306a36Sopenharmony_ci	} else {
26662306a36Sopenharmony_ci		fu->bot_req_out->buf = NULL;
26762306a36Sopenharmony_ci		fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
26862306a36Sopenharmony_ci		fu->bot_req_out->sg = se_cmd->t_data_sg;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	fu->bot_req_out->complete = usbg_data_write_cmpl;
27262306a36Sopenharmony_ci	fu->bot_req_out->length = se_cmd->data_length;
27362306a36Sopenharmony_ci	fu->bot_req_out->context = cmd;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
27662306a36Sopenharmony_ci	if (ret)
27762306a36Sopenharmony_ci		goto cleanup;
27862306a36Sopenharmony_ci	ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
27962306a36Sopenharmony_ci	if (ret)
28062306a36Sopenharmony_ci		pr_err("%s(%d)\n", __func__, __LINE__);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	wait_for_completion(&cmd->write_complete);
28362306a36Sopenharmony_ci	target_execute_cmd(se_cmd);
28462306a36Sopenharmony_cicleanup:
28562306a36Sopenharmony_ci	return ret;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int bot_submit_command(struct f_uas *, void *, unsigned int);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct f_uas *fu = req->context;
29362306a36Sopenharmony_ci	int ret;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	fu->flags &= ~USBG_BOT_CMD_PEND;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (req->status < 0)
29862306a36Sopenharmony_ci		return;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	ret = bot_submit_command(fu, req->buf, req->actual);
30162306a36Sopenharmony_ci	if (ret)
30262306a36Sopenharmony_ci		pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic int bot_prepare_reqs(struct f_uas *fu)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	int ret;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
31062306a36Sopenharmony_ci	if (!fu->bot_req_in)
31162306a36Sopenharmony_ci		goto err;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
31462306a36Sopenharmony_ci	if (!fu->bot_req_out)
31562306a36Sopenharmony_ci		goto err_out;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
31862306a36Sopenharmony_ci	if (!fu->cmd.req)
31962306a36Sopenharmony_ci		goto err_cmd;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
32262306a36Sopenharmony_ci	if (!fu->bot_status.req)
32362306a36Sopenharmony_ci		goto err_sts;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	fu->bot_status.req->buf = &fu->bot_status.csw;
32662306a36Sopenharmony_ci	fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
32762306a36Sopenharmony_ci	fu->bot_status.req->complete = bot_status_complete;
32862306a36Sopenharmony_ci	fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
33162306a36Sopenharmony_ci	if (!fu->cmd.buf)
33262306a36Sopenharmony_ci		goto err_buf;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	fu->cmd.req->complete = bot_cmd_complete;
33562306a36Sopenharmony_ci	fu->cmd.req->buf = fu->cmd.buf;
33662306a36Sopenharmony_ci	fu->cmd.req->length = fu->ep_out->maxpacket;
33762306a36Sopenharmony_ci	fu->cmd.req->context = fu;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	ret = bot_enqueue_cmd_cbw(fu);
34062306a36Sopenharmony_ci	if (ret)
34162306a36Sopenharmony_ci		goto err_queue;
34262306a36Sopenharmony_ci	return 0;
34362306a36Sopenharmony_cierr_queue:
34462306a36Sopenharmony_ci	kfree(fu->cmd.buf);
34562306a36Sopenharmony_ci	fu->cmd.buf = NULL;
34662306a36Sopenharmony_cierr_buf:
34762306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_in, fu->bot_status.req);
34862306a36Sopenharmony_cierr_sts:
34962306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_out, fu->cmd.req);
35062306a36Sopenharmony_ci	fu->cmd.req = NULL;
35162306a36Sopenharmony_cierr_cmd:
35262306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_out, fu->bot_req_out);
35362306a36Sopenharmony_ci	fu->bot_req_out = NULL;
35462306a36Sopenharmony_cierr_out:
35562306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_in, fu->bot_req_in);
35662306a36Sopenharmony_ci	fu->bot_req_in = NULL;
35762306a36Sopenharmony_cierr:
35862306a36Sopenharmony_ci	pr_err("BOT: endpoint setup failed\n");
35962306a36Sopenharmony_ci	return -ENOMEM;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic void bot_cleanup_old_alt(struct f_uas *fu)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	if (!(fu->flags & USBG_ENABLED))
36562306a36Sopenharmony_ci		return;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	usb_ep_disable(fu->ep_in);
36862306a36Sopenharmony_ci	usb_ep_disable(fu->ep_out);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (!fu->bot_req_in)
37162306a36Sopenharmony_ci		return;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_in, fu->bot_req_in);
37462306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_out, fu->bot_req_out);
37562306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_out, fu->cmd.req);
37662306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_in, fu->bot_status.req);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	kfree(fu->cmd.buf);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	fu->bot_req_in = NULL;
38162306a36Sopenharmony_ci	fu->bot_req_out = NULL;
38262306a36Sopenharmony_ci	fu->cmd.req = NULL;
38362306a36Sopenharmony_ci	fu->bot_status.req = NULL;
38462306a36Sopenharmony_ci	fu->cmd.buf = NULL;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic void bot_set_alt(struct f_uas *fu)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct usb_function *f = &fu->function;
39062306a36Sopenharmony_ci	struct usb_gadget *gadget = f->config->cdev->gadget;
39162306a36Sopenharmony_ci	int ret;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	fu->flags = USBG_IS_BOT;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	config_ep_by_speed_and_alt(gadget, f, fu->ep_in, USB_G_ALT_INT_BBB);
39662306a36Sopenharmony_ci	ret = usb_ep_enable(fu->ep_in);
39762306a36Sopenharmony_ci	if (ret)
39862306a36Sopenharmony_ci		goto err_b_in;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	config_ep_by_speed_and_alt(gadget, f, fu->ep_out, USB_G_ALT_INT_BBB);
40162306a36Sopenharmony_ci	ret = usb_ep_enable(fu->ep_out);
40262306a36Sopenharmony_ci	if (ret)
40362306a36Sopenharmony_ci		goto err_b_out;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ret = bot_prepare_reqs(fu);
40662306a36Sopenharmony_ci	if (ret)
40762306a36Sopenharmony_ci		goto err_wq;
40862306a36Sopenharmony_ci	fu->flags |= USBG_ENABLED;
40962306a36Sopenharmony_ci	pr_info("Using the BOT protocol\n");
41062306a36Sopenharmony_ci	return;
41162306a36Sopenharmony_cierr_wq:
41262306a36Sopenharmony_ci	usb_ep_disable(fu->ep_out);
41362306a36Sopenharmony_cierr_b_out:
41462306a36Sopenharmony_ci	usb_ep_disable(fu->ep_in);
41562306a36Sopenharmony_cierr_b_in:
41662306a36Sopenharmony_ci	fu->flags = USBG_IS_BOT;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic int usbg_bot_setup(struct usb_function *f,
42062306a36Sopenharmony_ci		const struct usb_ctrlrequest *ctrl)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct f_uas *fu = to_f_uas(f);
42362306a36Sopenharmony_ci	struct usb_composite_dev *cdev = f->config->cdev;
42462306a36Sopenharmony_ci	u16 w_value = le16_to_cpu(ctrl->wValue);
42562306a36Sopenharmony_ci	u16 w_length = le16_to_cpu(ctrl->wLength);
42662306a36Sopenharmony_ci	int luns;
42762306a36Sopenharmony_ci	u8 *ret_lun;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	switch (ctrl->bRequest) {
43062306a36Sopenharmony_ci	case US_BULK_GET_MAX_LUN:
43162306a36Sopenharmony_ci		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
43262306a36Sopenharmony_ci					USB_RECIP_INTERFACE))
43362306a36Sopenharmony_ci			return -ENOTSUPP;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		if (w_length < 1)
43662306a36Sopenharmony_ci			return -EINVAL;
43762306a36Sopenharmony_ci		if (w_value != 0)
43862306a36Sopenharmony_ci			return -EINVAL;
43962306a36Sopenharmony_ci		luns = atomic_read(&fu->tpg->tpg_port_count);
44062306a36Sopenharmony_ci		if (!luns) {
44162306a36Sopenharmony_ci			pr_err("No LUNs configured?\n");
44262306a36Sopenharmony_ci			return -EINVAL;
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci		/*
44562306a36Sopenharmony_ci		 * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
44662306a36Sopenharmony_ci		 * accessed. The upper limit is 0xf
44762306a36Sopenharmony_ci		 */
44862306a36Sopenharmony_ci		luns--;
44962306a36Sopenharmony_ci		if (luns > 0xf) {
45062306a36Sopenharmony_ci			pr_info_once("Limiting the number of luns to 16\n");
45162306a36Sopenharmony_ci			luns = 0xf;
45262306a36Sopenharmony_ci		}
45362306a36Sopenharmony_ci		ret_lun = cdev->req->buf;
45462306a36Sopenharmony_ci		*ret_lun = luns;
45562306a36Sopenharmony_ci		cdev->req->length = 1;
45662306a36Sopenharmony_ci		return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	case US_BULK_RESET_REQUEST:
45962306a36Sopenharmony_ci		/* XXX maybe we should remove previous requests for IN + OUT */
46062306a36Sopenharmony_ci		bot_enqueue_cmd_cbw(fu);
46162306a36Sopenharmony_ci		return 0;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci	return -ENOTSUPP;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci/* Start uas.c code */
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	/* We have either all three allocated or none */
47162306a36Sopenharmony_ci	if (!stream->req_in)
47262306a36Sopenharmony_ci		return;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_in, stream->req_in);
47562306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_out, stream->req_out);
47662306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_status, stream->req_status);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	stream->req_in = NULL;
47962306a36Sopenharmony_ci	stream->req_out = NULL;
48062306a36Sopenharmony_ci	stream->req_status = NULL;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic void uasp_free_cmdreq(struct f_uas *fu)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
48662306a36Sopenharmony_ci	kfree(fu->cmd.buf);
48762306a36Sopenharmony_ci	fu->cmd.req = NULL;
48862306a36Sopenharmony_ci	fu->cmd.buf = NULL;
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic void uasp_cleanup_old_alt(struct f_uas *fu)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	int i;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (!(fu->flags & USBG_ENABLED))
49662306a36Sopenharmony_ci		return;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	usb_ep_disable(fu->ep_in);
49962306a36Sopenharmony_ci	usb_ep_disable(fu->ep_out);
50062306a36Sopenharmony_ci	usb_ep_disable(fu->ep_status);
50162306a36Sopenharmony_ci	usb_ep_disable(fu->ep_cmd);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
50462306a36Sopenharmony_ci		uasp_cleanup_one_stream(fu, &fu->stream[i]);
50562306a36Sopenharmony_ci	uasp_free_cmdreq(fu);
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic int uasp_prepare_r_request(struct usbg_cmd *cmd)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
51362306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
51462306a36Sopenharmony_ci	struct usb_gadget *gadget = fuas_to_gadget(fu);
51562306a36Sopenharmony_ci	struct uas_stream *stream = cmd->stream;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (!gadget->sg_supported) {
51862306a36Sopenharmony_ci		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
51962306a36Sopenharmony_ci		if (!cmd->data_buf)
52062306a36Sopenharmony_ci			return -ENOMEM;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		sg_copy_to_buffer(se_cmd->t_data_sg,
52362306a36Sopenharmony_ci				se_cmd->t_data_nents,
52462306a36Sopenharmony_ci				cmd->data_buf,
52562306a36Sopenharmony_ci				se_cmd->data_length);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		stream->req_in->buf = cmd->data_buf;
52862306a36Sopenharmony_ci	} else {
52962306a36Sopenharmony_ci		stream->req_in->buf = NULL;
53062306a36Sopenharmony_ci		stream->req_in->num_sgs = se_cmd->t_data_nents;
53162306a36Sopenharmony_ci		stream->req_in->sg = se_cmd->t_data_sg;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	stream->req_in->is_last = 1;
53562306a36Sopenharmony_ci	stream->req_in->complete = uasp_status_data_cmpl;
53662306a36Sopenharmony_ci	stream->req_in->length = se_cmd->data_length;
53762306a36Sopenharmony_ci	stream->req_in->context = cmd;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	cmd->state = UASP_SEND_STATUS;
54062306a36Sopenharmony_ci	return 0;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic void uasp_prepare_status(struct usbg_cmd *cmd)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
54662306a36Sopenharmony_ci	struct sense_iu *iu = &cmd->sense_iu;
54762306a36Sopenharmony_ci	struct uas_stream *stream = cmd->stream;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	cmd->state = UASP_QUEUE_COMMAND;
55062306a36Sopenharmony_ci	iu->iu_id = IU_ID_STATUS;
55162306a36Sopenharmony_ci	iu->tag = cpu_to_be16(cmd->tag);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/*
55462306a36Sopenharmony_ci	 * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
55562306a36Sopenharmony_ci	 */
55662306a36Sopenharmony_ci	iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
55762306a36Sopenharmony_ci	iu->status = se_cmd->scsi_status;
55862306a36Sopenharmony_ci	stream->req_status->is_last = 1;
55962306a36Sopenharmony_ci	stream->req_status->context = cmd;
56062306a36Sopenharmony_ci	stream->req_status->length = se_cmd->scsi_sense_length + 16;
56162306a36Sopenharmony_ci	stream->req_status->buf = iu;
56262306a36Sopenharmony_ci	stream->req_status->complete = uasp_status_data_cmpl;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct usbg_cmd *cmd = req->context;
56862306a36Sopenharmony_ci	struct uas_stream *stream = cmd->stream;
56962306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
57062306a36Sopenharmony_ci	int ret;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	if (req->status < 0)
57362306a36Sopenharmony_ci		goto cleanup;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	switch (cmd->state) {
57662306a36Sopenharmony_ci	case UASP_SEND_DATA:
57762306a36Sopenharmony_ci		ret = uasp_prepare_r_request(cmd);
57862306a36Sopenharmony_ci		if (ret)
57962306a36Sopenharmony_ci			goto cleanup;
58062306a36Sopenharmony_ci		ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
58162306a36Sopenharmony_ci		if (ret)
58262306a36Sopenharmony_ci			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
58362306a36Sopenharmony_ci		break;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	case UASP_RECEIVE_DATA:
58662306a36Sopenharmony_ci		ret = usbg_prepare_w_request(cmd, stream->req_out);
58762306a36Sopenharmony_ci		if (ret)
58862306a36Sopenharmony_ci			goto cleanup;
58962306a36Sopenharmony_ci		ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
59062306a36Sopenharmony_ci		if (ret)
59162306a36Sopenharmony_ci			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
59262306a36Sopenharmony_ci		break;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	case UASP_SEND_STATUS:
59562306a36Sopenharmony_ci		uasp_prepare_status(cmd);
59662306a36Sopenharmony_ci		ret = usb_ep_queue(fu->ep_status, stream->req_status,
59762306a36Sopenharmony_ci				GFP_ATOMIC);
59862306a36Sopenharmony_ci		if (ret)
59962306a36Sopenharmony_ci			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
60062306a36Sopenharmony_ci		break;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	case UASP_QUEUE_COMMAND:
60362306a36Sopenharmony_ci		transport_generic_free_cmd(&cmd->se_cmd, 0);
60462306a36Sopenharmony_ci		usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
60562306a36Sopenharmony_ci		break;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	default:
60862306a36Sopenharmony_ci		BUG();
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci	return;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cicleanup:
61362306a36Sopenharmony_ci	transport_generic_free_cmd(&cmd->se_cmd, 0);
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic int uasp_send_status_response(struct usbg_cmd *cmd)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
61962306a36Sopenharmony_ci	struct uas_stream *stream = cmd->stream;
62062306a36Sopenharmony_ci	struct sense_iu *iu = &cmd->sense_iu;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	iu->tag = cpu_to_be16(cmd->tag);
62362306a36Sopenharmony_ci	stream->req_status->complete = uasp_status_data_cmpl;
62462306a36Sopenharmony_ci	stream->req_status->context = cmd;
62562306a36Sopenharmony_ci	cmd->fu = fu;
62662306a36Sopenharmony_ci	uasp_prepare_status(cmd);
62762306a36Sopenharmony_ci	return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic int uasp_send_read_response(struct usbg_cmd *cmd)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
63362306a36Sopenharmony_ci	struct uas_stream *stream = cmd->stream;
63462306a36Sopenharmony_ci	struct sense_iu *iu = &cmd->sense_iu;
63562306a36Sopenharmony_ci	int ret;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	cmd->fu = fu;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	iu->tag = cpu_to_be16(cmd->tag);
64062306a36Sopenharmony_ci	if (fu->flags & USBG_USE_STREAMS) {
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		ret = uasp_prepare_r_request(cmd);
64362306a36Sopenharmony_ci		if (ret)
64462306a36Sopenharmony_ci			goto out;
64562306a36Sopenharmony_ci		ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
64662306a36Sopenharmony_ci		if (ret) {
64762306a36Sopenharmony_ci			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
64862306a36Sopenharmony_ci			kfree(cmd->data_buf);
64962306a36Sopenharmony_ci			cmd->data_buf = NULL;
65062306a36Sopenharmony_ci		}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	} else {
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci		iu->iu_id = IU_ID_READ_READY;
65562306a36Sopenharmony_ci		iu->tag = cpu_to_be16(cmd->tag);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		stream->req_status->complete = uasp_status_data_cmpl;
65862306a36Sopenharmony_ci		stream->req_status->context = cmd;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		cmd->state = UASP_SEND_DATA;
66162306a36Sopenharmony_ci		stream->req_status->buf = iu;
66262306a36Sopenharmony_ci		stream->req_status->length = sizeof(struct iu);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		ret = usb_ep_queue(fu->ep_status, stream->req_status,
66562306a36Sopenharmony_ci				GFP_ATOMIC);
66662306a36Sopenharmony_ci		if (ret)
66762306a36Sopenharmony_ci			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ciout:
67062306a36Sopenharmony_ci	return ret;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic int uasp_send_write_request(struct usbg_cmd *cmd)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
67662306a36Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
67762306a36Sopenharmony_ci	struct uas_stream *stream = cmd->stream;
67862306a36Sopenharmony_ci	struct sense_iu *iu = &cmd->sense_iu;
67962306a36Sopenharmony_ci	int ret;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	init_completion(&cmd->write_complete);
68262306a36Sopenharmony_ci	cmd->fu = fu;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	iu->tag = cpu_to_be16(cmd->tag);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	if (fu->flags & USBG_USE_STREAMS) {
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		ret = usbg_prepare_w_request(cmd, stream->req_out);
68962306a36Sopenharmony_ci		if (ret)
69062306a36Sopenharmony_ci			goto cleanup;
69162306a36Sopenharmony_ci		ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
69262306a36Sopenharmony_ci		if (ret)
69362306a36Sopenharmony_ci			pr_err("%s(%d)\n", __func__, __LINE__);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	} else {
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci		iu->iu_id = IU_ID_WRITE_READY;
69862306a36Sopenharmony_ci		iu->tag = cpu_to_be16(cmd->tag);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci		stream->req_status->complete = uasp_status_data_cmpl;
70162306a36Sopenharmony_ci		stream->req_status->context = cmd;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		cmd->state = UASP_RECEIVE_DATA;
70462306a36Sopenharmony_ci		stream->req_status->buf = iu;
70562306a36Sopenharmony_ci		stream->req_status->length = sizeof(struct iu);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		ret = usb_ep_queue(fu->ep_status, stream->req_status,
70862306a36Sopenharmony_ci				GFP_ATOMIC);
70962306a36Sopenharmony_ci		if (ret)
71062306a36Sopenharmony_ci			pr_err("%s(%d)\n", __func__, __LINE__);
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	wait_for_completion(&cmd->write_complete);
71462306a36Sopenharmony_ci	target_execute_cmd(se_cmd);
71562306a36Sopenharmony_cicleanup:
71662306a36Sopenharmony_ci	return ret;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic int usbg_submit_command(struct f_uas *, void *, unsigned int);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	struct f_uas *fu = req->context;
72462306a36Sopenharmony_ci	int ret;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (req->status < 0)
72762306a36Sopenharmony_ci		return;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	ret = usbg_submit_command(fu, req->buf, req->actual);
73062306a36Sopenharmony_ci	/*
73162306a36Sopenharmony_ci	 * Once we tune for performance enqueue the command req here again so
73262306a36Sopenharmony_ci	 * we can receive a second command while we processing this one. Pay
73362306a36Sopenharmony_ci	 * attention to properly sync STAUS endpoint with DATA IN + OUT so you
73462306a36Sopenharmony_ci	 * don't break HS.
73562306a36Sopenharmony_ci	 */
73662306a36Sopenharmony_ci	if (!ret)
73762306a36Sopenharmony_ci		return;
73862306a36Sopenharmony_ci	usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
74462306a36Sopenharmony_ci	if (!stream->req_in)
74562306a36Sopenharmony_ci		goto out;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
74862306a36Sopenharmony_ci	if (!stream->req_out)
74962306a36Sopenharmony_ci		goto err_out;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
75262306a36Sopenharmony_ci	if (!stream->req_status)
75362306a36Sopenharmony_ci		goto err_sts;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	return 0;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cierr_sts:
75862306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_out, stream->req_out);
75962306a36Sopenharmony_ci	stream->req_out = NULL;
76062306a36Sopenharmony_cierr_out:
76162306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_in, stream->req_in);
76262306a36Sopenharmony_ci	stream->req_in = NULL;
76362306a36Sopenharmony_ciout:
76462306a36Sopenharmony_ci	return -ENOMEM;
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic int uasp_alloc_cmd(struct f_uas *fu)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
77062306a36Sopenharmony_ci	if (!fu->cmd.req)
77162306a36Sopenharmony_ci		goto err;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
77462306a36Sopenharmony_ci	if (!fu->cmd.buf)
77562306a36Sopenharmony_ci		goto err_buf;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	fu->cmd.req->complete = uasp_cmd_complete;
77862306a36Sopenharmony_ci	fu->cmd.req->buf = fu->cmd.buf;
77962306a36Sopenharmony_ci	fu->cmd.req->length = fu->ep_cmd->maxpacket;
78062306a36Sopenharmony_ci	fu->cmd.req->context = fu;
78162306a36Sopenharmony_ci	return 0;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cierr_buf:
78462306a36Sopenharmony_ci	usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
78562306a36Sopenharmony_cierr:
78662306a36Sopenharmony_ci	return -ENOMEM;
78762306a36Sopenharmony_ci}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	int i;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	for (i = 0; i < max_streams; i++) {
79462306a36Sopenharmony_ci		struct uas_stream *s = &fu->stream[i];
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci		s->req_in->stream_id = i + 1;
79762306a36Sopenharmony_ci		s->req_out->stream_id = i + 1;
79862306a36Sopenharmony_ci		s->req_status->stream_id = i + 1;
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic int uasp_prepare_reqs(struct f_uas *fu)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	int ret;
80562306a36Sopenharmony_ci	int i;
80662306a36Sopenharmony_ci	int max_streams;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (fu->flags & USBG_USE_STREAMS)
80962306a36Sopenharmony_ci		max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
81062306a36Sopenharmony_ci	else
81162306a36Sopenharmony_ci		max_streams = 1;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	for (i = 0; i < max_streams; i++) {
81462306a36Sopenharmony_ci		ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
81562306a36Sopenharmony_ci		if (ret)
81662306a36Sopenharmony_ci			goto err_cleanup;
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	ret = uasp_alloc_cmd(fu);
82062306a36Sopenharmony_ci	if (ret)
82162306a36Sopenharmony_ci		goto err_free_stream;
82262306a36Sopenharmony_ci	uasp_setup_stream_res(fu, max_streams);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
82562306a36Sopenharmony_ci	if (ret)
82662306a36Sopenharmony_ci		goto err_free_stream;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	return 0;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cierr_free_stream:
83162306a36Sopenharmony_ci	uasp_free_cmdreq(fu);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cierr_cleanup:
83462306a36Sopenharmony_ci	if (i) {
83562306a36Sopenharmony_ci		do {
83662306a36Sopenharmony_ci			uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
83762306a36Sopenharmony_ci			i--;
83862306a36Sopenharmony_ci		} while (i);
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci	pr_err("UASP: endpoint setup failed\n");
84162306a36Sopenharmony_ci	return ret;
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistatic void uasp_set_alt(struct f_uas *fu)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	struct usb_function *f = &fu->function;
84762306a36Sopenharmony_ci	struct usb_gadget *gadget = f->config->cdev->gadget;
84862306a36Sopenharmony_ci	int ret;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	fu->flags = USBG_IS_UAS;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	if (gadget->speed >= USB_SPEED_SUPER)
85362306a36Sopenharmony_ci		fu->flags |= USBG_USE_STREAMS;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	config_ep_by_speed_and_alt(gadget, f, fu->ep_in, USB_G_ALT_INT_UAS);
85662306a36Sopenharmony_ci	ret = usb_ep_enable(fu->ep_in);
85762306a36Sopenharmony_ci	if (ret)
85862306a36Sopenharmony_ci		goto err_b_in;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	config_ep_by_speed_and_alt(gadget, f, fu->ep_out, USB_G_ALT_INT_UAS);
86162306a36Sopenharmony_ci	ret = usb_ep_enable(fu->ep_out);
86262306a36Sopenharmony_ci	if (ret)
86362306a36Sopenharmony_ci		goto err_b_out;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	config_ep_by_speed_and_alt(gadget, f, fu->ep_cmd, USB_G_ALT_INT_UAS);
86662306a36Sopenharmony_ci	ret = usb_ep_enable(fu->ep_cmd);
86762306a36Sopenharmony_ci	if (ret)
86862306a36Sopenharmony_ci		goto err_cmd;
86962306a36Sopenharmony_ci	config_ep_by_speed_and_alt(gadget, f, fu->ep_status, USB_G_ALT_INT_UAS);
87062306a36Sopenharmony_ci	ret = usb_ep_enable(fu->ep_status);
87162306a36Sopenharmony_ci	if (ret)
87262306a36Sopenharmony_ci		goto err_status;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	ret = uasp_prepare_reqs(fu);
87562306a36Sopenharmony_ci	if (ret)
87662306a36Sopenharmony_ci		goto err_wq;
87762306a36Sopenharmony_ci	fu->flags |= USBG_ENABLED;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	pr_info("Using the UAS protocol\n");
88062306a36Sopenharmony_ci	return;
88162306a36Sopenharmony_cierr_wq:
88262306a36Sopenharmony_ci	usb_ep_disable(fu->ep_status);
88362306a36Sopenharmony_cierr_status:
88462306a36Sopenharmony_ci	usb_ep_disable(fu->ep_cmd);
88562306a36Sopenharmony_cierr_cmd:
88662306a36Sopenharmony_ci	usb_ep_disable(fu->ep_out);
88762306a36Sopenharmony_cierr_b_out:
88862306a36Sopenharmony_ci	usb_ep_disable(fu->ep_in);
88962306a36Sopenharmony_cierr_b_in:
89062306a36Sopenharmony_ci	fu->flags = 0;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic int get_cmd_dir(const unsigned char *cdb)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	int ret;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	switch (cdb[0]) {
89862306a36Sopenharmony_ci	case READ_6:
89962306a36Sopenharmony_ci	case READ_10:
90062306a36Sopenharmony_ci	case READ_12:
90162306a36Sopenharmony_ci	case READ_16:
90262306a36Sopenharmony_ci	case INQUIRY:
90362306a36Sopenharmony_ci	case MODE_SENSE:
90462306a36Sopenharmony_ci	case MODE_SENSE_10:
90562306a36Sopenharmony_ci	case SERVICE_ACTION_IN_16:
90662306a36Sopenharmony_ci	case MAINTENANCE_IN:
90762306a36Sopenharmony_ci	case PERSISTENT_RESERVE_IN:
90862306a36Sopenharmony_ci	case SECURITY_PROTOCOL_IN:
90962306a36Sopenharmony_ci	case ACCESS_CONTROL_IN:
91062306a36Sopenharmony_ci	case REPORT_LUNS:
91162306a36Sopenharmony_ci	case READ_BLOCK_LIMITS:
91262306a36Sopenharmony_ci	case READ_POSITION:
91362306a36Sopenharmony_ci	case READ_CAPACITY:
91462306a36Sopenharmony_ci	case READ_TOC:
91562306a36Sopenharmony_ci	case READ_FORMAT_CAPACITIES:
91662306a36Sopenharmony_ci	case REQUEST_SENSE:
91762306a36Sopenharmony_ci		ret = DMA_FROM_DEVICE;
91862306a36Sopenharmony_ci		break;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	case WRITE_6:
92162306a36Sopenharmony_ci	case WRITE_10:
92262306a36Sopenharmony_ci	case WRITE_12:
92362306a36Sopenharmony_ci	case WRITE_16:
92462306a36Sopenharmony_ci	case MODE_SELECT:
92562306a36Sopenharmony_ci	case MODE_SELECT_10:
92662306a36Sopenharmony_ci	case WRITE_VERIFY:
92762306a36Sopenharmony_ci	case WRITE_VERIFY_12:
92862306a36Sopenharmony_ci	case PERSISTENT_RESERVE_OUT:
92962306a36Sopenharmony_ci	case MAINTENANCE_OUT:
93062306a36Sopenharmony_ci	case SECURITY_PROTOCOL_OUT:
93162306a36Sopenharmony_ci	case ACCESS_CONTROL_OUT:
93262306a36Sopenharmony_ci		ret = DMA_TO_DEVICE;
93362306a36Sopenharmony_ci		break;
93462306a36Sopenharmony_ci	case ALLOW_MEDIUM_REMOVAL:
93562306a36Sopenharmony_ci	case TEST_UNIT_READY:
93662306a36Sopenharmony_ci	case SYNCHRONIZE_CACHE:
93762306a36Sopenharmony_ci	case START_STOP:
93862306a36Sopenharmony_ci	case ERASE:
93962306a36Sopenharmony_ci	case REZERO_UNIT:
94062306a36Sopenharmony_ci	case SEEK_10:
94162306a36Sopenharmony_ci	case SPACE:
94262306a36Sopenharmony_ci	case VERIFY:
94362306a36Sopenharmony_ci	case WRITE_FILEMARKS:
94462306a36Sopenharmony_ci		ret = DMA_NONE;
94562306a36Sopenharmony_ci		break;
94662306a36Sopenharmony_ci	default:
94762306a36Sopenharmony_ci#define CMD_DIR_MSG "target: Unknown data direction for SCSI Opcode 0x%02x\n"
94862306a36Sopenharmony_ci		pr_warn(CMD_DIR_MSG, cdb[0]);
94962306a36Sopenharmony_ci#undef CMD_DIR_MSG
95062306a36Sopenharmony_ci		ret = -EINVAL;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci	return ret;
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct usbg_cmd *cmd = req->context;
95862306a36Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	if (req->status < 0) {
96162306a36Sopenharmony_ci		pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
96262306a36Sopenharmony_ci		goto cleanup;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	if (req->num_sgs == 0) {
96662306a36Sopenharmony_ci		sg_copy_from_buffer(se_cmd->t_data_sg,
96762306a36Sopenharmony_ci				se_cmd->t_data_nents,
96862306a36Sopenharmony_ci				cmd->data_buf,
96962306a36Sopenharmony_ci				se_cmd->data_length);
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	complete(&cmd->write_complete);
97362306a36Sopenharmony_ci	return;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cicleanup:
97662306a36Sopenharmony_ci	transport_generic_free_cmd(&cmd->se_cmd, 0);
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cistatic int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	struct se_cmd *se_cmd = &cmd->se_cmd;
98262306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
98362306a36Sopenharmony_ci	struct usb_gadget *gadget = fuas_to_gadget(fu);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (!gadget->sg_supported) {
98662306a36Sopenharmony_ci		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
98762306a36Sopenharmony_ci		if (!cmd->data_buf)
98862306a36Sopenharmony_ci			return -ENOMEM;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci		req->buf = cmd->data_buf;
99162306a36Sopenharmony_ci	} else {
99262306a36Sopenharmony_ci		req->buf = NULL;
99362306a36Sopenharmony_ci		req->num_sgs = se_cmd->t_data_nents;
99462306a36Sopenharmony_ci		req->sg = se_cmd->t_data_sg;
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	req->is_last = 1;
99862306a36Sopenharmony_ci	req->complete = usbg_data_write_cmpl;
99962306a36Sopenharmony_ci	req->length = se_cmd->data_length;
100062306a36Sopenharmony_ci	req->context = cmd;
100162306a36Sopenharmony_ci	return 0;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic int usbg_send_status_response(struct se_cmd *se_cmd)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
100762306a36Sopenharmony_ci			se_cmd);
100862306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	if (fu->flags & USBG_IS_BOT)
101162306a36Sopenharmony_ci		return bot_send_status_response(cmd);
101262306a36Sopenharmony_ci	else
101362306a36Sopenharmony_ci		return uasp_send_status_response(cmd);
101462306a36Sopenharmony_ci}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_cistatic int usbg_send_write_request(struct se_cmd *se_cmd)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
101962306a36Sopenharmony_ci			se_cmd);
102062306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	if (fu->flags & USBG_IS_BOT)
102362306a36Sopenharmony_ci		return bot_send_write_request(cmd);
102462306a36Sopenharmony_ci	else
102562306a36Sopenharmony_ci		return uasp_send_write_request(cmd);
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_cistatic int usbg_send_read_response(struct se_cmd *se_cmd)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
103162306a36Sopenharmony_ci			se_cmd);
103262306a36Sopenharmony_ci	struct f_uas *fu = cmd->fu;
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	if (fu->flags & USBG_IS_BOT)
103562306a36Sopenharmony_ci		return bot_send_read_response(cmd);
103662306a36Sopenharmony_ci	else
103762306a36Sopenharmony_ci		return uasp_send_read_response(cmd);
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cistatic void usbg_cmd_work(struct work_struct *work)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
104362306a36Sopenharmony_ci	struct se_cmd *se_cmd;
104462306a36Sopenharmony_ci	struct tcm_usbg_nexus *tv_nexus;
104562306a36Sopenharmony_ci	struct usbg_tpg *tpg;
104662306a36Sopenharmony_ci	int dir, flags = (TARGET_SCF_UNKNOWN_SIZE | TARGET_SCF_ACK_KREF);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	se_cmd = &cmd->se_cmd;
104962306a36Sopenharmony_ci	tpg = cmd->fu->tpg;
105062306a36Sopenharmony_ci	tv_nexus = tpg->tpg_nexus;
105162306a36Sopenharmony_ci	dir = get_cmd_dir(cmd->cmd_buf);
105262306a36Sopenharmony_ci	if (dir < 0) {
105362306a36Sopenharmony_ci		__target_init_cmd(se_cmd,
105462306a36Sopenharmony_ci				  tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
105562306a36Sopenharmony_ci				  tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
105662306a36Sopenharmony_ci				  cmd->prio_attr, cmd->sense_iu.sense,
105762306a36Sopenharmony_ci				  cmd->unpacked_lun, NULL);
105862306a36Sopenharmony_ci		goto out;
105962306a36Sopenharmony_ci	}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, cmd->cmd_buf,
106262306a36Sopenharmony_ci			  cmd->sense_iu.sense, cmd->unpacked_lun, 0,
106362306a36Sopenharmony_ci			  cmd->prio_attr, dir, flags);
106462306a36Sopenharmony_ci	return;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ciout:
106762306a36Sopenharmony_ci	transport_send_check_condition_and_sense(se_cmd,
106862306a36Sopenharmony_ci			TCM_UNSUPPORTED_SCSI_OPCODE, 1);
106962306a36Sopenharmony_ci	transport_generic_free_cmd(&cmd->se_cmd, 0);
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic struct usbg_cmd *usbg_get_cmd(struct f_uas *fu,
107362306a36Sopenharmony_ci		struct tcm_usbg_nexus *tv_nexus, u32 scsi_tag)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	struct se_session *se_sess = tv_nexus->tvn_se_sess;
107662306a36Sopenharmony_ci	struct usbg_cmd *cmd;
107762306a36Sopenharmony_ci	int tag, cpu;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu);
108062306a36Sopenharmony_ci	if (tag < 0)
108162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	cmd = &((struct usbg_cmd *)se_sess->sess_cmd_map)[tag];
108462306a36Sopenharmony_ci	memset(cmd, 0, sizeof(*cmd));
108562306a36Sopenharmony_ci	cmd->se_cmd.map_tag = tag;
108662306a36Sopenharmony_ci	cmd->se_cmd.map_cpu = cpu;
108762306a36Sopenharmony_ci	cmd->se_cmd.tag = cmd->tag = scsi_tag;
108862306a36Sopenharmony_ci	cmd->fu = fu;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	return cmd;
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic void usbg_release_cmd(struct se_cmd *);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_cistatic int usbg_submit_command(struct f_uas *fu,
109662306a36Sopenharmony_ci		void *cmdbuf, unsigned int len)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	struct command_iu *cmd_iu = cmdbuf;
109962306a36Sopenharmony_ci	struct usbg_cmd *cmd;
110062306a36Sopenharmony_ci	struct usbg_tpg *tpg = fu->tpg;
110162306a36Sopenharmony_ci	struct tcm_usbg_nexus *tv_nexus;
110262306a36Sopenharmony_ci	u32 cmd_len;
110362306a36Sopenharmony_ci	u16 scsi_tag;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	if (cmd_iu->iu_id != IU_ID_COMMAND) {
110662306a36Sopenharmony_ci		pr_err("Unsupported type %d\n", cmd_iu->iu_id);
110762306a36Sopenharmony_ci		return -EINVAL;
110862306a36Sopenharmony_ci	}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	tv_nexus = tpg->tpg_nexus;
111162306a36Sopenharmony_ci	if (!tv_nexus) {
111262306a36Sopenharmony_ci		pr_err("Missing nexus, ignoring command\n");
111362306a36Sopenharmony_ci		return -EINVAL;
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	cmd_len = (cmd_iu->len & ~0x3) + 16;
111762306a36Sopenharmony_ci	if (cmd_len > USBG_MAX_CMD)
111862306a36Sopenharmony_ci		return -EINVAL;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	scsi_tag = be16_to_cpup(&cmd_iu->tag);
112162306a36Sopenharmony_ci	cmd = usbg_get_cmd(fu, tv_nexus, scsi_tag);
112262306a36Sopenharmony_ci	if (IS_ERR(cmd)) {
112362306a36Sopenharmony_ci		pr_err("usbg_get_cmd failed\n");
112462306a36Sopenharmony_ci		return -ENOMEM;
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci	memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (fu->flags & USBG_USE_STREAMS) {
112962306a36Sopenharmony_ci		if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
113062306a36Sopenharmony_ci			goto err;
113162306a36Sopenharmony_ci		if (!cmd->tag)
113262306a36Sopenharmony_ci			cmd->stream = &fu->stream[0];
113362306a36Sopenharmony_ci		else
113462306a36Sopenharmony_ci			cmd->stream = &fu->stream[cmd->tag - 1];
113562306a36Sopenharmony_ci	} else {
113662306a36Sopenharmony_ci		cmd->stream = &fu->stream[0];
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	switch (cmd_iu->prio_attr & 0x7) {
114062306a36Sopenharmony_ci	case UAS_HEAD_TAG:
114162306a36Sopenharmony_ci		cmd->prio_attr = TCM_HEAD_TAG;
114262306a36Sopenharmony_ci		break;
114362306a36Sopenharmony_ci	case UAS_ORDERED_TAG:
114462306a36Sopenharmony_ci		cmd->prio_attr = TCM_ORDERED_TAG;
114562306a36Sopenharmony_ci		break;
114662306a36Sopenharmony_ci	case UAS_ACA:
114762306a36Sopenharmony_ci		cmd->prio_attr = TCM_ACA_TAG;
114862306a36Sopenharmony_ci		break;
114962306a36Sopenharmony_ci	default:
115062306a36Sopenharmony_ci		pr_debug_once("Unsupported prio_attr: %02x.\n",
115162306a36Sopenharmony_ci				cmd_iu->prio_attr);
115262306a36Sopenharmony_ci		fallthrough;
115362306a36Sopenharmony_ci	case UAS_SIMPLE_TAG:
115462306a36Sopenharmony_ci		cmd->prio_attr = TCM_SIMPLE_TAG;
115562306a36Sopenharmony_ci		break;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	INIT_WORK(&cmd->work, usbg_cmd_work);
116162306a36Sopenharmony_ci	queue_work(tpg->workqueue, &cmd->work);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	return 0;
116462306a36Sopenharmony_cierr:
116562306a36Sopenharmony_ci	usbg_release_cmd(&cmd->se_cmd);
116662306a36Sopenharmony_ci	return -EINVAL;
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic void bot_cmd_work(struct work_struct *work)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
117262306a36Sopenharmony_ci	struct se_cmd *se_cmd;
117362306a36Sopenharmony_ci	struct tcm_usbg_nexus *tv_nexus;
117462306a36Sopenharmony_ci	struct usbg_tpg *tpg;
117562306a36Sopenharmony_ci	int dir;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	se_cmd = &cmd->se_cmd;
117862306a36Sopenharmony_ci	tpg = cmd->fu->tpg;
117962306a36Sopenharmony_ci	tv_nexus = tpg->tpg_nexus;
118062306a36Sopenharmony_ci	dir = get_cmd_dir(cmd->cmd_buf);
118162306a36Sopenharmony_ci	if (dir < 0) {
118262306a36Sopenharmony_ci		__target_init_cmd(se_cmd,
118362306a36Sopenharmony_ci				  tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
118462306a36Sopenharmony_ci				  tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
118562306a36Sopenharmony_ci				  cmd->prio_attr, cmd->sense_iu.sense,
118662306a36Sopenharmony_ci				  cmd->unpacked_lun, NULL);
118762306a36Sopenharmony_ci		goto out;
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
119162306a36Sopenharmony_ci			  cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
119262306a36Sopenharmony_ci			  cmd->data_len, cmd->prio_attr, dir, 0);
119362306a36Sopenharmony_ci	return;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ciout:
119662306a36Sopenharmony_ci	transport_send_check_condition_and_sense(se_cmd,
119762306a36Sopenharmony_ci				TCM_UNSUPPORTED_SCSI_OPCODE, 1);
119862306a36Sopenharmony_ci	transport_generic_free_cmd(&cmd->se_cmd, 0);
119962306a36Sopenharmony_ci}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_cistatic int bot_submit_command(struct f_uas *fu,
120262306a36Sopenharmony_ci		void *cmdbuf, unsigned int len)
120362306a36Sopenharmony_ci{
120462306a36Sopenharmony_ci	struct bulk_cb_wrap *cbw = cmdbuf;
120562306a36Sopenharmony_ci	struct usbg_cmd *cmd;
120662306a36Sopenharmony_ci	struct usbg_tpg *tpg = fu->tpg;
120762306a36Sopenharmony_ci	struct tcm_usbg_nexus *tv_nexus;
120862306a36Sopenharmony_ci	u32 cmd_len;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
121162306a36Sopenharmony_ci		pr_err("Wrong signature on CBW\n");
121262306a36Sopenharmony_ci		return -EINVAL;
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci	if (len != 31) {
121562306a36Sopenharmony_ci		pr_err("Wrong length for CBW\n");
121662306a36Sopenharmony_ci		return -EINVAL;
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	cmd_len = cbw->Length;
122062306a36Sopenharmony_ci	if (cmd_len < 1 || cmd_len > 16)
122162306a36Sopenharmony_ci		return -EINVAL;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	tv_nexus = tpg->tpg_nexus;
122462306a36Sopenharmony_ci	if (!tv_nexus) {
122562306a36Sopenharmony_ci		pr_err("Missing nexus, ignoring command\n");
122662306a36Sopenharmony_ci		return -ENODEV;
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	cmd = usbg_get_cmd(fu, tv_nexus, cbw->Tag);
123062306a36Sopenharmony_ci	if (IS_ERR(cmd)) {
123162306a36Sopenharmony_ci		pr_err("usbg_get_cmd failed\n");
123262306a36Sopenharmony_ci		return -ENOMEM;
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci	memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	cmd->bot_tag = cbw->Tag;
123762306a36Sopenharmony_ci	cmd->prio_attr = TCM_SIMPLE_TAG;
123862306a36Sopenharmony_ci	cmd->unpacked_lun = cbw->Lun;
123962306a36Sopenharmony_ci	cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
124062306a36Sopenharmony_ci	cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
124162306a36Sopenharmony_ci	cmd->se_cmd.tag = le32_to_cpu(cmd->bot_tag);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	INIT_WORK(&cmd->work, bot_cmd_work);
124462306a36Sopenharmony_ci	queue_work(tpg->workqueue, &cmd->work);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	return 0;
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci/* Start fabric.c code */
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic int usbg_check_true(struct se_portal_group *se_tpg)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	return 1;
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	struct usbg_tpg *tpg = container_of(se_tpg,
125962306a36Sopenharmony_ci				struct usbg_tpg, se_tpg);
126062306a36Sopenharmony_ci	struct usbg_tport *tport = tpg->tport;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	return &tport->tport_name[0];
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic u16 usbg_get_tag(struct se_portal_group *se_tpg)
126662306a36Sopenharmony_ci{
126762306a36Sopenharmony_ci	struct usbg_tpg *tpg = container_of(se_tpg,
126862306a36Sopenharmony_ci				struct usbg_tpg, se_tpg);
126962306a36Sopenharmony_ci	return tpg->tport_tpgt;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cistatic void usbg_release_cmd(struct se_cmd *se_cmd)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
127562306a36Sopenharmony_ci			se_cmd);
127662306a36Sopenharmony_ci	struct se_session *se_sess = se_cmd->se_sess;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	kfree(cmd->data_buf);
127962306a36Sopenharmony_ci	target_free_tag(se_sess, se_cmd);
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic void usbg_queue_tm_rsp(struct se_cmd *se_cmd)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_cistatic void usbg_aborted_task(struct se_cmd *se_cmd)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_cistatic const char *usbg_check_wwn(const char *name)
129162306a36Sopenharmony_ci{
129262306a36Sopenharmony_ci	const char *n;
129362306a36Sopenharmony_ci	unsigned int len;
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	n = strstr(name, "naa.");
129662306a36Sopenharmony_ci	if (!n)
129762306a36Sopenharmony_ci		return NULL;
129862306a36Sopenharmony_ci	n += 4;
129962306a36Sopenharmony_ci	len = strlen(n);
130062306a36Sopenharmony_ci	if (len == 0 || len > USBG_NAMELEN - 1)
130162306a36Sopenharmony_ci		return NULL;
130262306a36Sopenharmony_ci	return n;
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cistatic int usbg_init_nodeacl(struct se_node_acl *se_nacl, const char *name)
130662306a36Sopenharmony_ci{
130762306a36Sopenharmony_ci	if (!usbg_check_wwn(name))
130862306a36Sopenharmony_ci		return -EINVAL;
130962306a36Sopenharmony_ci	return 0;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_cistatic struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn,
131362306a36Sopenharmony_ci					     const char *name)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
131662306a36Sopenharmony_ci			tport_wwn);
131762306a36Sopenharmony_ci	struct usbg_tpg *tpg;
131862306a36Sopenharmony_ci	unsigned long tpgt;
131962306a36Sopenharmony_ci	int ret;
132062306a36Sopenharmony_ci	struct f_tcm_opts *opts;
132162306a36Sopenharmony_ci	unsigned i;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (strstr(name, "tpgt_") != name)
132462306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
132562306a36Sopenharmony_ci	if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
132662306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
132762306a36Sopenharmony_ci	ret = -ENODEV;
132862306a36Sopenharmony_ci	mutex_lock(&tpg_instances_lock);
132962306a36Sopenharmony_ci	for (i = 0; i < TPG_INSTANCES; ++i)
133062306a36Sopenharmony_ci		if (tpg_instances[i].func_inst && !tpg_instances[i].tpg)
133162306a36Sopenharmony_ci			break;
133262306a36Sopenharmony_ci	if (i == TPG_INSTANCES)
133362306a36Sopenharmony_ci		goto unlock_inst;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	opts = container_of(tpg_instances[i].func_inst, struct f_tcm_opts,
133662306a36Sopenharmony_ci		func_inst);
133762306a36Sopenharmony_ci	mutex_lock(&opts->dep_lock);
133862306a36Sopenharmony_ci	if (!opts->ready)
133962306a36Sopenharmony_ci		goto unlock_dep;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	if (opts->has_dep) {
134262306a36Sopenharmony_ci		if (!try_module_get(opts->dependent))
134362306a36Sopenharmony_ci			goto unlock_dep;
134462306a36Sopenharmony_ci	} else {
134562306a36Sopenharmony_ci		ret = configfs_depend_item_unlocked(
134662306a36Sopenharmony_ci			wwn->wwn_group.cg_subsys,
134762306a36Sopenharmony_ci			&opts->func_inst.group.cg_item);
134862306a36Sopenharmony_ci		if (ret)
134962306a36Sopenharmony_ci			goto unlock_dep;
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
135362306a36Sopenharmony_ci	ret = -ENOMEM;
135462306a36Sopenharmony_ci	if (!tpg)
135562306a36Sopenharmony_ci		goto unref_dep;
135662306a36Sopenharmony_ci	mutex_init(&tpg->tpg_mutex);
135762306a36Sopenharmony_ci	atomic_set(&tpg->tpg_port_count, 0);
135862306a36Sopenharmony_ci	tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
135962306a36Sopenharmony_ci	if (!tpg->workqueue)
136062306a36Sopenharmony_ci		goto free_tpg;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	tpg->tport = tport;
136362306a36Sopenharmony_ci	tpg->tport_tpgt = tpgt;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	/*
136662306a36Sopenharmony_ci	 * SPC doesn't assign a protocol identifier for USB-SCSI, so we
136762306a36Sopenharmony_ci	 * pretend to be SAS..
136862306a36Sopenharmony_ci	 */
136962306a36Sopenharmony_ci	ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SAS);
137062306a36Sopenharmony_ci	if (ret < 0)
137162306a36Sopenharmony_ci		goto free_workqueue;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	tpg_instances[i].tpg = tpg;
137462306a36Sopenharmony_ci	tpg->fi = tpg_instances[i].func_inst;
137562306a36Sopenharmony_ci	mutex_unlock(&opts->dep_lock);
137662306a36Sopenharmony_ci	mutex_unlock(&tpg_instances_lock);
137762306a36Sopenharmony_ci	return &tpg->se_tpg;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_cifree_workqueue:
138062306a36Sopenharmony_ci	destroy_workqueue(tpg->workqueue);
138162306a36Sopenharmony_cifree_tpg:
138262306a36Sopenharmony_ci	kfree(tpg);
138362306a36Sopenharmony_ciunref_dep:
138462306a36Sopenharmony_ci	if (opts->has_dep)
138562306a36Sopenharmony_ci		module_put(opts->dependent);
138662306a36Sopenharmony_ci	else
138762306a36Sopenharmony_ci		configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item);
138862306a36Sopenharmony_ciunlock_dep:
138962306a36Sopenharmony_ci	mutex_unlock(&opts->dep_lock);
139062306a36Sopenharmony_ciunlock_inst:
139162306a36Sopenharmony_ci	mutex_unlock(&tpg_instances_lock);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	return ERR_PTR(ret);
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistatic int tcm_usbg_drop_nexus(struct usbg_tpg *);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic void usbg_drop_tpg(struct se_portal_group *se_tpg)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	struct usbg_tpg *tpg = container_of(se_tpg,
140162306a36Sopenharmony_ci				struct usbg_tpg, se_tpg);
140262306a36Sopenharmony_ci	unsigned i;
140362306a36Sopenharmony_ci	struct f_tcm_opts *opts;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	tcm_usbg_drop_nexus(tpg);
140662306a36Sopenharmony_ci	core_tpg_deregister(se_tpg);
140762306a36Sopenharmony_ci	destroy_workqueue(tpg->workqueue);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	mutex_lock(&tpg_instances_lock);
141062306a36Sopenharmony_ci	for (i = 0; i < TPG_INSTANCES; ++i)
141162306a36Sopenharmony_ci		if (tpg_instances[i].tpg == tpg)
141262306a36Sopenharmony_ci			break;
141362306a36Sopenharmony_ci	if (i < TPG_INSTANCES) {
141462306a36Sopenharmony_ci		tpg_instances[i].tpg = NULL;
141562306a36Sopenharmony_ci		opts = container_of(tpg_instances[i].func_inst,
141662306a36Sopenharmony_ci			struct f_tcm_opts, func_inst);
141762306a36Sopenharmony_ci		mutex_lock(&opts->dep_lock);
141862306a36Sopenharmony_ci		if (opts->has_dep)
141962306a36Sopenharmony_ci			module_put(opts->dependent);
142062306a36Sopenharmony_ci		else
142162306a36Sopenharmony_ci			configfs_undepend_item_unlocked(
142262306a36Sopenharmony_ci				&opts->func_inst.group.cg_item);
142362306a36Sopenharmony_ci		mutex_unlock(&opts->dep_lock);
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci	mutex_unlock(&tpg_instances_lock);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	kfree(tpg);
142862306a36Sopenharmony_ci}
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_cistatic struct se_wwn *usbg_make_tport(
143162306a36Sopenharmony_ci	struct target_fabric_configfs *tf,
143262306a36Sopenharmony_ci	struct config_group *group,
143362306a36Sopenharmony_ci	const char *name)
143462306a36Sopenharmony_ci{
143562306a36Sopenharmony_ci	struct usbg_tport *tport;
143662306a36Sopenharmony_ci	const char *wnn_name;
143762306a36Sopenharmony_ci	u64 wwpn = 0;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	wnn_name = usbg_check_wwn(name);
144062306a36Sopenharmony_ci	if (!wnn_name)
144162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
144462306a36Sopenharmony_ci	if (!(tport))
144562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	tport->tport_wwpn = wwpn;
144862306a36Sopenharmony_ci	snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name);
144962306a36Sopenharmony_ci	return &tport->tport_wwn;
145062306a36Sopenharmony_ci}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_cistatic void usbg_drop_tport(struct se_wwn *wwn)
145362306a36Sopenharmony_ci{
145462306a36Sopenharmony_ci	struct usbg_tport *tport = container_of(wwn,
145562306a36Sopenharmony_ci				struct usbg_tport, tport_wwn);
145662306a36Sopenharmony_ci	kfree(tport);
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci/*
146062306a36Sopenharmony_ci * If somebody feels like dropping the version property, go ahead.
146162306a36Sopenharmony_ci */
146262306a36Sopenharmony_cistatic ssize_t usbg_wwn_version_show(struct config_item *item,  char *page)
146362306a36Sopenharmony_ci{
146462306a36Sopenharmony_ci	return sprintf(page, "usb-gadget fabric module\n");
146562306a36Sopenharmony_ci}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ciCONFIGFS_ATTR_RO(usbg_wwn_, version);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cistatic struct configfs_attribute *usbg_wwn_attrs[] = {
147062306a36Sopenharmony_ci	&usbg_wwn_attr_version,
147162306a36Sopenharmony_ci	NULL,
147262306a36Sopenharmony_ci};
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic int usbg_attach(struct usbg_tpg *);
147562306a36Sopenharmony_cistatic void usbg_detach(struct usbg_tpg *);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_cistatic int usbg_enable_tpg(struct se_portal_group *se_tpg, bool enable)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
148062306a36Sopenharmony_ci	int ret = 0;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	if (enable)
148362306a36Sopenharmony_ci		ret = usbg_attach(tpg);
148462306a36Sopenharmony_ci	else
148562306a36Sopenharmony_ci		usbg_detach(tpg);
148662306a36Sopenharmony_ci	if (ret)
148762306a36Sopenharmony_ci		return ret;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	tpg->gadget_connect = enable;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	return 0;
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_cistatic ssize_t tcm_usbg_tpg_nexus_show(struct config_item *item, char *page)
149562306a36Sopenharmony_ci{
149662306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);
149762306a36Sopenharmony_ci	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
149862306a36Sopenharmony_ci	struct tcm_usbg_nexus *tv_nexus;
149962306a36Sopenharmony_ci	ssize_t ret;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	mutex_lock(&tpg->tpg_mutex);
150262306a36Sopenharmony_ci	tv_nexus = tpg->tpg_nexus;
150362306a36Sopenharmony_ci	if (!tv_nexus) {
150462306a36Sopenharmony_ci		ret = -ENODEV;
150562306a36Sopenharmony_ci		goto out;
150662306a36Sopenharmony_ci	}
150762306a36Sopenharmony_ci	ret = snprintf(page, PAGE_SIZE, "%s\n",
150862306a36Sopenharmony_ci			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
150962306a36Sopenharmony_ciout:
151062306a36Sopenharmony_ci	mutex_unlock(&tpg->tpg_mutex);
151162306a36Sopenharmony_ci	return ret;
151262306a36Sopenharmony_ci}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_cistatic int usbg_alloc_sess_cb(struct se_portal_group *se_tpg,
151562306a36Sopenharmony_ci			      struct se_session *se_sess, void *p)
151662306a36Sopenharmony_ci{
151762306a36Sopenharmony_ci	struct usbg_tpg *tpg = container_of(se_tpg,
151862306a36Sopenharmony_ci				struct usbg_tpg, se_tpg);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	tpg->tpg_nexus = p;
152162306a36Sopenharmony_ci	return 0;
152262306a36Sopenharmony_ci}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_cistatic int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
152562306a36Sopenharmony_ci{
152662306a36Sopenharmony_ci	struct tcm_usbg_nexus *tv_nexus;
152762306a36Sopenharmony_ci	int ret = 0;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	mutex_lock(&tpg->tpg_mutex);
153062306a36Sopenharmony_ci	if (tpg->tpg_nexus) {
153162306a36Sopenharmony_ci		ret = -EEXIST;
153262306a36Sopenharmony_ci		pr_debug("tpg->tpg_nexus already exists\n");
153362306a36Sopenharmony_ci		goto out_unlock;
153462306a36Sopenharmony_ci	}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
153762306a36Sopenharmony_ci	if (!tv_nexus) {
153862306a36Sopenharmony_ci		ret = -ENOMEM;
153962306a36Sopenharmony_ci		goto out_unlock;
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	tv_nexus->tvn_se_sess = target_setup_session(&tpg->se_tpg,
154362306a36Sopenharmony_ci						     USB_G_DEFAULT_SESSION_TAGS,
154462306a36Sopenharmony_ci						     sizeof(struct usbg_cmd),
154562306a36Sopenharmony_ci						     TARGET_PROT_NORMAL, name,
154662306a36Sopenharmony_ci						     tv_nexus, usbg_alloc_sess_cb);
154762306a36Sopenharmony_ci	if (IS_ERR(tv_nexus->tvn_se_sess)) {
154862306a36Sopenharmony_ci#define MAKE_NEXUS_MSG "core_tpg_check_initiator_node_acl() failed for %s\n"
154962306a36Sopenharmony_ci		pr_debug(MAKE_NEXUS_MSG, name);
155062306a36Sopenharmony_ci#undef MAKE_NEXUS_MSG
155162306a36Sopenharmony_ci		ret = PTR_ERR(tv_nexus->tvn_se_sess);
155262306a36Sopenharmony_ci		kfree(tv_nexus);
155362306a36Sopenharmony_ci	}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ciout_unlock:
155662306a36Sopenharmony_ci	mutex_unlock(&tpg->tpg_mutex);
155762306a36Sopenharmony_ci	return ret;
155862306a36Sopenharmony_ci}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_cistatic int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	struct se_session *se_sess;
156362306a36Sopenharmony_ci	struct tcm_usbg_nexus *tv_nexus;
156462306a36Sopenharmony_ci	int ret = -ENODEV;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	mutex_lock(&tpg->tpg_mutex);
156762306a36Sopenharmony_ci	tv_nexus = tpg->tpg_nexus;
156862306a36Sopenharmony_ci	if (!tv_nexus)
156962306a36Sopenharmony_ci		goto out;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	se_sess = tv_nexus->tvn_se_sess;
157262306a36Sopenharmony_ci	if (!se_sess)
157362306a36Sopenharmony_ci		goto out;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (atomic_read(&tpg->tpg_port_count)) {
157662306a36Sopenharmony_ci		ret = -EPERM;
157762306a36Sopenharmony_ci#define MSG "Unable to remove Host I_T Nexus with active TPG port count: %d\n"
157862306a36Sopenharmony_ci		pr_err(MSG, atomic_read(&tpg->tpg_port_count));
157962306a36Sopenharmony_ci#undef MSG
158062306a36Sopenharmony_ci		goto out;
158162306a36Sopenharmony_ci	}
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
158462306a36Sopenharmony_ci			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
158562306a36Sopenharmony_ci	/*
158662306a36Sopenharmony_ci	 * Release the SCSI I_T Nexus to the emulated vHost Target Port
158762306a36Sopenharmony_ci	 */
158862306a36Sopenharmony_ci	target_remove_session(se_sess);
158962306a36Sopenharmony_ci	tpg->tpg_nexus = NULL;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	kfree(tv_nexus);
159262306a36Sopenharmony_ci	ret = 0;
159362306a36Sopenharmony_ciout:
159462306a36Sopenharmony_ci	mutex_unlock(&tpg->tpg_mutex);
159562306a36Sopenharmony_ci	return ret;
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_cistatic ssize_t tcm_usbg_tpg_nexus_store(struct config_item *item,
159962306a36Sopenharmony_ci		const char *page, size_t count)
160062306a36Sopenharmony_ci{
160162306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);
160262306a36Sopenharmony_ci	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
160362306a36Sopenharmony_ci	unsigned char i_port[USBG_NAMELEN], *ptr;
160462306a36Sopenharmony_ci	int ret;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	if (!strncmp(page, "NULL", 4)) {
160762306a36Sopenharmony_ci		ret = tcm_usbg_drop_nexus(tpg);
160862306a36Sopenharmony_ci		return (!ret) ? count : ret;
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci	if (strlen(page) >= USBG_NAMELEN) {
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci#define NEXUS_STORE_MSG "Emulated NAA Sas Address: %s, exceeds max: %d\n"
161362306a36Sopenharmony_ci		pr_err(NEXUS_STORE_MSG, page, USBG_NAMELEN);
161462306a36Sopenharmony_ci#undef NEXUS_STORE_MSG
161562306a36Sopenharmony_ci		return -EINVAL;
161662306a36Sopenharmony_ci	}
161762306a36Sopenharmony_ci	snprintf(i_port, USBG_NAMELEN, "%s", page);
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	ptr = strstr(i_port, "naa.");
162062306a36Sopenharmony_ci	if (!ptr) {
162162306a36Sopenharmony_ci		pr_err("Missing 'naa.' prefix\n");
162262306a36Sopenharmony_ci		return -EINVAL;
162362306a36Sopenharmony_ci	}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	if (i_port[strlen(i_port) - 1] == '\n')
162662306a36Sopenharmony_ci		i_port[strlen(i_port) - 1] = '\0';
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	ret = tcm_usbg_make_nexus(tpg, &i_port[0]);
162962306a36Sopenharmony_ci	if (ret < 0)
163062306a36Sopenharmony_ci		return ret;
163162306a36Sopenharmony_ci	return count;
163262306a36Sopenharmony_ci}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ciCONFIGFS_ATTR(tcm_usbg_tpg_, nexus);
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_cistatic struct configfs_attribute *usbg_base_attrs[] = {
163762306a36Sopenharmony_ci	&tcm_usbg_tpg_attr_nexus,
163862306a36Sopenharmony_ci	NULL,
163962306a36Sopenharmony_ci};
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_cistatic int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
164262306a36Sopenharmony_ci{
164362306a36Sopenharmony_ci	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	atomic_inc(&tpg->tpg_port_count);
164662306a36Sopenharmony_ci	smp_mb__after_atomic();
164762306a36Sopenharmony_ci	return 0;
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cistatic void usbg_port_unlink(struct se_portal_group *se_tpg,
165162306a36Sopenharmony_ci		struct se_lun *se_lun)
165262306a36Sopenharmony_ci{
165362306a36Sopenharmony_ci	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	atomic_dec(&tpg->tpg_port_count);
165662306a36Sopenharmony_ci	smp_mb__after_atomic();
165762306a36Sopenharmony_ci}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_cistatic int usbg_check_stop_free(struct se_cmd *se_cmd)
166062306a36Sopenharmony_ci{
166162306a36Sopenharmony_ci	return target_put_sess_cmd(se_cmd);
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_cistatic const struct target_core_fabric_ops usbg_ops = {
166562306a36Sopenharmony_ci	.module				= THIS_MODULE,
166662306a36Sopenharmony_ci	.fabric_name			= "usb_gadget",
166762306a36Sopenharmony_ci	.tpg_get_wwn			= usbg_get_fabric_wwn,
166862306a36Sopenharmony_ci	.tpg_get_tag			= usbg_get_tag,
166962306a36Sopenharmony_ci	.tpg_check_demo_mode		= usbg_check_true,
167062306a36Sopenharmony_ci	.release_cmd			= usbg_release_cmd,
167162306a36Sopenharmony_ci	.sess_get_initiator_sid		= NULL,
167262306a36Sopenharmony_ci	.write_pending			= usbg_send_write_request,
167362306a36Sopenharmony_ci	.queue_data_in			= usbg_send_read_response,
167462306a36Sopenharmony_ci	.queue_status			= usbg_send_status_response,
167562306a36Sopenharmony_ci	.queue_tm_rsp			= usbg_queue_tm_rsp,
167662306a36Sopenharmony_ci	.aborted_task			= usbg_aborted_task,
167762306a36Sopenharmony_ci	.check_stop_free		= usbg_check_stop_free,
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	.fabric_make_wwn		= usbg_make_tport,
168062306a36Sopenharmony_ci	.fabric_drop_wwn		= usbg_drop_tport,
168162306a36Sopenharmony_ci	.fabric_make_tpg		= usbg_make_tpg,
168262306a36Sopenharmony_ci	.fabric_enable_tpg		= usbg_enable_tpg,
168362306a36Sopenharmony_ci	.fabric_drop_tpg		= usbg_drop_tpg,
168462306a36Sopenharmony_ci	.fabric_post_link		= usbg_port_link,
168562306a36Sopenharmony_ci	.fabric_pre_unlink		= usbg_port_unlink,
168662306a36Sopenharmony_ci	.fabric_init_nodeacl		= usbg_init_nodeacl,
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	.tfc_wwn_attrs			= usbg_wwn_attrs,
168962306a36Sopenharmony_ci	.tfc_tpg_base_attrs		= usbg_base_attrs,
169062306a36Sopenharmony_ci};
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci/* Start gadget.c code */
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_cistatic struct usb_interface_descriptor bot_intf_desc = {
169562306a36Sopenharmony_ci	.bLength =              sizeof(bot_intf_desc),
169662306a36Sopenharmony_ci	.bDescriptorType =      USB_DT_INTERFACE,
169762306a36Sopenharmony_ci	.bNumEndpoints =        2,
169862306a36Sopenharmony_ci	.bAlternateSetting =	USB_G_ALT_INT_BBB,
169962306a36Sopenharmony_ci	.bInterfaceClass =      USB_CLASS_MASS_STORAGE,
170062306a36Sopenharmony_ci	.bInterfaceSubClass =   USB_SC_SCSI,
170162306a36Sopenharmony_ci	.bInterfaceProtocol =   USB_PR_BULK,
170262306a36Sopenharmony_ci};
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_cistatic struct usb_interface_descriptor uasp_intf_desc = {
170562306a36Sopenharmony_ci	.bLength =		sizeof(uasp_intf_desc),
170662306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_INTERFACE,
170762306a36Sopenharmony_ci	.bNumEndpoints =	4,
170862306a36Sopenharmony_ci	.bAlternateSetting =	USB_G_ALT_INT_UAS,
170962306a36Sopenharmony_ci	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
171062306a36Sopenharmony_ci	.bInterfaceSubClass =	USB_SC_SCSI,
171162306a36Sopenharmony_ci	.bInterfaceProtocol =	USB_PR_UAS,
171262306a36Sopenharmony_ci};
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_bi_desc = {
171562306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
171662306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
171762306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_IN,
171862306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
171962306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(512),
172062306a36Sopenharmony_ci};
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_fs_bi_desc = {
172362306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
172462306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
172562306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_IN,
172662306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
172762306a36Sopenharmony_ci};
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_cistatic struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
173062306a36Sopenharmony_ci	.bLength =		sizeof(uasp_bi_pipe_desc),
173162306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_PIPE_USAGE,
173262306a36Sopenharmony_ci	.bPipeID =		DATA_IN_PIPE_ID,
173362306a36Sopenharmony_ci};
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_ss_bi_desc = {
173662306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
173762306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
173862306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_IN,
173962306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
174062306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(1024),
174162306a36Sopenharmony_ci};
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
174462306a36Sopenharmony_ci	.bLength =		sizeof(uasp_bi_ep_comp_desc),
174562306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
174662306a36Sopenharmony_ci	.bMaxBurst =		0,
174762306a36Sopenharmony_ci	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
174862306a36Sopenharmony_ci	.wBytesPerInterval =	0,
174962306a36Sopenharmony_ci};
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
175262306a36Sopenharmony_ci	.bLength =		sizeof(bot_bi_ep_comp_desc),
175362306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
175462306a36Sopenharmony_ci	.bMaxBurst =		0,
175562306a36Sopenharmony_ci};
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_bo_desc = {
175862306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
175962306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
176062306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_OUT,
176162306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
176262306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(512),
176362306a36Sopenharmony_ci};
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_fs_bo_desc = {
176662306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
176762306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
176862306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_OUT,
176962306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
177062306a36Sopenharmony_ci};
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_cistatic struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
177362306a36Sopenharmony_ci	.bLength =		sizeof(uasp_bo_pipe_desc),
177462306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_PIPE_USAGE,
177562306a36Sopenharmony_ci	.bPipeID =		DATA_OUT_PIPE_ID,
177662306a36Sopenharmony_ci};
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_ss_bo_desc = {
177962306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
178062306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
178162306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_OUT,
178262306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
178362306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(0x400),
178462306a36Sopenharmony_ci};
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
178762306a36Sopenharmony_ci	.bLength =		sizeof(uasp_bo_ep_comp_desc),
178862306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
178962306a36Sopenharmony_ci	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
179062306a36Sopenharmony_ci};
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
179362306a36Sopenharmony_ci	.bLength =		sizeof(bot_bo_ep_comp_desc),
179462306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
179562306a36Sopenharmony_ci};
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_status_desc = {
179862306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
179962306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
180062306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_IN,
180162306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
180262306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(512),
180362306a36Sopenharmony_ci};
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_fs_status_desc = {
180662306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
180762306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
180862306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_IN,
180962306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
181062306a36Sopenharmony_ci};
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_cistatic struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
181362306a36Sopenharmony_ci	.bLength =		sizeof(uasp_status_pipe_desc),
181462306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_PIPE_USAGE,
181562306a36Sopenharmony_ci	.bPipeID =		STATUS_PIPE_ID,
181662306a36Sopenharmony_ci};
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_ss_status_desc = {
181962306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
182062306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
182162306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_IN,
182262306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
182362306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(1024),
182462306a36Sopenharmony_ci};
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
182762306a36Sopenharmony_ci	.bLength =		sizeof(uasp_status_in_ep_comp_desc),
182862306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
182962306a36Sopenharmony_ci	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
183062306a36Sopenharmony_ci};
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_cmd_desc = {
183362306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
183462306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
183562306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_OUT,
183662306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
183762306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(512),
183862306a36Sopenharmony_ci};
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
184162306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
184262306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
184362306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_OUT,
184462306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
184562306a36Sopenharmony_ci};
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_cistatic struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
184862306a36Sopenharmony_ci	.bLength =		sizeof(uasp_cmd_pipe_desc),
184962306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_PIPE_USAGE,
185062306a36Sopenharmony_ci	.bPipeID =		CMD_PIPE_ID,
185162306a36Sopenharmony_ci};
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
185462306a36Sopenharmony_ci	.bLength =		USB_DT_ENDPOINT_SIZE,
185562306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_ENDPOINT,
185662306a36Sopenharmony_ci	.bEndpointAddress =	USB_DIR_OUT,
185762306a36Sopenharmony_ci	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
185862306a36Sopenharmony_ci	.wMaxPacketSize =	cpu_to_le16(1024),
185962306a36Sopenharmony_ci};
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
186262306a36Sopenharmony_ci	.bLength =		sizeof(uasp_cmd_comp_desc),
186362306a36Sopenharmony_ci	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
186462306a36Sopenharmony_ci};
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_cistatic struct usb_descriptor_header *uasp_fs_function_desc[] = {
186762306a36Sopenharmony_ci	(struct usb_descriptor_header *) &bot_intf_desc,
186862306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_fs_bi_desc,
186962306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_fs_bo_desc,
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_intf_desc,
187262306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_fs_bi_desc,
187362306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
187462306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_fs_bo_desc,
187562306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
187662306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_fs_status_desc,
187762306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
187862306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_fs_cmd_desc,
187962306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
188062306a36Sopenharmony_ci	NULL,
188162306a36Sopenharmony_ci};
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_cistatic struct usb_descriptor_header *uasp_hs_function_desc[] = {
188462306a36Sopenharmony_ci	(struct usb_descriptor_header *) &bot_intf_desc,
188562306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bi_desc,
188662306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bo_desc,
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_intf_desc,
188962306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bi_desc,
189062306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
189162306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bo_desc,
189262306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
189362306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_status_desc,
189462306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
189562306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_cmd_desc,
189662306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
189762306a36Sopenharmony_ci	NULL,
189862306a36Sopenharmony_ci};
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_cistatic struct usb_descriptor_header *uasp_ss_function_desc[] = {
190162306a36Sopenharmony_ci	(struct usb_descriptor_header *) &bot_intf_desc,
190262306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_ss_bi_desc,
190362306a36Sopenharmony_ci	(struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
190462306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_ss_bo_desc,
190562306a36Sopenharmony_ci	(struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_intf_desc,
190862306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_ss_bi_desc,
190962306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
191062306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
191162306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_ss_bo_desc,
191262306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
191362306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
191462306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_ss_status_desc,
191562306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
191662306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
191762306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_ss_cmd_desc,
191862306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_cmd_comp_desc,
191962306a36Sopenharmony_ci	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
192062306a36Sopenharmony_ci	NULL,
192162306a36Sopenharmony_ci};
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_cistatic struct usb_string	tcm_us_strings[] = {
192462306a36Sopenharmony_ci	[USB_G_STR_INT_UAS].s		= "USB Attached SCSI",
192562306a36Sopenharmony_ci	[USB_G_STR_INT_BBB].s		= "Bulk Only Transport",
192662306a36Sopenharmony_ci	{ },
192762306a36Sopenharmony_ci};
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_cistatic struct usb_gadget_strings tcm_stringtab = {
193062306a36Sopenharmony_ci	.language = 0x0409,
193162306a36Sopenharmony_ci	.strings = tcm_us_strings,
193262306a36Sopenharmony_ci};
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_cistatic struct usb_gadget_strings *tcm_strings[] = {
193562306a36Sopenharmony_ci	&tcm_stringtab,
193662306a36Sopenharmony_ci	NULL,
193762306a36Sopenharmony_ci};
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_cistatic int tcm_bind(struct usb_configuration *c, struct usb_function *f)
194062306a36Sopenharmony_ci{
194162306a36Sopenharmony_ci	struct f_uas		*fu = to_f_uas(f);
194262306a36Sopenharmony_ci	struct usb_string	*us;
194362306a36Sopenharmony_ci	struct usb_gadget	*gadget = c->cdev->gadget;
194462306a36Sopenharmony_ci	struct usb_ep		*ep;
194562306a36Sopenharmony_ci	struct f_tcm_opts	*opts;
194662306a36Sopenharmony_ci	int			iface;
194762306a36Sopenharmony_ci	int			ret;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	opts = container_of(f->fi, struct f_tcm_opts, func_inst);
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	mutex_lock(&opts->dep_lock);
195262306a36Sopenharmony_ci	if (!opts->can_attach) {
195362306a36Sopenharmony_ci		mutex_unlock(&opts->dep_lock);
195462306a36Sopenharmony_ci		return -ENODEV;
195562306a36Sopenharmony_ci	}
195662306a36Sopenharmony_ci	mutex_unlock(&opts->dep_lock);
195762306a36Sopenharmony_ci	us = usb_gstrings_attach(c->cdev, tcm_strings,
195862306a36Sopenharmony_ci		ARRAY_SIZE(tcm_us_strings));
195962306a36Sopenharmony_ci	if (IS_ERR(us))
196062306a36Sopenharmony_ci		return PTR_ERR(us);
196162306a36Sopenharmony_ci	bot_intf_desc.iInterface = us[USB_G_STR_INT_BBB].id;
196262306a36Sopenharmony_ci	uasp_intf_desc.iInterface = us[USB_G_STR_INT_UAS].id;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	iface = usb_interface_id(c, f);
196562306a36Sopenharmony_ci	if (iface < 0)
196662306a36Sopenharmony_ci		return iface;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	bot_intf_desc.bInterfaceNumber = iface;
196962306a36Sopenharmony_ci	uasp_intf_desc.bInterfaceNumber = iface;
197062306a36Sopenharmony_ci	fu->iface = iface;
197162306a36Sopenharmony_ci	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
197262306a36Sopenharmony_ci			&uasp_bi_ep_comp_desc);
197362306a36Sopenharmony_ci	if (!ep)
197462306a36Sopenharmony_ci		goto ep_fail;
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	fu->ep_in = ep;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
197962306a36Sopenharmony_ci			&uasp_bo_ep_comp_desc);
198062306a36Sopenharmony_ci	if (!ep)
198162306a36Sopenharmony_ci		goto ep_fail;
198262306a36Sopenharmony_ci	fu->ep_out = ep;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
198562306a36Sopenharmony_ci			&uasp_status_in_ep_comp_desc);
198662306a36Sopenharmony_ci	if (!ep)
198762306a36Sopenharmony_ci		goto ep_fail;
198862306a36Sopenharmony_ci	fu->ep_status = ep;
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
199162306a36Sopenharmony_ci			&uasp_cmd_comp_desc);
199262306a36Sopenharmony_ci	if (!ep)
199362306a36Sopenharmony_ci		goto ep_fail;
199462306a36Sopenharmony_ci	fu->ep_cmd = ep;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	/* Assume endpoint addresses are the same for both speeds */
199762306a36Sopenharmony_ci	uasp_bi_desc.bEndpointAddress =	uasp_ss_bi_desc.bEndpointAddress;
199862306a36Sopenharmony_ci	uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
199962306a36Sopenharmony_ci	uasp_status_desc.bEndpointAddress =
200062306a36Sopenharmony_ci		uasp_ss_status_desc.bEndpointAddress;
200162306a36Sopenharmony_ci	uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
200462306a36Sopenharmony_ci	uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
200562306a36Sopenharmony_ci	uasp_fs_status_desc.bEndpointAddress =
200662306a36Sopenharmony_ci		uasp_ss_status_desc.bEndpointAddress;
200762306a36Sopenharmony_ci	uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	ret = usb_assign_descriptors(f, uasp_fs_function_desc,
201062306a36Sopenharmony_ci			uasp_hs_function_desc, uasp_ss_function_desc,
201162306a36Sopenharmony_ci			uasp_ss_function_desc);
201262306a36Sopenharmony_ci	if (ret)
201362306a36Sopenharmony_ci		goto ep_fail;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	return 0;
201662306a36Sopenharmony_ciep_fail:
201762306a36Sopenharmony_ci	pr_err("Can't claim all required eps\n");
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	return -ENOTSUPP;
202062306a36Sopenharmony_ci}
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_cistruct guas_setup_wq {
202362306a36Sopenharmony_ci	struct work_struct work;
202462306a36Sopenharmony_ci	struct f_uas *fu;
202562306a36Sopenharmony_ci	unsigned int alt;
202662306a36Sopenharmony_ci};
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_cistatic void tcm_delayed_set_alt(struct work_struct *wq)
202962306a36Sopenharmony_ci{
203062306a36Sopenharmony_ci	struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
203162306a36Sopenharmony_ci			work);
203262306a36Sopenharmony_ci	struct f_uas *fu = work->fu;
203362306a36Sopenharmony_ci	int alt = work->alt;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	kfree(work);
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	if (fu->flags & USBG_IS_BOT)
203862306a36Sopenharmony_ci		bot_cleanup_old_alt(fu);
203962306a36Sopenharmony_ci	if (fu->flags & USBG_IS_UAS)
204062306a36Sopenharmony_ci		uasp_cleanup_old_alt(fu);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	if (alt == USB_G_ALT_INT_BBB)
204362306a36Sopenharmony_ci		bot_set_alt(fu);
204462306a36Sopenharmony_ci	else if (alt == USB_G_ALT_INT_UAS)
204562306a36Sopenharmony_ci		uasp_set_alt(fu);
204662306a36Sopenharmony_ci	usb_composite_setup_continue(fu->function.config->cdev);
204762306a36Sopenharmony_ci}
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_cistatic int tcm_get_alt(struct usb_function *f, unsigned intf)
205062306a36Sopenharmony_ci{
205162306a36Sopenharmony_ci	if (intf == bot_intf_desc.bInterfaceNumber)
205262306a36Sopenharmony_ci		return USB_G_ALT_INT_BBB;
205362306a36Sopenharmony_ci	if (intf == uasp_intf_desc.bInterfaceNumber)
205462306a36Sopenharmony_ci		return USB_G_ALT_INT_UAS;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	return -EOPNOTSUPP;
205762306a36Sopenharmony_ci}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_cistatic int tcm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	struct f_uas *fu = to_f_uas(f);
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
206462306a36Sopenharmony_ci		struct guas_setup_wq *work;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci		work = kmalloc(sizeof(*work), GFP_ATOMIC);
206762306a36Sopenharmony_ci		if (!work)
206862306a36Sopenharmony_ci			return -ENOMEM;
206962306a36Sopenharmony_ci		INIT_WORK(&work->work, tcm_delayed_set_alt);
207062306a36Sopenharmony_ci		work->fu = fu;
207162306a36Sopenharmony_ci		work->alt = alt;
207262306a36Sopenharmony_ci		schedule_work(&work->work);
207362306a36Sopenharmony_ci		return USB_GADGET_DELAYED_STATUS;
207462306a36Sopenharmony_ci	}
207562306a36Sopenharmony_ci	return -EOPNOTSUPP;
207662306a36Sopenharmony_ci}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cistatic void tcm_disable(struct usb_function *f)
207962306a36Sopenharmony_ci{
208062306a36Sopenharmony_ci	struct f_uas *fu = to_f_uas(f);
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	if (fu->flags & USBG_IS_UAS)
208362306a36Sopenharmony_ci		uasp_cleanup_old_alt(fu);
208462306a36Sopenharmony_ci	else if (fu->flags & USBG_IS_BOT)
208562306a36Sopenharmony_ci		bot_cleanup_old_alt(fu);
208662306a36Sopenharmony_ci	fu->flags = 0;
208762306a36Sopenharmony_ci}
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_cistatic int tcm_setup(struct usb_function *f,
209062306a36Sopenharmony_ci		const struct usb_ctrlrequest *ctrl)
209162306a36Sopenharmony_ci{
209262306a36Sopenharmony_ci	struct f_uas *fu = to_f_uas(f);
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	if (!(fu->flags & USBG_IS_BOT))
209562306a36Sopenharmony_ci		return -EOPNOTSUPP;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	return usbg_bot_setup(f, ctrl);
209862306a36Sopenharmony_ci}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_cistatic inline struct f_tcm_opts *to_f_tcm_opts(struct config_item *item)
210162306a36Sopenharmony_ci{
210262306a36Sopenharmony_ci	return container_of(to_config_group(item), struct f_tcm_opts,
210362306a36Sopenharmony_ci		func_inst.group);
210462306a36Sopenharmony_ci}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_cistatic void tcm_attr_release(struct config_item *item)
210762306a36Sopenharmony_ci{
210862306a36Sopenharmony_ci	struct f_tcm_opts *opts = to_f_tcm_opts(item);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	usb_put_function_instance(&opts->func_inst);
211162306a36Sopenharmony_ci}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_cistatic struct configfs_item_operations tcm_item_ops = {
211462306a36Sopenharmony_ci	.release		= tcm_attr_release,
211562306a36Sopenharmony_ci};
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_cistatic const struct config_item_type tcm_func_type = {
211862306a36Sopenharmony_ci	.ct_item_ops	= &tcm_item_ops,
211962306a36Sopenharmony_ci	.ct_owner	= THIS_MODULE,
212062306a36Sopenharmony_ci};
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_cistatic void tcm_free_inst(struct usb_function_instance *f)
212362306a36Sopenharmony_ci{
212462306a36Sopenharmony_ci	struct f_tcm_opts *opts;
212562306a36Sopenharmony_ci	unsigned i;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	opts = container_of(f, struct f_tcm_opts, func_inst);
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	mutex_lock(&tpg_instances_lock);
213062306a36Sopenharmony_ci	for (i = 0; i < TPG_INSTANCES; ++i)
213162306a36Sopenharmony_ci		if (tpg_instances[i].func_inst == f)
213262306a36Sopenharmony_ci			break;
213362306a36Sopenharmony_ci	if (i < TPG_INSTANCES)
213462306a36Sopenharmony_ci		tpg_instances[i].func_inst = NULL;
213562306a36Sopenharmony_ci	mutex_unlock(&tpg_instances_lock);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	kfree(opts);
213862306a36Sopenharmony_ci}
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_cistatic int tcm_register_callback(struct usb_function_instance *f)
214162306a36Sopenharmony_ci{
214262306a36Sopenharmony_ci	struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	mutex_lock(&opts->dep_lock);
214562306a36Sopenharmony_ci	opts->can_attach = true;
214662306a36Sopenharmony_ci	mutex_unlock(&opts->dep_lock);
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	return 0;
214962306a36Sopenharmony_ci}
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_cistatic void tcm_unregister_callback(struct usb_function_instance *f)
215262306a36Sopenharmony_ci{
215362306a36Sopenharmony_ci	struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	mutex_lock(&opts->dep_lock);
215662306a36Sopenharmony_ci	unregister_gadget_item(opts->
215762306a36Sopenharmony_ci		func_inst.group.cg_item.ci_parent->ci_parent);
215862306a36Sopenharmony_ci	opts->can_attach = false;
215962306a36Sopenharmony_ci	mutex_unlock(&opts->dep_lock);
216062306a36Sopenharmony_ci}
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_cistatic int usbg_attach(struct usbg_tpg *tpg)
216362306a36Sopenharmony_ci{
216462306a36Sopenharmony_ci	struct usb_function_instance *f = tpg->fi;
216562306a36Sopenharmony_ci	struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	if (opts->tcm_register_callback)
216862306a36Sopenharmony_ci		return opts->tcm_register_callback(f);
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	return 0;
217162306a36Sopenharmony_ci}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_cistatic void usbg_detach(struct usbg_tpg *tpg)
217462306a36Sopenharmony_ci{
217562306a36Sopenharmony_ci	struct usb_function_instance *f = tpg->fi;
217662306a36Sopenharmony_ci	struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	if (opts->tcm_unregister_callback)
217962306a36Sopenharmony_ci		opts->tcm_unregister_callback(f);
218062306a36Sopenharmony_ci}
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_cistatic int tcm_set_name(struct usb_function_instance *f, const char *name)
218362306a36Sopenharmony_ci{
218462306a36Sopenharmony_ci	struct f_tcm_opts *opts = container_of(f, struct f_tcm_opts, func_inst);
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	pr_debug("tcm: Activating %s\n", name);
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	mutex_lock(&opts->dep_lock);
218962306a36Sopenharmony_ci	opts->ready = true;
219062306a36Sopenharmony_ci	mutex_unlock(&opts->dep_lock);
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	return 0;
219362306a36Sopenharmony_ci}
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_cistatic struct usb_function_instance *tcm_alloc_inst(void)
219662306a36Sopenharmony_ci{
219762306a36Sopenharmony_ci	struct f_tcm_opts *opts;
219862306a36Sopenharmony_ci	int i;
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
220262306a36Sopenharmony_ci	if (!opts)
220362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	mutex_lock(&tpg_instances_lock);
220662306a36Sopenharmony_ci	for (i = 0; i < TPG_INSTANCES; ++i)
220762306a36Sopenharmony_ci		if (!tpg_instances[i].func_inst)
220862306a36Sopenharmony_ci			break;
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	if (i == TPG_INSTANCES) {
221162306a36Sopenharmony_ci		mutex_unlock(&tpg_instances_lock);
221262306a36Sopenharmony_ci		kfree(opts);
221362306a36Sopenharmony_ci		return ERR_PTR(-EBUSY);
221462306a36Sopenharmony_ci	}
221562306a36Sopenharmony_ci	tpg_instances[i].func_inst = &opts->func_inst;
221662306a36Sopenharmony_ci	mutex_unlock(&tpg_instances_lock);
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	mutex_init(&opts->dep_lock);
221962306a36Sopenharmony_ci	opts->func_inst.set_inst_name = tcm_set_name;
222062306a36Sopenharmony_ci	opts->func_inst.free_func_inst = tcm_free_inst;
222162306a36Sopenharmony_ci	opts->tcm_register_callback = tcm_register_callback;
222262306a36Sopenharmony_ci	opts->tcm_unregister_callback = tcm_unregister_callback;
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	config_group_init_type_name(&opts->func_inst.group, "",
222562306a36Sopenharmony_ci			&tcm_func_type);
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	return &opts->func_inst;
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_cistatic void tcm_free(struct usb_function *f)
223162306a36Sopenharmony_ci{
223262306a36Sopenharmony_ci	struct f_uas *tcm = to_f_uas(f);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	kfree(tcm);
223562306a36Sopenharmony_ci}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_cistatic void tcm_unbind(struct usb_configuration *c, struct usb_function *f)
223862306a36Sopenharmony_ci{
223962306a36Sopenharmony_ci	usb_free_all_descriptors(f);
224062306a36Sopenharmony_ci}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_cistatic struct usb_function *tcm_alloc(struct usb_function_instance *fi)
224362306a36Sopenharmony_ci{
224462306a36Sopenharmony_ci	struct f_uas *fu;
224562306a36Sopenharmony_ci	unsigned i;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	mutex_lock(&tpg_instances_lock);
224862306a36Sopenharmony_ci	for (i = 0; i < TPG_INSTANCES; ++i)
224962306a36Sopenharmony_ci		if (tpg_instances[i].func_inst == fi)
225062306a36Sopenharmony_ci			break;
225162306a36Sopenharmony_ci	if (i == TPG_INSTANCES) {
225262306a36Sopenharmony_ci		mutex_unlock(&tpg_instances_lock);
225362306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
225462306a36Sopenharmony_ci	}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	fu = kzalloc(sizeof(*fu), GFP_KERNEL);
225762306a36Sopenharmony_ci	if (!fu) {
225862306a36Sopenharmony_ci		mutex_unlock(&tpg_instances_lock);
225962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
226062306a36Sopenharmony_ci	}
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	fu->function.name = "Target Function";
226362306a36Sopenharmony_ci	fu->function.bind = tcm_bind;
226462306a36Sopenharmony_ci	fu->function.unbind = tcm_unbind;
226562306a36Sopenharmony_ci	fu->function.set_alt = tcm_set_alt;
226662306a36Sopenharmony_ci	fu->function.get_alt = tcm_get_alt;
226762306a36Sopenharmony_ci	fu->function.setup = tcm_setup;
226862306a36Sopenharmony_ci	fu->function.disable = tcm_disable;
226962306a36Sopenharmony_ci	fu->function.free_func = tcm_free;
227062306a36Sopenharmony_ci	fu->tpg = tpg_instances[i].tpg;
227162306a36Sopenharmony_ci	mutex_unlock(&tpg_instances_lock);
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	return &fu->function;
227462306a36Sopenharmony_ci}
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ciDECLARE_USB_FUNCTION(tcm, tcm_alloc_inst, tcm_alloc);
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_cistatic int __init tcm_init(void)
227962306a36Sopenharmony_ci{
228062306a36Sopenharmony_ci	int ret;
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	ret = usb_function_register(&tcmusb_func);
228362306a36Sopenharmony_ci	if (ret)
228462306a36Sopenharmony_ci		return ret;
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	ret = target_register_template(&usbg_ops);
228762306a36Sopenharmony_ci	if (ret)
228862306a36Sopenharmony_ci		usb_function_unregister(&tcmusb_func);
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	return ret;
229162306a36Sopenharmony_ci}
229262306a36Sopenharmony_cimodule_init(tcm_init);
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_cistatic void __exit tcm_exit(void)
229562306a36Sopenharmony_ci{
229662306a36Sopenharmony_ci	target_unregister_template(&usbg_ops);
229762306a36Sopenharmony_ci	usb_function_unregister(&tcmusb_func);
229862306a36Sopenharmony_ci}
229962306a36Sopenharmony_cimodule_exit(tcm_exit);
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
230262306a36Sopenharmony_ciMODULE_AUTHOR("Sebastian Andrzej Siewior");
2303