Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2002 Russell King * * Commonly used functions by the ARM SCSI-II drivers. */ #include <linux/scatterlist.h> #define BELT_AND_BRACES struct arm_cmd_priv { struct scsi_pointer scsi_pointer; }; static inline struct scsi_pointer *arm_scsi_pointer(struct scsi_cmnd *cmd) { struct arm_cmd_priv *acmd = scsi_cmd_priv(cmd); return &acmd->scsi_pointer; } /* * The scatter-gather list handling. This contains all * the yucky stuff that needs to be fixed properly. */ /* * copy_SCp_to_sg() Assumes contiguous allocation at @sg of at-most @max * entries of uninitialized memory. SCp is from scsi-ml and has a valid * (possibly chained) sg-list */ static inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max) { int bufs = SCp->buffers_residual; /* FIXME: It should be easy for drivers to loop on copy_SCp_to_sg(). * and to remove this BUG_ON. Use min() in-its-place */ BUG_ON(bufs + 1 > max); sg_set_buf(sg, SCp->ptr, SCp->this_residual); if (bufs) { struct scatterlist *src_sg; unsigned i; for_each_sg(sg_next(SCp->buffer), src_sg, bufs, i) *(++sg) = *src_sg; sg_mark_end(sg); } return bufs + 1; } static inline int next_SCp(struct scsi_pointer *SCp) { int ret = SCp->buffers_residual; if (ret) { SCp->buffer = sg_next(SCp->buffer); SCp->buffers_residual--; SCp->ptr = sg_virt(SCp->buffer); SCp->this_residual = SCp->buffer->length; } else { SCp->ptr = NULL; SCp->this_residual = 0; } return ret; } static inline unsigned char get_next_SCp_byte(struct scsi_pointer *SCp) { char c = *SCp->ptr; SCp->ptr += 1; SCp->this_residual -= 1; return c; } static inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c) { *SCp->ptr = c; SCp->ptr += 1; SCp->this_residual -= 1; } static inline void init_SCp(struct scsi_cmnd *SCpnt) { struct scsi_pointer *scsi_pointer = arm_scsi_pointer(SCpnt); memset(scsi_pointer, 0, sizeof(struct scsi_pointer)); if (scsi_bufflen(SCpnt)) { unsigned long len = 0; scsi_pointer->buffer = scsi_sglist(SCpnt); scsi_pointer->buffers_residual = scsi_sg_count(SCpnt) - 1; scsi_pointer->ptr = sg_virt(scsi_pointer->buffer); scsi_pointer->this_residual = scsi_pointer->buffer->length; scsi_pointer->phase = scsi_bufflen(SCpnt); #ifdef BELT_AND_BRACES { /* * Calculate correct buffer length. Some commands * come in with the wrong scsi_bufflen. */ struct scatterlist *sg; unsigned i, sg_count = scsi_sg_count(SCpnt); scsi_for_each_sg(SCpnt, sg, sg_count, i) len += sg->length; if (scsi_bufflen(SCpnt) != len) { printk(KERN_WARNING "scsi%d.%c: bad request buffer " "length %d, should be %ld\n", SCpnt->device->host->host_no, '0' + SCpnt->device->id, scsi_bufflen(SCpnt), len); /* * FIXME: Totaly naive fixup. We should abort * with error */ scsi_pointer->phase = min_t(unsigned long, len, scsi_bufflen(SCpnt)); } } #endif } else { scsi_pointer->ptr = NULL; scsi_pointer->this_residual = 0; scsi_pointer->phase = 0; } } |