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