Re: [PATCH 1/2] scsi_transport_fc: FC pass through support via bsg interface - revised

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Oct 13, 2008, at 10:53 AM, Seokmann Ju wrote:

Signed-off-by: Seokmann Ju <seokmann.ju@xxxxxxxxxx>
---
By mistake, I placed patches so that it won't match with the subject.
Sorry for the shortcomings.
Here is the patch for scsi_transport_fc module.

Signed-off-by: Seokmann Ju <seokmann.ju@xxxxxxxxxx>
---
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/ scsi_transport_fc.c
index cb971f0..dda12e0 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -43,6 +43,11 @@ static void fc_vport_sched_delete(struct work_struct *work);
 static int fc_vport_setup(struct Scsi_Host *shost, int channel,
 	struct device *pdev, struct fc_vport_identifiers  *ids,
 	struct fc_vport **vport);
+static void fc_service_timeout(unsigned long);
+static void fc_service_done(struct fc_service *);
+static int fc_service_handler(struct Scsi_Host *, struct fc_rport *,
+    struct request *, struct request_queue *);
+static void fc_bsg_remove(struct Scsi_Host *, struct fc_rport *);

 /*
  * Redefine so that we can have same named attributes in the
@@ -2406,12 +2411,194 @@ fc_rport_final_delete(struct work_struct *work)

 	transport_remove_device(dev);
 	device_del(dev);
+	fc_bsg_remove(shost, rport);
 	transport_destroy_device(dev);
 	put_device(&shost->shost_gendev);	/* for fc_host->rport list */
 	put_device(dev);			/* for self-reference */
 }


+static void fc_service_timeout(unsigned long _service)
+{
+	struct fc_service *service = (void *) _service;
+	unsigned long flags;
+
+	spin_lock_irqsave(&service->service_state_lock, flags);
+	if (!(service->service_state_flag & FC_SERVICE_STATE_DONE))
+		service->service_state_flag |= FC_SERVICE_STATE_TIMEOUT;
+	spin_unlock_irqrestore(&service->service_state_lock, flags);
+}
+
+static void fc_service_done(struct fc_service *service)
+{
+	if (service->service_state_flag != FC_SERVICE_STATE_DONE) {
+		if (service->service_state_flag == FC_SERVICE_STATE_TIMEOUT) {
+			printk(KERN_ERR "ERROR: FC service timed out\n");
+			/* expect abort to be issued by the application */
+			return;
+		} else
+			printk(KERN_ERR "ERROR: FC service not finished\n");
+	}
+
+	if (service->srv_reply.status != FC_SERVICE_COMPLETE) {
+		printk(KERN_ERR "ERROR: FC service to rport %p failed with"
+		    " status 0x%x\n", service->rport,
+		    service->srv_reply.status);
+	}
+
+	if (service->srv_reply.residual) {
+		service->req->data_len = 0;
+		service->req->next_rq->data_len = service->srv_reply.residual;
+	} else {
+		service->req->data_len = 0;
+		service->req->next_rq->data_len = 0;
+	}
+
+	service->req->end_io(service->req, 0);
+	kfree(service);
+}
+
+static int
+issue_fc_service(struct fc_rport *rport, struct request *req,
+    struct request *rsp, struct request_queue *q)
+{
+	int res = -ECOMM;
+	struct fc_service *service;
+	struct Scsi_Host *shost = rport_to_shost(rport);
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+	struct fc_service_request *srv_request = (struct fc_service_request *)
+	    req->cmd;
+
+	service = kzalloc(sizeof (struct fc_service), GFP_KERNEL);
+	if (!service)
+		return -ENOMEM;
+
+	service->rport = rport;
+	service->req = req;
+	service->q = q;
+	service->srv_request = srv_request;
+
+	sg_init_table(service->payload_dma, FC_SERVICE_MAX_SG);
+	service->payload_sg_cnt =
+	    blk_rq_map_sg(q, req, service->payload_dma);
+	service->payload = (void *) bio_data(req->bio);
+	service->payload_size = req->data_len;
+
+	sg_init_table(service->response_dma, FC_SERVICE_MAX_SG);
+	service->response_sg_cnt =
+	    blk_rq_map_sg(q, rsp, service->response_dma);
+	service->response = bio_data(rsp->bio);
+	service->response_size = rsp->data_len;
+
+	/* sense area of the request structure */
+	service->reply_seq = req->sense;
+	service->service_done = fc_service_done;
+	service->service_state_flag = FC_SERVICE_STATE_PENDING;
+
+	if (i->f->execute_fc_service)
+		res = i->f->execute_fc_service(service);
+
+	if (res) {
+		printk(KERN_ERR "ERROR: issuing FC service to the LLD "
+		"failed with status %d\n", res);
+		fc_service_done(service);
+		return res;
+	}
+
+	return 0;
+}
+
+static int
+fc_service_handler(struct Scsi_Host *shost, struct fc_rport *rport,
+			  struct request *req, struct request_queue *q)
+{
+	int ret;
+	struct request *rsp = req->next_rq;
+
+	if (!rsp) {
+		printk(KERN_ERR "ERROR: space for a FC service"
+		   " response is missing\n");
+		return -EINVAL;
+	}
+
+	if ((req->bio->bi_vcnt > FC_SERVICE_MAX_SG) ||
+	    (rsp->bio->bi_vcnt > FC_SERVICE_MAX_SG)) {
+		printk(KERN_ERR "ERROR: a FC service"
+		    " supports no more than %d SGs\n", FC_SERVICE_MAX_SG);
+		return -EINVAL;
+	}
+
+	ret = issue_fc_service(rport, req, rsp, q);
+
+	return ret;
+}
+
+static void fc_service_dispatch(struct request_queue *q)
+{
+	struct request *req;
+	struct fc_rport *rport = q->queuedata;
+	struct Scsi_Host *shost = rport_to_shost(rport);
+
+	while (!blk_queue_plugged(q)) {
+		req = elv_next_request(q);
+		if (!req)
+			break;
+
+		blkdev_dequeue_request(req);
+		spin_unlock_irq(q->queue_lock);
+
+		fc_service_handler(shost, rport, req, q);
+
+		spin_lock_irq(q->queue_lock);
+	}
+}
+
+static int
+fc_bsg_initialize(struct Scsi_Host *shost, struct fc_rport *rport)
+{
+	struct request_queue *q;
+	int error;
+	struct device *dev;
+	const char *name;
+	void (*release)(struct device *);
+
+	if (!rport) {
+		printk(KERN_ERR "ERROR: rport is NULL\n");
+		return -ENOMEM;
+	}
+
+	q = blk_init_queue(fc_service_dispatch, NULL);
+	if (!q)
+		return -ENOMEM;
+
+	dev = &rport->dev;
+	name = dev->bus_id;
+	release = NULL;
+
+	error = bsg_register_queue(q, dev, name, release);
+	if (error) {
+		blk_cleanup_queue(q);
+		return -ENOMEM;
+	}
+
+	rport->q = q;
+	q->queuedata = rport;
+	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
+
+	return 0;
+}
+
+static void
+fc_bsg_remove(struct Scsi_Host *shost, struct fc_rport *rport)
+{
+	struct request_queue *q = rport->q;
+
+	if (!q)
+		return;
+
+	bsg_unregister_queue(q);
+}
+
 /**
  * fc_rport_create - allocates and creates a remote FC port.
  * @shost:	scsi host the remote port is connected to.
@@ -2471,8 +2658,8 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
 	else
 		rport->scsi_target_id = -1;
 	list_add_tail(&rport->peers, &fc_host->rports);
-	get_device(&shost->shost_gendev);	/* for fc_host->rport list */

+	get_device(&shost->shost_gendev);	/* for fc_host->rport list */
 	spin_unlock_irqrestore(shost->host_lock, flags);

 	dev = &rport->dev;
@@ -2491,6 +2678,8 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
 	transport_add_device(dev);
 	transport_configure_device(dev);

+	fc_bsg_initialize(shost, rport);
+
 	if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
 		/* initiate a scan of the target */
 		rport->flags |= FC_RPORT_SCAN_PENDING;
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/ scsi_transport_fc.h
index 21018a4..6c6809a 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -33,7 +33,6 @@

 struct scsi_transport_template;

-
 /*
  * FC Port definitions - Following FC HBAAPI guidelines
  *
@@ -352,6 +351,7 @@ struct fc_rport {	/* aka fc_starget_attrs */
  	struct delayed_work fail_io_work;
  	struct work_struct stgt_delete_work;
 	struct work_struct rport_delete_work;
+	struct request_queue *q;
 } __attribute__((aligned(sizeof(unsigned long))));

 /* bit field values for struct fc_rport "flags" field: */
@@ -514,6 +514,81 @@ struct fc_host_attrs {
 	struct workqueue_struct *devloss_work_q;
 };

+#define FC_STATUS_BUF_SIZE 96
+
+enum fc_frame_type {
+	FC_FRAME_TYPE_BS,
+	FC_FRAME_TYPE_ELS,
+	FC_FRAME_TYPE_IEC = 4,
+	FC_FRAME_TYPE_IP,
+	FC_FRAME_TYPE_FCP = 8,
+	FC_FRAME_TYPE_GPP,
+	FC_FRAME_TYPE_FC_CT = 0x20,
+};
+
+enum fc_service_status {
+	FC_SERVICE_COMPLETE,
+	FC_SERVICE_TIMEOUT,
+	FC_SERVICE_ABORT,
+	FC_SERVICE_UNSUPPORTED,
+	FC_SERVICE_ERROR = -1,
+};
+
+#define FC_SERVICE_STATE_PENDING      1
+#define FC_SERVICE_STATE_DONE         2
+#define FC_SERVICE_STATE_ABORTED      4
+#define FC_SERVICE_STATE_TIMEOUT      8
+
+#define FC_SERVICE_TIMEOUT 10
+#define FC_SERVICE_MAX_SG             16
+
+/* request (CDB) structure of the sg_io_v4 */
+struct fc_service_request {
+	u8   request_type;
+	u8   timeout;
+	u8   reserved0;
+	u8   reserved1;
+};
+
+/* response  (request sense data) structure of the sg_io_v4 */
+struct fc_service_reply {
+	enum fc_service_status status;
+	u16  error_code;
+	u16  additional_error_code;
+	u32  residual;
+};
+
+struct fc_service {
+	struct fc_rport  *rport;
+	struct list_head list;
+
+	spinlock_t   service_state_lock;
+	unsigned     service_state_flag;
+
+	struct request *req;
+	struct request_queue *q;
+
+	/* Used by the discovery code. */
+	struct timer_list  timer;
+	struct completion  completion;
+
+	struct fc_service_request *srv_request;
+	void  *payload;
+	struct scatterlist payload_dma[FC_SERVICE_MAX_SG];
+	int   payload_sg_cnt;
+	int   payload_size;
+	void  *response;
+	struct scatterlist response_dma[FC_SERVICE_MAX_SG];
+	int   response_sg_cnt;
+	int   response_size;
+
+	struct fc_service_reply srv_reply;
+	void  *reply_seq;   /* pointer to sense area of request */
+	void  (*service_done)(struct fc_service *);
+
+	void *lld_pkt;
+};
+
 #define shost_to_fc_host(x) \
 	((struct fc_host_attrs *)(x)->shost_data)

@@ -612,6 +687,10 @@ struct fc_function_template {
 	int     (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int);
 	int     (* it_nexus_response)(struct Scsi_Host *, u64, int);

+	/* fc service handler */
+	int	(*execute_fc_service)(struct fc_service *);
+	int	(*abort_fc_service)(struct fc_service *);
+
 	/* allocation lengths for host-specific data */
 	u32	 			dd_fcrport_size;
 	u32	 			dd_fcvport_size;
@@ -732,7 +811,6 @@ fc_vport_set_state(struct fc_vport *vport, enum fc_vport_state new_state)
 	vport->vport_state = new_state;
 }

-
 struct scsi_transport_template *fc_attach_transport(
 			struct fc_function_template *);
 void fc_release_transport(struct scsi_transport_template *);
---
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux