11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/acorn/scsi/scsi.h 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 Russell King 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Commonly used scsi driver functions. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13378f058cc49bcda7fa63d3cd86d2f9a0a5188b1cDavid Hardeman#include <linux/scatterlist.h> 14378f058cc49bcda7fa63d3cd86d2f9a0a5188b1cDavid Hardeman 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BELT_AND_BRACES 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The scatter-gather list handling. This contains all 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the yucky stuff that needs to be fixed properly. 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2184ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh 2284ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh/* 2384ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh * copy_SCp_to_sg() Assumes contiguous allocation at @sg of at-most @max 2484ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh * entries of uninitialized memory. SCp is from scsi-ml and has a valid 2584ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh * (possibly chained) sg-list 2684ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh */ 270a04137e75204e370dbdf2376033853eea126de7Christoph Hellwigstatic inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max) 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bufs = SCp->buffers_residual; 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3184ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh /* FIXME: It should be easy for drivers to loop on copy_SCp_to_sg(). 3284ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh * and to remove this BUG_ON. Use min() in-its-place 3384ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh */ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(bufs + 1 > max); 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36378f058cc49bcda7fa63d3cd86d2f9a0a5188b1cDavid Hardeman sg_set_buf(sg, SCp->ptr, SCp->this_residual); 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3884ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh if (bufs) { 3984ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh struct scatterlist *src_sg; 4084ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh unsigned i; 4184ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh 4284ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh for_each_sg(sg_next(SCp->buffer), src_sg, bufs, i) 4384ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh *(++sg) = *src_sg; 4484ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh sg_mark_end(sg); 4584ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh } 4684ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return bufs + 1; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 500a04137e75204e370dbdf2376033853eea126de7Christoph Hellwigstatic inline int next_SCp(struct scsi_pointer *SCp) 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = SCp->buffers_residual; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 5484ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh SCp->buffer = sg_next(SCp->buffer); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCp->buffers_residual--; 5601c0ad58548fa1fa76379d1bea060f6e1d6ba2afRussell King SCp->ptr = sg_virt(SCp->buffer); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCp->this_residual = SCp->buffer->length; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCp->ptr = NULL; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCp->this_residual = 0; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 650a04137e75204e370dbdf2376033853eea126de7Christoph Hellwigstatic inline unsigned char get_next_SCp_byte(struct scsi_pointer *SCp) 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char c = *SCp->ptr; 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCp->ptr += 1; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCp->this_residual -= 1; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return c; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 750a04137e75204e370dbdf2376033853eea126de7Christoph Hellwigstatic inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *SCp->ptr = c; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCp->ptr += 1; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCp->this_residual -= 1; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82ee0ca6bab394fe41a2b4de58c4532b09a41c9165Henrik Kretzschmarstatic inline void init_SCp(struct scsi_cmnd *SCpnt) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer)); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8684ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh if (scsi_bufflen(SCpnt)) { 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long len = 0; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8984ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh SCpnt->SCp.buffer = scsi_sglist(SCpnt); 9084ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; 9101c0ad58548fa1fa76379d1bea060f6e1d6ba2afRussell King SCpnt->SCp.ptr = sg_virt(SCpnt->SCp.buffer); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; 9384ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh SCpnt->SCp.phase = scsi_bufflen(SCpnt); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BELT_AND_BRACES 9684ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh { /* 9784ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh * Calculate correct buffer length. Some commands 9884ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh * come in with the wrong scsi_bufflen. 9984ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh */ 10084ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh struct scatterlist *sg; 10184ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh unsigned i, sg_count = scsi_sg_count(SCpnt); 10284ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh 10384ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh scsi_for_each_sg(SCpnt, sg, sg_count, i) 10484ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh len += sg->length; 10584ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh 10684ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh if (scsi_bufflen(SCpnt) != len) { 10784ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh printk(KERN_WARNING 10884ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh "scsi%d.%c: bad request buffer " 10984ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh "length %d, should be %ld\n", 11084ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh SCpnt->device->host->host_no, 11184ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh '0' + SCpnt->device->id, 11284ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh scsi_bufflen(SCpnt), len); 11384ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh /* 11484ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh * FIXME: Totaly naive fixup. We should abort 11584ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh * with error 11684ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh */ 11784ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh SCpnt->SCp.phase = 11884ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh min_t(unsigned long, len, 11984ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh scsi_bufflen(SCpnt)); 12084ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh } 12184ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh } 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCpnt->SCp.ptr = NULL; 12584ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh SCpnt->SCp.this_residual = 0; 12684ac86ca8c6787f9efff28bc04b1b65fe0a5c310Boaz Harrosh SCpnt->SCp.phase = 0; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 129