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