On Mon, 13 Oct 2008 11:14:56 -0700 Seokmann Ju <seokmann.ju@xxxxxxxxxx> wrote: > > 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); > +} Hmm, this function is not used? Using rq_timed_out_fn is todo? > +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); You use scatter-gather for data transfer so bio_data should not be used. > + 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; > + } This doesn't look correct. bi_vcnt is not related with the number of sg. You use scatter-gather for large data transfer. You don't need to worry about bi_vcnt. > + 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; > + } I think that you need to call blk_queue_max_hw_segments and blk_queue_max_phys_segments here with FC_SERVICE_MAX_SG. > + > + 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 -- 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