sg.c
来自「linux 内核源代码」· C语言 代码 · 共 2,357 行 · 第 1/5 页
C
2,357 行
num_xfer = schp->bufflen; } if ((num_xfer <= 0) || (schp->dio_in_use) || (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags))) return 0; SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n", num_xfer, iovec_count, schp->k_use_sg)); if (iovec_count) { onum = iovec_count; if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum)) return -EFAULT; } else onum = 1; ksglen = sg->length; p = page_address(sg_page(sg)); for (j = 0, k = 0; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up); if (res) return res; for (; p; sg = sg_next(sg), ksglen = sg->length, p = page_address(sg_page(sg))) { if (usglen <= 0) break; if (ksglen > usglen) { if (usglen >= num_xfer) { if (__copy_from_user(p, up, num_xfer)) return -EFAULT; return 0; } if (__copy_from_user(p, up, usglen)) return -EFAULT; p += usglen; ksglen -= usglen; break; } else { if (ksglen >= num_xfer) { if (__copy_from_user(p, up, num_xfer)) return -EFAULT; return 0; } if (__copy_from_user(p, up, ksglen)) return -EFAULT; up += ksglen; usglen -= ksglen; } ++k; if (k >= schp->k_use_sg) return 0; } } return 0;}static intsg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind, int wr_xf, int *countp, unsigned char __user **up){ int num_xfer = (int) hp->dxfer_len; unsigned char __user *p = hp->dxferp; int count; if (0 == sg_num) { if (wr_xf && ('\0' == hp->interface_id)) count = (int) hp->flags; /* holds "old" input_size */ else count = num_xfer; } else { sg_iovec_t iovec; if (__copy_from_user(&iovec, p + ind*SZ_SG_IOVEC, SZ_SG_IOVEC)) return -EFAULT; p = iovec.iov_base; count = (int) iovec.iov_len; } if (!access_ok(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count)) return -EFAULT; if (up) *up = p; if (countp) *countp = count; return 0;}static voidsg_remove_scat(Sg_scatter_hold * schp){ SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: k_use_sg=%d\n", schp->k_use_sg)); if (schp->buffer && (schp->sglist_len > 0)) { struct scatterlist *sg = schp->buffer; if (schp->dio_in_use) {#ifdef SG_ALLOW_DIO_CODE st_unmap_user_pages(sg, schp->k_use_sg, TRUE);#endif } else { int k; for (k = 0; (k < schp->k_use_sg) && sg_page(sg); ++k, sg = sg_next(sg)) { SCSI_LOG_TIMEOUT(5, printk( "sg_remove_scat: k=%d, pg=0x%p, len=%d\n", k, sg_page(sg), sg->length)); sg_page_free(sg_page(sg), sg->length); } } kfree(schp->buffer); } memset(schp, 0, sizeof (*schp));}static intsg_read_xfer(Sg_request * srp){ sg_io_hdr_t *hp = &srp->header; Sg_scatter_hold *schp = &srp->data; struct scatterlist *sg = schp->buffer; int num_xfer = 0; int j, k, onum, usglen, ksglen, res; int iovec_count = (int) hp->iovec_count; int dxfer_dir = hp->dxfer_direction; unsigned char *p; unsigned char __user *up; int new_interface = ('\0' == hp->interface_id) ? 0 : 1; if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_FROM_DEV == dxfer_dir) || (SG_DXFER_TO_FROM_DEV == dxfer_dir)) { num_xfer = hp->dxfer_len; if (schp->bufflen < num_xfer) num_xfer = schp->bufflen; } if ((num_xfer <= 0) || (schp->dio_in_use) || (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags))) return 0; SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n", num_xfer, iovec_count, schp->k_use_sg)); if (iovec_count) { onum = iovec_count; if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum)) return -EFAULT; } else onum = 1; p = page_address(sg_page(sg)); ksglen = sg->length; for (j = 0, k = 0; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up); if (res) return res; for (; p; sg = sg_next(sg), ksglen = sg->length, p = page_address(sg_page(sg))) { if (usglen <= 0) break; if (ksglen > usglen) { if (usglen >= num_xfer) { if (__copy_to_user(up, p, num_xfer)) return -EFAULT; return 0; } if (__copy_to_user(up, p, usglen)) return -EFAULT; p += usglen; ksglen -= usglen; break; } else { if (ksglen >= num_xfer) { if (__copy_to_user(up, p, num_xfer)) return -EFAULT; return 0; } if (__copy_to_user(up, p, ksglen)) return -EFAULT; up += ksglen; usglen -= ksglen; } ++k; if (k >= schp->k_use_sg) return 0; } } return 0;}static intsg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer){ Sg_scatter_hold *schp = &srp->data; struct scatterlist *sg = schp->buffer; int k, num; SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n", num_read_xfer)); if ((!outp) || (num_read_xfer <= 0)) return 0; for (k = 0; (k < schp->k_use_sg) && sg_page(sg); ++k, sg = sg_next(sg)) { num = sg->length; if (num > num_read_xfer) { if (__copy_to_user(outp, page_address(sg_page(sg)), num_read_xfer)) return -EFAULT; break; } else { if (__copy_to_user(outp, page_address(sg_page(sg)), num)) return -EFAULT; num_read_xfer -= num; if (num_read_xfer <= 0) break; outp += num; } } return 0;}static voidsg_build_reserve(Sg_fd * sfp, int req_size){ Sg_scatter_hold *schp = &sfp->reserve; SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size)); do { if (req_size < PAGE_SIZE) req_size = PAGE_SIZE; if (0 == sg_build_indirect(schp, sfp, req_size)) return; else sg_remove_scat(schp); req_size >>= 1; /* divide by 2 */ } while (req_size > (PAGE_SIZE / 2));}static voidsg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size){ Sg_scatter_hold *req_schp = &srp->data; Sg_scatter_hold *rsv_schp = &sfp->reserve; struct scatterlist *sg = rsv_schp->buffer; int k, num, rem; srp->res_used = 1; SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); rem = size; for (k = 0; k < rsv_schp->k_use_sg; ++k, sg = sg_next(sg)) { num = sg->length; if (rem <= num) { sfp->save_scat_len = num; sg->length = rem; req_schp->k_use_sg = k + 1; req_schp->sglist_len = rsv_schp->sglist_len; req_schp->buffer = rsv_schp->buffer; req_schp->bufflen = size; req_schp->b_malloc_len = rsv_schp->b_malloc_len; break; } else rem -= num; } if (k >= rsv_schp->k_use_sg) SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n"));}static voidsg_unlink_reserve(Sg_fd * sfp, Sg_request * srp){ Sg_scatter_hold *req_schp = &srp->data; Sg_scatter_hold *rsv_schp = &sfp->reserve; SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n", (int) req_schp->k_use_sg)); if ((rsv_schp->k_use_sg > 0) && (req_schp->k_use_sg > 0)) { struct scatterlist *sg = rsv_schp->buffer; if (sfp->save_scat_len > 0) (sg + (req_schp->k_use_sg - 1))->length = (unsigned) sfp->save_scat_len; else SCSI_LOG_TIMEOUT(1, printk ("sg_unlink_reserve: BAD save_scat_len\n")); } req_schp->k_use_sg = 0; req_schp->bufflen = 0; req_schp->buffer = NULL; req_schp->sglist_len = 0; sfp->save_scat_len = 0; srp->res_used = 0;}static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id){ Sg_request *resp; unsigned long iflags; write_lock_irqsave(&sfp->rq_list_lock, iflags); for (resp = sfp->headrp; resp; resp = resp->nextrp) { /* look for requests that are ready + not SG_IO owned */ if ((1 == resp->done) && (!resp->sg_io_owned) && ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { resp->done = 2; /* guard against other readers */ break; } } write_unlock_irqrestore(&sfp->rq_list_lock, iflags); return resp;}#ifdef CONFIG_SCSI_PROC_FSstatic Sg_request *sg_get_nth_request(Sg_fd * sfp, int nth){ Sg_request *resp; unsigned long iflags; int k; read_lock_irqsave(&sfp->rq_list_lock, iflags); for (k = 0, resp = sfp->headrp; resp && (k < nth); ++k, resp = resp->nextrp) ; read_unlock_irqrestore(&sfp->rq_list_lock, iflags); return resp;}#endif/* always adds to end of list */static Sg_request *sg_add_request(Sg_fd * sfp){ int k; unsigned long iflags; Sg_request *resp; Sg_request *rp = sfp->req_arr; write_lock_irqsave(&sfp->rq_list_lock, iflags); resp = sfp->headrp; if (!resp) { memset(rp, 0, sizeof (Sg_request)); rp->parentfp = sfp; resp = rp; sfp->headrp = resp; } else { if (0 == sfp->cmd_q) resp = NULL; /* command queuing disallowed */ else { for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) { if (!rp->parentfp) break; } if (k < SG_MAX_QUEUE) { memset(rp, 0, sizeof (Sg_request)); rp->parentfp = sfp; while (resp->nextrp) resp = resp->nextrp; resp->nextrp = rp; resp = rp; } else resp = NULL; } } if (resp) { resp->nextrp = NULL; resp->header.duration = jiffies_to_msecs(jiffies); } write_unlock_irqrestore(&sfp->rq_list_lock, iflags); return resp;}/* Return of 1 for found; 0 for not found */static intsg_remove_request(Sg_fd * sfp, Sg_request * srp){ Sg_request *prev_rp; Sg_request *rp; unsigned long iflags; int res = 0; if ((!sfp) || (!srp) || (!sfp->headrp)) return res; write_lock_irqsave(&sfp->rq_list_lock, iflags); prev_rp = sfp->headrp; if (srp == prev_rp) { sfp->headrp = prev_rp->nextrp; prev_rp->parentfp = NULL; res = 1; } else { while ((rp = prev_rp->nextrp)) { if (srp == rp) { prev_rp->nextrp = rp->nextrp; rp->parentfp = NULL; res = 1; break; } prev_rp = rp; } } write_unlock_irqrestore(&sfp->rq_list_lock, iflags); return res;}#ifdef CONFIG_SCSI_PROC_FSstatic Sg_fd *sg_get_nth_sfp(Sg_device * sdp, int nth){ Sg_fd *resp; unsigned long iflags; int k; read_lock_irqsave(&sg_index_lock, iflags); for (k = 0, resp = sdp->headfp; resp && (k < nth); ++k, resp = resp->nextfp) ; read_unlock_irqrestore(&sg_index_lock, iflags); return resp;}#endifstatic Sg_fd *sg_add_sfp(Sg_device * sdp, int dev){ Sg_fd *sfp; unsigned long iflags; int bufflen; sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN); if (!sfp) return NULL; init_waitqueue_head(&sfp->read_wait); rwlock_init(&sfp->rq_list_lock); sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER; sfp->force_packid = SG_DEF_FORCE_PACK_ID; sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? sdp->device->host->unchecked_isa_dma : 1; sfp->cmd_q = SG_DEF_COMMAND_Q; sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; sfp->parentdp = sdp; write_lock_irqsave(&sg_index_lock, iflags); if (!sdp->headfp) sdp->headfp = sfp; else { /* add to tail of existing list */ Sg_fd *pfp = sdp->headfp; while (pfp->nextfp) pfp = pfp->nextfp; pfp->nextfp = sfp; } write_unlock_irqrestore(&sg_index_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); if (unlikely(sg_big_buff != def_reserved_size)) sg_big_buff = def_reserved_size; bufflen = min_t(int, sg_big_buff, sdp->device->request_queue->max_sectors * 512); sg_build_reserve(sfp, bufflen); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", sfp->reserve.bufflen, sfp->reserve.k_use_sg)); return sfp;}static void__sg_remove_sfp(Sg_dev
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?