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 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 SCpnt->SCp.phase = 111 min_t(unsigned long, len, 112 scsi_bufflen(SCpnt)); 113 } 114 } 115#endif 116 } else { 117 SCpnt->SCp.ptr = NULL; 118 SCpnt->SCp.this_residual = 0; 119 SCpnt->SCp.phase = 0; 120 } 121} 122