📄 scsi_tgt_lib.c
字号:
{ struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); int err; dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done); switch (err) { case SCSI_MLQUEUE_HOST_BUSY: case SCSI_MLQUEUE_DEVICE_BUSY: return -EAGAIN; } return 0;}static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask){ struct request *rq = cmd->request; int count; cmd->use_sg = rq->nr_phys_segments; cmd->request_buffer = scsi_alloc_sgtable(cmd, gfp_mask); if (!cmd->request_buffer) return -ENOMEM; cmd->request_bufflen = rq->data_len; dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq)); count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer); if (likely(count <= cmd->use_sg)) { cmd->use_sg = count; return 0; } eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg); scsi_free_sgtable(cmd); return -EINVAL;}/* TODO: test this crap and replace bio_map_user with new interface maybe */static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, unsigned long uaddr, unsigned int len, int rw){ struct request_queue *q = cmd->request->q; struct request *rq = cmd->request; int err; dprintk("%lx %u\n", uaddr, len); err = blk_rq_map_user(q, rq, (void *)uaddr, len); if (err) { /* * TODO: need to fixup sg_tablesize, max_segment_size, * max_sectors, etc for modern HW and software drivers * where this value is bogus. * * TODO2: we can alloc a reserve buffer of max size * we can handle and do the slow copy path for really large * IO. */ eprintk("Could not handle request of size %u.\n", len); return err; } tcmd->bio = rq->bio; err = scsi_tgt_init_cmd(cmd, GFP_KERNEL); if (err) goto unmap_rq; return 0;unmap_rq: scsi_unmap_user_pages(tcmd); return err;}static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr, unsigned len){ char __user *p = (char __user *) uaddr; if (copy_from_user(cmd->sense_buffer, p, min_t(unsigned, SCSI_SENSE_BUFFERSIZE, len))) { printk(KERN_ERR "Could not copy the sense buffer\n"); return -EIO; } return 0;}static int scsi_tgt_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd){ struct scsi_tgt_cmd *tcmd; int err; err = shost->hostt->eh_abort_handler(cmd); if (err) eprintk("fail to abort %p\n", cmd); tcmd = cmd->request->end_io_data; scsi_tgt_cmd_destroy(&tcmd->work); return err;}static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag){ struct scsi_tgt_queuedata *qdata = q->queuedata; struct request *rq = NULL; struct list_head *head; struct scsi_tgt_cmd *tcmd; unsigned long flags; head = &qdata->cmd_hash[cmd_hashfn(tag)]; spin_lock_irqsave(&qdata->cmd_hash_lock, flags); list_for_each_entry(tcmd, head, hash_list) { if (tcmd->tag == tag) { rq = tcmd->rq; list_del(&tcmd->hash_list); break; } } spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); return rq;}int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag, unsigned long uaddr, u32 len, unsigned long sense_uaddr, u32 sense_len, u8 rw){ struct Scsi_Host *shost; struct scsi_cmnd *cmd; struct request *rq; struct scsi_tgt_cmd *tcmd; int err = 0; dprintk("%d %llu %d %u %lx %u\n", host_no, (unsigned long long) tag, result, len, uaddr, rw); /* TODO: replace with a O(1) alg */ shost = scsi_host_lookup(host_no); if (IS_ERR(shost)) { printk(KERN_ERR "Could not find host no %d\n", host_no); return -EINVAL; } if (!shost->uspace_req_q) { printk(KERN_ERR "Not target scsi host %d\n", host_no); goto done; } rq = tgt_cmd_hash_lookup(shost->uspace_req_q, tag); if (!rq) { printk(KERN_ERR "Could not find tag %llu\n", (unsigned long long) tag); err = -EINVAL; goto done; } cmd = rq->special; dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n", cmd, cmd->cmnd[0], result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]); if (result == TASK_ABORTED) { scsi_tgt_abort_cmd(shost, cmd); goto done; } /* * store the userspace values here, the working values are * in the request_* values */ tcmd = cmd->request->end_io_data; cmd->result = result; if (cmd->result == SAM_STAT_CHECK_CONDITION) scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len); if (len) { err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw); if (err) { /* * user-space daemon bugs or OOM * TODO: we can do better for OOM. */ struct scsi_tgt_queuedata *qdata; struct list_head *head; unsigned long flags; eprintk("cmd %p ret %d uaddr %lx len %d rw %d\n", cmd, err, uaddr, len, rw); qdata = shost->uspace_req_q->queuedata; head = &qdata->cmd_hash[cmd_hashfn(tcmd->tag)]; spin_lock_irqsave(&qdata->cmd_hash_lock, flags); list_add(&tcmd->hash_list, head); spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); goto done; } } err = scsi_tgt_transfer_response(cmd);done: scsi_host_put(shost); return err;}int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, u64 itn_id, int function, u64 tag, struct scsi_lun *scsilun, void *data){ int err; /* TODO: need to retry if this fails. */ err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, itn_id, function, tag, scsilun, data); if (err < 0) eprintk("The task management request lost!\n"); return err;}EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request);int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result){ struct Scsi_Host *shost; int err = -EINVAL; dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid); shost = scsi_host_lookup(host_no); if (IS_ERR(shost)) { printk(KERN_ERR "Could not find host no %d\n", host_no); return err; } if (!shost->uspace_req_q) { printk(KERN_ERR "Not target scsi host %d\n", host_no); goto done; } err = shost->transportt->tsk_mgmt_response(shost, itn_id, mid, result);done: scsi_host_put(shost); return err;}int scsi_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, char *initiator){ int err; /* TODO: need to retry if this fails. */ err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 0, initiator); if (err < 0) eprintk("The i_t_neuxs request lost, %d %llx!\n", shost->host_no, (unsigned long long)itn_id); return err;}EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_create);int scsi_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id){ int err; /* TODO: need to retry if this fails. */ err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 1, NULL); if (err < 0) eprintk("The i_t_neuxs request lost, %d %llx!\n", shost->host_no, (unsigned long long)itn_id); return err;}EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_destroy);int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result){ struct Scsi_Host *shost; int err = -EINVAL; dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid); shost = scsi_host_lookup(host_no); if (IS_ERR(shost)) { printk(KERN_ERR "Could not find host no %d\n", host_no); return err; } if (!shost->uspace_req_q) { printk(KERN_ERR "Not target scsi host %d\n", host_no); goto done; } err = shost->transportt->it_nexus_response(shost, itn_id, result);done: scsi_host_put(shost); return err;}static int __init scsi_tgt_init(void){ int err; scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd", sizeof(struct scsi_tgt_cmd), 0, 0, NULL); if (!scsi_tgt_cmd_cache) return -ENOMEM; scsi_tgtd = create_workqueue("scsi_tgtd"); if (!scsi_tgtd) { err = -ENOMEM; goto free_kmemcache; } err = scsi_tgt_if_init(); if (err) goto destroy_wq; return 0;destroy_wq: destroy_workqueue(scsi_tgtd);free_kmemcache: kmem_cache_destroy(scsi_tgt_cmd_cache); return err;}static void __exit scsi_tgt_exit(void){ destroy_workqueue(scsi_tgtd); scsi_tgt_if_exit(); kmem_cache_destroy(scsi_tgt_cmd_cache);}module_init(scsi_tgt_init);module_exit(scsi_tgt_exit);MODULE_DESCRIPTION("SCSI target core");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -