📄 sg.c
字号:
if (mx_sc_elems < 0) return mx_sc_elems; /* most likely -ENOMEM */ mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist)); for (k = 0, sclp = schp->buffer, rem_sz = blk_size; (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); ++k, rem_sz -= ret_sz, ++sclp) { if (first) first = 0; else { num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz; mem_src = SG_HEAP_PAGE; p = sg_malloc(sfp, num, &ret_sz, &mem_src); if (! p) break; } sclp->address = p; sclp->length = ret_sz; mem_src_arr[k] = mem_src; SCSI_LOG_TIMEOUT(5, printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n", k, sclp->address, ret_sz, mem_src)); } /* end of for loop */ schp->k_use_sg = k; SCSI_LOG_TIMEOUT(5, printk("sg_build_indi: k_use_sg=%d, rem_sz=%d\n", k, rem_sz)); schp->bufflen = blk_size; if (rem_sz > 0) /* must have failed */ return -ENOMEM; } return 0;}static int sg_write_xfer(Sg_request * srp){ sg_io_hdr_t * hp = &srp->header; Sg_scatter_hold * schp = &srp->data; int num_xfer = 0; int j, k, onum, usglen, ksglen, res, ok; int iovec_count = (int)hp->iovec_count; int dxfer_dir = hp->dxfer_direction; unsigned char * p; unsigned char * up; int new_interface = ('\0' == hp->interface_id) ? 0 : 1; if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_TO_DEV == dxfer_dir) || (SG_DXFER_TO_FROM_DEV == dxfer_dir)) { num_xfer = (int)(new_interface ? hp->dxfer_len : hp->flags); if (schp->bufflen < num_xfer) num_xfer = schp->bufflen; } if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & 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 ((k = verify_area(VERIFY_READ, hp->dxferp, size_sg_iovec * onum))) return k; } else onum = 1; if (0 == schp->k_use_sg) { /* kernel has single buffer */ if (SG_USER_MEM != schp->buffer_mem_src) { /* else nothing to do */ for (j = 0, p = schp->buffer; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up); if (res) return res; usglen = (num_xfer > usglen) ? usglen : num_xfer; __copy_from_user(p, up, usglen); p += usglen; num_xfer -= usglen; if (num_xfer <= 0) return 0; } } } else { /* kernel using scatter gather list */ struct scatterlist * sclp = (struct scatterlist *)schp->buffer; char * mem_src_arr = sg_get_sgat_msa(schp); ksglen = (int)sclp->length; p = sclp->address; for (j = 0, k = 0; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up); if (res) return res; for (; (k < schp->k_use_sg) && p; ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) { ok = (SG_USER_MEM != mem_src_arr[k]); if (usglen <= 0) break; if (ksglen > usglen) { if (usglen >= num_xfer) { if (ok) __copy_from_user(p, up, num_xfer); return 0; } if (ok) __copy_from_user(p, up, usglen); p += usglen; ksglen -= usglen; break; } else { if (ksglen >= num_xfer) { if (ok) __copy_from_user(p, up, num_xfer); return 0; } if (ok) __copy_from_user(p, up, ksglen); up += ksglen; usglen -= ksglen; } } } } return 0;}static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind, int wr_xf, int * countp, unsigned char ** up){ int num_xfer = (int)hp->dxfer_len; unsigned char * p; int count, k; sg_iovec_t u_iovec; if (0 == sg_num) { p = (unsigned char *)hp->dxferp; if (wr_xf && ('\0' == hp->interface_id)) count = (int)hp->flags; /* holds "old" input_size */ else count = num_xfer; } else { __copy_from_user(&u_iovec, (unsigned char *)hp->dxferp + (ind * size_sg_iovec), size_sg_iovec); p = (unsigned char *)u_iovec.iov_base; count = (int)u_iovec.iov_len; } if ((k = verify_area(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count))) return k; if (up) *up = p; if (countp) *countp = count; return 0;}static char * sg_get_sgat_msa(Sg_scatter_hold * schp){ int elem_sz = sizeof(struct scatterlist) + sizeof(char); int mx_sc_elems = (schp->sglist_len / elem_sz) - 1; return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems);}static void sg_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) { int k, mem_src; struct scatterlist * sclp = (struct scatterlist *)schp->buffer; char * mem_src_arr = sg_get_sgat_msa(schp); for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) { mem_src = mem_src_arr[k]; SCSI_LOG_TIMEOUT(5, printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n", k, sclp->address, sclp->length, mem_src)); sg_free(sclp->address, sclp->length, mem_src); sclp->address = NULL; sclp->length = 0; } sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src); } else if (schp->buffer) sg_free(schp->buffer, schp->b_malloc_len, schp->buffer_mem_src); memset(schp, 0, sizeof(*schp));}static int sg_read_xfer(Sg_request * srp){ sg_io_hdr_t * hp = &srp->header; Sg_scatter_hold * schp = &srp->data; int num_xfer = 0; int j, k, onum, usglen, ksglen, res, ok; int iovec_count = (int)hp->iovec_count; int dxfer_dir = hp->dxfer_direction; unsigned char * p; unsigned char * 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) || (new_interface && (SG_FLAG_NO_DXFER & 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 ((k = verify_area(VERIFY_READ, hp->dxferp, size_sg_iovec * onum))) return k; } else onum = 1; if (0 == schp->k_use_sg) { /* kernel has single buffer */ if (SG_USER_MEM != schp->buffer_mem_src) { /* else nothing to do */ for (j = 0, p = schp->buffer; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up); if (res) return res; usglen = (num_xfer > usglen) ? usglen : num_xfer; __copy_to_user(up, p, usglen); p += usglen; num_xfer -= usglen; if (num_xfer <= 0) return 0; } } } else { /* kernel using scatter gather list */ struct scatterlist * sclp = (struct scatterlist *)schp->buffer; char * mem_src_arr = sg_get_sgat_msa(schp); ksglen = (int)sclp->length; p = sclp->address; for (j = 0, k = 0; j < onum; ++j) { res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up); if (res) return res; for (; (k < schp->k_use_sg) && p; ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) { ok = (SG_USER_MEM != mem_src_arr[k]); if (usglen <= 0) break; if (ksglen > usglen) { if (usglen >= num_xfer) { if (ok) __copy_to_user(up, p, num_xfer); return 0; } if (ok) __copy_to_user(up, p, usglen); p += usglen; ksglen -= usglen; break; } else { if (ksglen >= num_xfer) { if (ok) __copy_to_user(up, p, num_xfer); return 0; } if (ok) __copy_to_user(up, p, ksglen); up += ksglen; usglen -= ksglen; } } } } return 0;}static void sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer){ Sg_scatter_hold * schp = &srp->data; SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n", num_read_xfer)); if ((! outp) || (num_read_xfer <= 0)) return; if(schp->k_use_sg > 0) { int k, num; struct scatterlist * sclp = (struct scatterlist *)schp->buffer; for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) { num = (int)sclp->length; if (num > num_read_xfer) { __copy_to_user(outp, sclp->address, num_read_xfer); break; } else { __copy_to_user(outp, sclp->address, num); num_read_xfer -= num; if (num_read_xfer <= 0) break; outp += num; } } } else __copy_to_user(outp, schp->buffer, num_read_xfer);}static void sg_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_indi(schp, sfp, req_size)) return; else sg_remove_scat(schp); req_size >>= 1; /* divide by 2 */ } while (req_size > (PAGE_SIZE / 2));}static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size){ Sg_scatter_hold * req_schp = &srp->data; Sg_scatter_hold * rsv_schp = &sfp->reserve; srp->res_used = 1; SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); size = (size + 1) & (~1); /* round to even for aha1542 */ if (rsv_schp->k_use_sg > 0) { int k, num; int rem = size; struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer; for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) { num = (int)sclp->length; if (rem <= num) { if (0 == k) { req_schp->k_use_sg = 0; req_schp->buffer = sclp->address; } else { sfp->save_scat_len = num; sclp->length = (unsigned)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->buffer_mem_src = rsv_schp->buffer_mem_src; 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")); } else { req_schp->k_use_sg = 0; req_schp->bufflen = size; req_schp->buffer = rsv_schp->buffer; req_schp->buffer_mem_src = rsv_schp->buffer_mem_src; req_schp->b_malloc_len = rsv_schp->b_malloc_len; }}static void sg_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 * sclp = (struct scatterlist *)rsv_schp->buffer; if (sfp->save_scat_len > 0) (sclp + (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_sca
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -