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

Re: [Xen-devel] [Patch 5/7] pvSCSI driver



> diff -r 77e3c0d472ac -r 81e347dc1bfe drivers/xen/scsiback/comback.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/drivers/xen/scsiback/comback.c  Fri Feb 15 19:49:24 2008 +0900
...
> +#include <scsi/scsi.h>
> +#include <scsi/scsi_host.h>
> +#include <scsi/scsi_device.h>
> +#include "comback.h"
> +
> +extern struct list_head pending_free;
> +extern int vscsiif_reqs;
Is there any reason not to pull these into comback.h?

> +
> +static DEFINE_SPINLOCK(pending_free_lock);
> +static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
> +
> +extern void scsiback_cmd_exec(pending_req_t *);
> +extern int copy_request_ring_info(struct comback_info *,
> +             struct vscsiif_request *, pending_req_t *);
> +extern void scsiback_reset_exec(pending_req_t *);
> +
> +/* ------------------------------------------------------------ */
> +/*   for frontend to backend communication                   */
> +/* ------------------------------------------------------------ */
> +
> +static pending_req_t * alloc_req(void)
> +{
> +     pending_req_t *req = NULL;
> +     unsigned long flags;
> +
> +     spin_lock_irqsave(&pending_free_lock, flags);
> +     if (!list_empty(&pending_free)) {
> +             req = list_entry(pending_free.next, pending_req_t, free_list);
> +             list_del(&req->free_list);
> +     }
> +     spin_unlock_irqrestore(&pending_free_lock, flags);
> +     return req;
> +}
> +
> +void free_req(pending_req_t *req)
> +{
> +     unsigned long flags;
> +     int was_empty;
> +
> +     spin_lock_irqsave(&pending_free_lock, flags);
> +     was_empty = list_empty(&pending_free);
> +     list_add(&req->free_list, &pending_free);
> +     spin_unlock_irqrestore(&pending_free_lock, flags);
> +     if (was_empty)
> +             wake_up(&pending_free_wq);
> +}
> +
> +static void comback_notify_work(struct comback_info *info)
> +{
> +     info->waiting_reqs = 1;
> +     wake_up(&info->wq);
> +}
> +
> +irqreturn_t comback_intr(int irq, void *dev_id, struct pt_regs *regs)
> +{
> +     comback_notify_work((struct comback_info *)dev_id);
> +     return IRQ_HANDLED;
> +}
> +
> +static int do_comback_cmd_fn(struct comback_info *info)
> +{
> +     struct vscsiif_back_ring *ring = &info->ring;
> +     struct vscsiif_request  *ring_req;
> +
> +     pending_req_t *pending_req;
> +     RING_IDX rc, rp;
> +     int err;
> +     int more_to_do = 0;
> +
> +     DPRINTK("%s\n",__FUNCTION__);
> +
> +     rc = ring->req_cons;
> +     rp = ring->sring->req_prod;
> +     rmb();
> +
> +     while ((rc != rp)) {
> +             if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
> +                     break;
> +
> +             pending_req = alloc_req();
> +             if (NULL == pending_req) {
> +                     more_to_do = 1;
> +                     break;
> +             }
> +
> +             ring_req = RING_GET_REQUEST(ring, rc);
> +             ring->req_cons = ++rc;
> +
> +             err = copy_request_ring_info(info, ring_req, pending_req);
> +
> +             if (pending_req->cmd == VSCSIIF_CMND_SCSI) {
> +                     scsiback_cmd_exec(pending_req);
> +             } else if (pending_req->cmd == VSCSIIF_CMND_SCSI_RESET) {
> +                     scsiback_reset_exec(pending_req);
> +             }
> +     }
> +
Do you not need to do a FINAL_CHECK_FOR_REQUESTS around here somewhere?


> +     return more_to_do;
> +}
> +
> +int comback_schedule(void *data)
> +{
> +     struct comback_info *info = (struct comback_info *)data;
> +
> +     DPRINTK("%s\n",__FUNCTION__);
> +
> +     scsiback_get(info);
> +
> +     while (!kthread_should_stop()) {
> +             wait_event_interruptible(
> +                     info->wq,
> +                     info->waiting_reqs || kthread_should_stop());
> +             wait_event_interruptible(
> +                     pending_free_wq,
> +                     !list_empty(&pending_free) || kthread_should_stop());
> +
> +             info->waiting_reqs = 0;
> +             smp_mb();
> +
> +             if (do_comback_cmd_fn(info))
> +                     info->waiting_reqs = 1;
> +     }
> +
> +     info->kthread = NULL;
> +     scsiback_put(info);
> +
> +     return 0;
> +}
> diff -r 77e3c0d472ac -r 81e347dc1bfe drivers/xen/scsiback/comback.h
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/drivers/xen/scsiback/comback.h  Fri Feb 15 19:49:24 2008 +0900
...

> +struct comback_info {
> +     struct xenbus_device *dev;
> +     struct scsi_device *sdev;
> +
> +     domid_t domid;
> +     unsigned int evtchn;
> +     unsigned int irq;
> +
> +     struct vscsiif_back_ring  ring;
> +     struct vm_struct *ring_area;
> +
> +     grant_handle_t shmem_handle;
> +     grant_ref_t shmem_ref;
> +
> +     struct work_struct scsiback_work;
> +
> +     spinlock_t ring_lock;
> +     atomic_t refcnt;
> +
> +     struct task_struct *kthread;
> +     wait_queue_head_t waiting_to_free;
> +     wait_queue_head_t wq;
> +     unsigned int waiting_reqs;
> +     struct page **mmap_pages;
> +
> +};
> +
> +typedef struct {
> +     unsigned char cmd;
> +     struct comback_info *info;
> +     uint8_t data_dir;
> +     uint16_t rqid;
> +     uint8_t use_sg;
> +     uint32_t request_bufflen;
> +     atomic_t pendcnt;
Is this ever anything other than 0 or 1?

> +     struct request *rq;
> +     struct scsiback_request_segment{
> +             grant_ref_t gref;
> +             uint16_t offset;
> +             uint16_t length;
> +     } pend_seg[VSCSIIF_SG_TABLESIZE];
> +     struct list_head free_list;
> +} pending_req_t;
Would it not be easier just to ember a struct vcsiif_request in there?

> +typedef struct scsi_pending_req              scsi_pending_req_t;
> +
> +irqreturn_t scsiback_intr(int, void *, struct pt_regs *);
> +int scsiback_init_sring(struct comback_info *,
> +             unsigned long, unsigned int);
> +int scsiback_schedule(void *data);
> +
> +
> +#define scsiback_get(_b) (atomic_inc(&(_b)->refcnt))
> +#define scsiback_put(_b)                             \
> +     do {                                            \
> +             if (atomic_dec_and_test(&(_b)->refcnt)) \
> +                     wake_up(&(_b)->waiting_to_free);\
> +     } while (0)
> +
> +struct comback_info *scsiinfo_alloc(domid_t domid);
> +void scsiback_free(struct comback_info *info);
> +void scsiback_disconnect(struct comback_info *info);
> +void __init scsiback_interface_init(void);
> +void __exit scsiback_interface_exit(void);
> +int scsiif_xenbus_init(void);
> +void scsiif_xenbus_unregister(void);
> +
> +
> +#endif /* __SCSIIF__BACKEND__COMMON_H__ */
> diff -r 77e3c0d472ac -r 81e347dc1bfe drivers/xen/scsiback/interface.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/drivers/xen/scsiback/interface.c        Fri Feb 15 19:49:24 2008 +0900
...

> +struct comback_info *scsiinfo_alloc(domid_t domid)
> +{
> +     struct comback_info *info;
> +
> +     info = kmem_cache_alloc(scsiback_cachep, GFP_KERNEL);
> +     if (!info)
> +             return ERR_PTR(-ENOMEM);
> +
> +     memset(info, 0, sizeof(*info));
> +     info->domid = domid;
> +     spin_lock_init(&info->ring_lock);
> +     atomic_set(&info->refcnt, 1);
> +     init_waitqueue_head(&info->wq);
> +     init_waitqueue_head(&info->waiting_to_free);
> +
> +     return info;
> +}
> +
> +static int map_frontend_page( struct comback_info *info, unsigned long 
> ring_ref)
> +{
> +     struct gnttab_map_grant_ref op;
> +     int err;
> +
> +     gnttab_set_map_op(&op, (unsigned long)info->ring_area->addr,
> +                             GNTMAP_host_map, ring_ref,
> +                             info->domid);
> +
> +     err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
> +     BUG_ON(err);
> +
> +     if (op.status) {
> +             printk(KERN_ERR "scsiback: Grant table operation failure !\n");
> +             return op.status;
> +     }
> +
> +     info->shmem_ref    = ring_ref;
> +     info->shmem_handle = op.handle;
> +
> +     return 0;
> +}
> +
> +static void unmap_frontend_page(struct comback_info *info)
> +{
> +     struct gnttab_unmap_grant_ref op;
> +     int err;
> +
> +     gnttab_set_unmap_op(&op, (unsigned long)info->ring_area->addr,
> +                             GNTMAP_host_map, info->shmem_handle);
> +
> +     err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
> +     BUG_ON(err);
> +
> +}
> +
> +int scsiback_init_sring(struct comback_info *info,
> +     unsigned long ring_ref, unsigned int evtchn)
> +{
> +     struct vscsiif_sring *sring;
> +     int err;
> +
> +     if (info->irq) {
> +             printk(KERN_ERR "scsiback: Already connected through?\n");
> +             return 0;
> +     }
> +
> +     info->ring_area = alloc_vm_area(PAGE_SIZE);
> +     if (!info)
> +             return -ENOMEM;
> +
> +     err = map_frontend_page(info, ring_ref);
> +     if (err)
> +             goto free_vm;
> +
> +     sring = (struct vscsiif_sring *) info->ring_area->addr;
> +     BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
> +
> +     err = bind_interdomain_evtchn_to_irqhandler(
> +                     info->domid, evtchn,
> +                     comback_intr, 0, "vscsiif-backend", info);
> +
> +     if (err < 0)
> +             goto unmap_page;
> +             
> +     info->irq = err;
> +
> +     return 0;
> +
> +unmap_page:
> +     unmap_frontend_page(info);
> +free_vm:
> +     free_vm_area(info->ring_area);
> +     return err;
> +}
> +
> +void scsiback_disconnect(struct comback_info *info)
> +{
> +     if (info->kthread) {
> +             kthread_stop(info->kthread);
> +             info->kthread = NULL;
> +     }
> +
> +     atomic_dec(&info->refcnt);
> +     wait_event(info->waiting_to_free, atomic_read(&info->refcnt) == 0);
> +     atomic_inc(&info->refcnt);
That looks a bit odd.  Would you mind explaining your reference
counting rules, please?


> +
> +     if (info->irq) {
> +             unbind_from_irqhandler(info->irq, info);
> +             info->irq = 0;
> +     }
> +
> +     if (info->ring.sring) {
> +             unmap_frontend_page(info);
> +             free_vm_area(info->ring_area);
> +             info->ring.sring = NULL;
> +     }
> +}
> +
> +void scsiback_free(struct comback_info *info)
> +{
> +     if (!atomic_dec_and_test(&info->refcnt))
> +             BUG();
> +     kmem_cache_free(scsiback_cachep, info);
> +}
> +
> +void __init scsiback_interface_init(void)
> +{
> +     scsiback_cachep = kmem_cache_create("vscsiif_cache",
> +             sizeof(struct comback_info), 0, 0, NULL, NULL);
What happens if this fails?

> +}
> +
> +void __exit scsiback_interface_exit(void)
> +{
> +     kmem_cache_destroy(scsiback_cachep);
> +}
> diff -r 77e3c0d472ac -r 81e347dc1bfe drivers/xen/scsiback/scsiback.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/drivers/xen/scsiback/scsiback.c Fri Feb 15 19:49:24 2008 +0900
...
> +#include "comback.h"
> +
> +extern void free_req(pending_req_t *req);
> +
> +int vscsiif_reqs = VSCSIIF_DEFAULT_CAN_QUEUE;
> +module_param_named(reqs, vscsiif_reqs, int, 0);
> +MODULE_PARM_DESC(reqs, "Number of scsiback requests to allocate");
> +
> +
> +#define INVALID_GRANT_HANDLE 0xFFFF
> +#define SCSIBACK_INVALID_HANDLE (~0)
> +#define VSCSIIF_TIMEOUT              (5*HZ)
> +
> +static pending_req_t *pending_reqs;
> +struct list_head pending_free;
> +static struct page **pending_pages;
> +static grant_handle_t *pending_grant_handles;
> +
> +static inline int vaddr_pagenr(pending_req_t *req, int seg)
> +{
> +     return (req - pending_reqs) * VSCSIIF_SG_TABLESIZE + seg;
> +}
Okay, so pending_pages is a big array with VSCSIIF_SG_TABLESIZE slots
per request?

> +
> +static inline unsigned long vaddr(pending_req_t *req, int seg)
> +{
> +     unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
> +     return (unsigned long)pfn_to_kaddr(pfn);
> +}
Would it make more sense for this to return a pointer, rather than an
unsigned long, given that it's a virtual address?

Also, inline in .c files is usually a mistake.

> +
> +#define pending_handle(_req, _seg) \
> +     (pending_grant_handles[vaddr_pagenr(_req, _seg)])
> +
> +
> +static void fast_flush_area(pending_req_t *req)
> +{
> +     struct gnttab_unmap_grant_ref unmap[VSCSIIF_SG_TABLESIZE];
> +     unsigned int i, invcount = 0;
> +     grant_handle_t handle;
> +     int err;
> +
> +     if (req->use_sg) {
> +             for (i = 0; i < req->use_sg; i++) {
> +                     handle = pending_handle(req, i);
> +                     if (handle == SCSIBACK_INVALID_HANDLE)
> +                             continue;
> +                     gnttab_set_unmap_op(&unmap[i], vaddr(req, i),
> +                                             GNTMAP_host_map, handle);
> +                     pending_handle(req, i) = SCSIBACK_INVALID_HANDLE;
> +                     invcount++;
> +             }
> +
> +             err = HYPERVISOR_grant_table_op(
> +                     GNTTABOP_unmap_grant_ref, unmap, invcount);
> +             BUG_ON(err);
> +     } else if (req->request_bufflen) {
> +             handle = pending_handle(req, 0);
> +             if (handle == SCSIBACK_INVALID_HANDLE)
> +                     return;
> +             gnttab_set_unmap_op(&unmap[0], vaddr(req, 0),
> +                                     GNTMAP_host_map, handle);
> +             pending_handle(req, 0) = SCSIBACK_INVALID_HANDLE;
> +
> +             err = HYPERVISOR_grant_table_op(
> +                     GNTTABOP_unmap_grant_ref, unmap, 1);
> +             BUG_ON(err);
> +     }
> +     
> +     return;
> +}
> +
> +static void make_sense(struct comback_info *info, struct request *req,
> +                    int32_t result, uint16_t rqid)
This does a fair bit more than just making the sense data, so it
probably wants a more descriptive name.

> +{
> +     struct vscsiif_response *ring_res;
> +     int notify, more_to_do = 1;
> +     unsigned long flags;
> +
> +     DPRINTK("%s\n",__FUNCTION__);
> +
> +     spin_lock_irqsave(&info->ring_lock, flags);
> +
> +     ring_res = RING_GET_RESPONSE(&info->ring,
> +                                     info->ring.rsp_prod_pvt);
> +     info->ring.rsp_prod_pvt++;
> +
> +     memset(ring_res->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
> +
> +     ring_res->rslt   = result;
> +     ring_res->rqid   = rqid;
> +
> +     if (result != 0 && req != NULL ) {
> +             memcpy(ring_res->sense_buffer,
> +                    req->sense, req->sense_len);
> +             ring_res->sense_len = req->sense_len;
> +     } else
> +             ring_res->sense_len = 0;
> +
> +     RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify);

> +     if (info->ring.rsp_prod_pvt == info->ring.req_cons) {
> +             RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do);
> +     } else if (RING_HAS_UNCONSUMED_REQUESTS(&info->ring)) {
> +             more_to_do = 1;
> +     }
Why do you need to check for more requests from here?  The frontend
should be giving you a kick over the event channel when it queues
requests (assuming you've set up req_event correctly and so forth).
That would make this check redundant.

> +
> +     spin_unlock_irqrestore(&info->ring_lock, flags);
> +
> +     if (more_to_do) {
> +             info->waiting_reqs = 1;
> +             wake_up(&info->wq);
> +     }
> +     if (notify)
> +             notify_remote_via_irq(info->irq);
> +}
> +
> +static void scsiback_end_cmd_fn(struct request *req, int error)
> +{
> +     unsigned char sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
> +     pending_req_t *pending_req = req->end_io_data;
> +     struct comback_info *info = pending_req->info;
> +     pending_req->rq = req;
> +
> +     DPRINTK("%s\n",__FUNCTION__);
> +
> +     if ((req->errors != 0) && (req->cmd[0] != TEST_UNIT_READY)) {
> +
> +             printk(KERN_ERR "scsiback: %d:%d:%d:%d  
> ",info->sdev->host->host_no,
> +                             info->sdev->channel, info->sdev->id, 
> +                             info->sdev->lun);
> +             printk(KERN_ERR "status = 0x%02x, message = 0x%02x, host = 
> 0x%02x, driver = 0x%02x\n",
> +                             status_byte(req->errors), msg_byte(req->errors),
> +                             host_byte(req->errors), 
> driver_byte(req->errors));
> +             memcpy(sense_buffer, req->sense, req->sense_len);
> +
> +             printk(KERN_ERR "scsiback: cmnd[0]=0x%02X use_sg=%d 
> req_buflen=%d\n",
> +                             req->cmd[0],
> +                             pending_req->use_sg, 
> +                             pending_req->request_bufflen);
> +
> +             __scsi_print_sense("scsiback", sense_buffer, req->sense_len);
> +     }
> +
> +     if (atomic_dec_and_test(&pending_req->pendcnt)) {
> +             fast_flush_area(pending_req);
> +
> +             make_sense(pending_req->info, pending_req->rq,
> +                        req->errors, pending_req->rqid);
> +
> +             scsiback_put(pending_req->info);
> +             free_req(pending_req);
> +     }
> +
> +     __blk_put_request(req->q, req);
> +
> +}
> +
> +
> +/* quoted scsi_lib.c/scsi_merge_bio */
> +static int scsiback_merge_bio(struct request *rq, struct bio *bio)
Umm... Why do you need your own merge_bio function?  That sounds like
something best handled by Linux's generic block and scsi subsystems,
rather than doing it in the backend.


> +{
> +     struct request_queue *q = rq->q;
> +
> +     bio->bi_flags &= ~(1 << BIO_SEG_VALID);
> +     if (rq_data_dir(rq) == WRITE)
> +             bio->bi_rw |= (1 << BIO_RW);
> +
> +     blk_queue_bounce(q, &bio);
> +
> +     if (!rq->bio)
> +             blk_rq_bio_prep(q, rq, bio);
> +     else if (!q->back_merge_fn(q, rq, bio))
> +             return -EINVAL;
> +     else {
> +             rq->biotail->bi_next = bio;
> +             rq->biotail          = bio;
> +             rq->hard_nr_sectors += bio_sectors(bio);
> +             rq->nr_sectors       = rq->hard_nr_sectors;
> +     }
> +
> +     return 0;
> +}
> +
> +
> +/* quoted scsi_lib.c/scsi_bi_endio */
> +static int scsiback_bi_endio(struct bio *bio, unsigned int bytes_done, int 
> error)
Again, why do you need this?

> +{
> +     if (bio->bi_size)
> +             return 1;
> +
> +     bio_put(bio);
> +     return 0;
> +}
> +
> +
> +/* quoted scsi_lib.c/scsi_req_map_sg . */
> +static int requset_map_sg(pending_req_t *pending_req, unsigned int count)
??????

Also, this one's missplet.

> +{
> +     struct request *rq = pending_req->rq;
> +     struct request_queue *q = pending_req->rq->q;
> +     int nr_pages;
> +     unsigned int nsegs = count;
> +
> +     unsigned int data_len = 0, len, bytes, off;
> +     struct page *page;
> +     struct bio *bio = NULL;
> +     int i, err, nr_vecs = 0;
> +
> +     for (i = 0; i < nsegs; i++) {
> +             page = virt_to_page(vaddr(pending_req, i));
> +             off = (unsigned int)pending_req->pend_seg[i].offset;
> +             len = (unsigned int)pending_req->pend_seg[i].length;
> +             data_len += len;
> +
> +             nr_pages = (len + off + PAGE_SIZE - 1) >> PAGE_SHIFT;
> +             while (len > 0) {
> +                     bytes = min_t(unsigned int, len, PAGE_SIZE - off);
> +
> +                     if (!bio) {
> +                             nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
> +                             nr_pages -= nr_vecs;
> +                             bio = bio_alloc(GFP_KERNEL, nr_vecs);
> +                             if (!bio) {
> +                                     err = -ENOMEM;
> +                                     goto free_bios;
> +                             }
> +                             bio->bi_end_io = scsiback_bi_endio;
> +                     }
> +
> +                     if (bio_add_pc_page(q, bio, page, bytes, off) !=
> +                                             bytes) {
> +                             bio_put(bio);
> +                             err = -EINVAL;
> +                             goto free_bios;
> +                     }
> +
> +                     if (bio->bi_vcnt >= nr_vecs) {
> +                             err = scsiback_merge_bio(rq, bio);
> +                             if (err) {
> +                                     bio_endio(bio, bio->bi_size, 0);
> +                                     goto free_bios;
> +                             }
> +                             bio = NULL;
> +                     }
> +
> +                     page++;
> +                     len -= bytes;
> +                     off = 0;
> +             }
> +     }
> +
> +     rq->buffer   = rq->data = NULL;
> +     rq->data_len = data_len;
> +
> +     return 0;
> +
> +free_bios:
> +     while ((bio = rq->bio) != NULL) {
> +             rq->bio = bio->bi_next;
> +             /*
> +              * call endio instead of bio_put incase it was bounced
> +              */
> +             bio_endio(bio, bio->bi_size, 0);
> +     }
> +
> +     return err;
> +}
> +
> +int copy_request_ring_info(struct comback_info *info,
> +             struct vscsiif_request *ring_req, pending_req_t *pending_req)
> +{
> +     int write;
> +     char sense[VSCSIIF_SENSE_BUFFERSIZE];
> +     int i;
> +
> +     DPRINTK("%s\n",__FUNCTION__);
> +
> +     pending_req->rqid   = ring_req->rqid;
> +     pending_req->cmd    = ring_req->cmd;
> +
> +     if (ring_req->channel != info->sdev->channel ||
> +             ring_req->id != info->sdev->id ||
> +             ring_req->lun != info->sdev->lun) {
> +             printk(KERN_ERR "scsiback: Device different %d:%d:%d\n",
> +                     ring_req->channel, ring_req->id, ring_req->lun);
> +             BUG();
Umm.  Yeah, letting the frontend cause a BUG() in the backend isn't
really a good idea.

Also, if you're enforcing that the per-request channel, ID, and LUN
always match the per-ring ones, there's not much point in having them
in the request structure.

> +     }
> +
> +     write = (ring_req->sc_data_direction == DMA_TO_DEVICE);
> +     pending_req->data_dir = ring_req->sc_data_direction;
> +     pending_req->rq       =
> +                     blk_get_request(info->sdev->request_queue,
> +                                                     write, GFP_KERNEL);
> +     pending_req->info   = info;
> +     pending_req->use_sg = ring_req->use_sg;
> +     pending_req->request_bufflen = ring_req->request_bufflen;
> +
> +
> +     pending_req->rq->flags  |= REQ_BLOCK_PC;
> +     pending_req->rq->cmd_len = (unsigned int)ring_req->cmd_len;
> +     memcpy(pending_req->rq->cmd, ring_req->cmnd,
> +                ring_req->cmd_len);
You probably want to be checking that cmd_len <= 16 (or whatever your
maximum CDB size is) here, or bad things are going to happen.  Also,
remember that the frontend can still modify ring_req underneath your
feet.

> +
> +     memset(sense, 0, sizeof(sense));
> +     pending_req->rq->sense     = sense;
> +     pending_req->rq->sense_len = VSCSIIF_SENSE_BUFFERSIZE;
> +
> +     pending_req->rq->retries   = 0;
> +     /*pending_req->rq->timeout   = (unsigned 
> int)ring_req->timeout_per_command;*/
> +     pending_req->rq->timeout   = VSCSIIF_TIMEOUT;
> +
> +     pending_req->rq->end_io_data = pending_req;
> +
> +     if (ring_req->use_sg) {
> +             for (i = 0; i < ring_req->use_sg; i++) {
> +                     pending_req->pend_seg[i].gref   = ring_req->seg[i].gref;
> +                     pending_req->pend_seg[i].offset = 
> ring_req->seg[i].offset;
> +                     pending_req->pend_seg[i].length = 
> ring_req->seg[i].length;
> +             }
> +     } else if (ring_req->request_bufflen) {
> +             pending_req->pend_seg[0].gref   = ring_req->seg[0].gref;
> +             pending_req->pend_seg[0].offset = ring_req->seg[0].offset;
> +             pending_req->pend_seg[0].length = ring_req->seg[0].length;
> +     }
Could you not just require that use_sg is never 0 when request_bufflen
is non-zero?


> +     
> +     return 0;
> +}
> +
> +
> +void scsiback_cmd_exec(pending_req_t *pending_req)
> +{
> +
> +     struct gnttab_map_grant_ref map[VSCSIIF_SG_TABLESIZE];
> +     struct comback_info *info = pending_req->info;
> +     
> +     int write = (pending_req->data_dir == DMA_TO_DEVICE);
> +     u32 flags;
> +     int i, err = 0;
> +     unsigned int use_sg = (unsigned int)pending_req->use_sg;
> +
> +     DPRINTK("%s\n",__FUNCTION__);
> +
> +     if (!info->sdev) {
> +             goto fail_response;
> +     }
> +
> +     if (use_sg) {
> +
> +             for (i = 0; i < use_sg; i++) {
> +                     flags = GNTMAP_host_map;
> +                     if (write)
> +                             flags |= GNTMAP_readonly;
> +                     gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
> +                                             pending_req->pend_seg[i].gref,
> +                                             info->domid);
> +             }
> +
> +             err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, 
> use_sg);
> +             BUG_ON(err);
> +
> +             for (i = 0; i < use_sg; i++) {
> +                     if (unlikely(map[i].status != 0)) {
> +                             printk(KERN_ERR "scsiback: invalid buffer -- 
> could not remap it\n");
> +                             map[i].handle = SCSIBACK_INVALID_HANDLE;
> +                             err |= 1;
> +                     }
> +
> +                     pending_handle(pending_req, i) = map[i].handle;
> +
> +                     if (err)
> +                             continue;
> +
> +                     set_phys_to_machine(__pa(vaddr(
> +                             pending_req, i)) >> PAGE_SHIFT,
> +                             FOREIGN_FRAME(map[i].dev_bus_addr >> 
> PAGE_SHIFT));
> +             }
> +
> +             if (err)
> +                     goto fail_flush;
> +
> +             if (requset_map_sg(pending_req, use_sg)) {
> +                     printk(KERN_ERR "scsiback: SG Request Map Error\n");
> +                     goto fail_map;
> +             }
I think you might find it easier to just use scsi_execute_async()
here.  Sure, it'll mean building an SG list for the request, but it
looks like it'll be far less work than going behind the scsi layer's
back and reimplementing everything.

> +
> +     } else if (pending_req->request_bufflen) {
> +
> +             flags = GNTMAP_host_map;
> +             if (write)
> +                     flags |= GNTMAP_readonly;
> +             gnttab_set_map_op(&map[0], vaddr(pending_req, 0), flags,
> +                                     pending_req->pend_seg[0].gref,
> +                                     info->domid);
> +
> +             err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, 1);
> +             BUG_ON(err);
> +
> +             if (unlikely(map[0].status != 0)) {
> +                     printk(KERN_ERR "scsiback: invalid buffer single -- 
> could not remap it\n");
> +                     map[0].handle = SCSIBACK_INVALID_HANDLE;
> +                     err |= 1;
> +             }
> +
> +             pending_handle(pending_req, 0) = map[0].handle;
> +
> +             set_phys_to_machine(__pa(vaddr(
> +                     pending_req, 0)) >> PAGE_SHIFT,
> +                     FOREIGN_FRAME(map[0].dev_bus_addr >> PAGE_SHIFT));
> +
> +             if (err)
> +                     goto fail_flush;
> +
> +             if (requset_map_sg(pending_req, 1)) {
> +                     printk(KERN_ERR "scsiback: SG Request Map Error\n");
> +                     goto fail_map;
> +             }
> +     }
> +
> +     atomic_set(&pending_req->pendcnt, 1);
> +     scsiback_get(info);
> +
> +     blk_execute_rq_nowait(pending_req->rq->q, NULL,
> +                                               pending_req->rq, 1, 
> scsiback_end_cmd_fn);
> +
> +     return ;
> +
> +fail_map:
> +fail_flush:
> +     fast_flush_area(pending_req);
> +
> +fail_response:
> +     make_sense(info, NULL, (DID_NO_CONNECT << 16),
> +                pending_req->rqid);
> +     free_req(pending_req);
> +
> +}
> +
> +
> +void scsiback_reset_exec(pending_req_t *pending_req)
> +{
> +     /* not implemented */
> +     BUG();
Yay!  Another way for the frontend to kill the backend.

> +}
> +
> +

Attachment: signature.asc
Description: Digital signature

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.