⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_tgt_lib.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * SCSI target lib functions * * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu> * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */#include <linux/blkdev.h>#include <linux/hash.h>#include <linux/module.h>#include <linux/pagemap.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_transport.h>#include <scsi/scsi_tgt.h>#include "scsi_tgt_priv.h"static struct workqueue_struct *scsi_tgtd;static struct kmem_cache *scsi_tgt_cmd_cache;/* * TODO: this struct will be killed when the block layer supports large bios * and James's work struct code is in */struct scsi_tgt_cmd {	/* TODO replace work with James b's code */	struct work_struct work;	/* TODO fix limits of some drivers */	struct bio *bio;	struct list_head hash_list;	struct request *rq;	u64 itn_id;	u64 tag;};#define TGT_HASH_ORDER	4#define cmd_hashfn(tag)	hash_long((unsigned long) (tag), TGT_HASH_ORDER)struct scsi_tgt_queuedata {	struct Scsi_Host *shost;	struct list_head cmd_hash[1 << TGT_HASH_ORDER];	spinlock_t cmd_hash_lock;};/* * Function:	scsi_host_get_command() * * Purpose:	Allocate and setup a scsi command block and blk request * * Arguments:	shost	- scsi host *		data_dir - dma data dir *		gfp_mask- allocator flags * * Returns:	The allocated scsi command structure. * * This should be called by target LLDs to get a command. */struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,					enum dma_data_direction data_dir,					gfp_t gfp_mask){	int write = (data_dir == DMA_TO_DEVICE);	struct request *rq;	struct scsi_cmnd *cmd;	struct scsi_tgt_cmd *tcmd;	/* Bail if we can't get a reference to the device */	if (!get_device(&shost->shost_gendev))		return NULL;	tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC);	if (!tcmd)		goto put_dev;	/*	 * The blk helpers are used to the READ/WRITE requests	 * transfering data from a initiator point of view. Since	 * we are in target mode we want the opposite.	 */	rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask);	if (!rq)		goto free_tcmd;	cmd = __scsi_get_command(shost, gfp_mask);	if (!cmd)		goto release_rq;	memset(cmd, 0, sizeof(*cmd));	cmd->sc_data_direction = data_dir;	cmd->jiffies_at_alloc = jiffies;	cmd->request = rq;	rq->special = cmd;	rq->cmd_type = REQ_TYPE_SPECIAL;	rq->cmd_flags |= REQ_TYPE_BLOCK_PC;	rq->end_io_data = tcmd;	tcmd->rq = rq;	return cmd;release_rq:	blk_put_request(rq);free_tcmd:	kmem_cache_free(scsi_tgt_cmd_cache, tcmd);put_dev:	put_device(&shost->shost_gendev);	return NULL;}EXPORT_SYMBOL_GPL(scsi_host_get_command);/* * Function:	scsi_host_put_command() * * Purpose:	Free a scsi command block * * Arguments:	shost	- scsi host * 		cmd	- command block to free * * Returns:	Nothing. * * Notes:	The command must not belong to any lists. */void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd){	struct request_queue *q = shost->uspace_req_q;	struct request *rq = cmd->request;	struct scsi_tgt_cmd *tcmd = rq->end_io_data;	unsigned long flags;	kmem_cache_free(scsi_tgt_cmd_cache, tcmd);	spin_lock_irqsave(q->queue_lock, flags);	__blk_put_request(q, rq);	spin_unlock_irqrestore(q->queue_lock, flags);	__scsi_put_command(shost, cmd, &shost->shost_gendev);}EXPORT_SYMBOL_GPL(scsi_host_put_command);static void cmd_hashlist_del(struct scsi_cmnd *cmd){	struct request_queue *q = cmd->request->q;	struct scsi_tgt_queuedata *qdata = q->queuedata;	unsigned long flags;	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;	spin_lock_irqsave(&qdata->cmd_hash_lock, flags);	list_del(&tcmd->hash_list);	spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);}static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd){	blk_rq_unmap_user(tcmd->bio);}static void scsi_tgt_cmd_destroy(struct work_struct *work){	struct scsi_tgt_cmd *tcmd =		container_of(work, struct scsi_tgt_cmd, work);	struct scsi_cmnd *cmd = tcmd->rq->special;	dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,		rq_data_dir(cmd->request));	scsi_unmap_user_pages(tcmd);	scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);}static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd,			      u64 itn_id, u64 tag){	struct scsi_tgt_queuedata *qdata = rq->q->queuedata;	unsigned long flags;	struct list_head *head;	tcmd->itn_id = itn_id;	tcmd->tag = tag;	tcmd->bio = NULL;	INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy);	spin_lock_irqsave(&qdata->cmd_hash_lock, flags);	head = &qdata->cmd_hash[cmd_hashfn(tag)];	list_add(&tcmd->hash_list, head);	spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);}/* * scsi_tgt_alloc_queue - setup queue used for message passing * shost: scsi host * * This should be called by the LLD after host allocation. * And will be released when the host is released. */int scsi_tgt_alloc_queue(struct Scsi_Host *shost){	struct scsi_tgt_queuedata *queuedata;	struct request_queue *q;	int err, i;	/*	 * Do we need to send a netlink event or should uspace	 * just respond to the hotplug event?	 */	q = __scsi_alloc_queue(shost, NULL);	if (!q)		return -ENOMEM;	queuedata = kzalloc(sizeof(*queuedata), GFP_KERNEL);	if (!queuedata) {		err = -ENOMEM;		goto cleanup_queue;	}	queuedata->shost = shost;	q->queuedata = queuedata;	/*	 * this is a silly hack. We should probably just queue as many	 * command as is recvd to userspace. uspace can then make	 * sure we do not overload the HBA	 */	q->nr_requests = shost->can_queue;	/*	 * We currently only support software LLDs so this does	 * not matter for now. Do we need this for the cards we support?	 * If so we should make it a host template value.	 */	blk_queue_dma_alignment(q, 0);	shost->uspace_req_q = q;	for (i = 0; i < ARRAY_SIZE(queuedata->cmd_hash); i++)		INIT_LIST_HEAD(&queuedata->cmd_hash[i]);	spin_lock_init(&queuedata->cmd_hash_lock);	return 0;cleanup_queue:	blk_cleanup_queue(q);	return err;}EXPORT_SYMBOL_GPL(scsi_tgt_alloc_queue);void scsi_tgt_free_queue(struct Scsi_Host *shost){	int i;	unsigned long flags;	struct request_queue *q = shost->uspace_req_q;	struct scsi_cmnd *cmd;	struct scsi_tgt_queuedata *qdata = q->queuedata;	struct scsi_tgt_cmd *tcmd, *n;	LIST_HEAD(cmds);	spin_lock_irqsave(&qdata->cmd_hash_lock, flags);	for (i = 0; i < ARRAY_SIZE(qdata->cmd_hash); i++) {		list_for_each_entry_safe(tcmd, n, &qdata->cmd_hash[i],					 hash_list) {			list_del(&tcmd->hash_list);			list_add(&tcmd->hash_list, &cmds);		}	}	spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);	while (!list_empty(&cmds)) {		tcmd = list_entry(cmds.next, struct scsi_tgt_cmd, hash_list);		list_del(&tcmd->hash_list);		cmd = tcmd->rq->special;		shost->hostt->eh_abort_handler(cmd);		scsi_tgt_cmd_destroy(&tcmd->work);	}}EXPORT_SYMBOL_GPL(scsi_tgt_free_queue);struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *cmd){	struct scsi_tgt_queuedata *queue = cmd->request->q->queuedata;	return queue->shost;}EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);/* * scsi_tgt_queue_command - queue command for userspace processing * @cmd:	scsi command * @scsilun:	scsi lun * @tag:	unique value to identify this command for tmf */int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id,			   struct scsi_lun *scsilun, u64 tag){	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;	int err;	init_scsi_tgt_cmd(cmd->request, tcmd, itn_id, tag);	err = scsi_tgt_uspace_send_cmd(cmd, itn_id, scsilun, tag);	if (err)		cmd_hashlist_del(cmd);	return err;}EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);/* * This is run from a interrpt handler normally and the unmap * needs process context so we must queue */static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd){	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));	scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag);	if (cmd->request_buffer)		scsi_free_sgtable(cmd);	queue_work(scsi_tgtd, &tcmd->work);}static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -