scsi.h revision ee0ca6bab394fe41a2b4de58c4532b09a41c9165
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 */
210a04137e75204e370dbdf2376033853eea126de7Christoph Hellwigstatic inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max)
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bufs = SCp->buffers_residual;
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUG_ON(bufs + 1 > max);
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27378f058cc49bcda7fa63d3cd86d2f9a0a5188b1cDavid Hardeman	sg_set_buf(sg, SCp->ptr, SCp->this_residual);
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (bufs)
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		memcpy(sg + 1, SCp->buffer + 1,
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       sizeof(struct scatterlist) * bufs);
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return bufs + 1;
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
350a04137e75204e370dbdf2376033853eea126de7Christoph Hellwigstatic inline int next_SCp(struct scsi_pointer *SCp)
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = SCp->buffers_residual;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCp->buffer++;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCp->buffers_residual--;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCp->ptr = (char *)
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 (page_address(SCp->buffer->page) +
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  SCp->buffer->offset);
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCp->this_residual = SCp->buffer->length;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCp->ptr = NULL;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCp->this_residual = 0;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
520a04137e75204e370dbdf2376033853eea126de7Christoph Hellwigstatic inline unsigned char get_next_SCp_byte(struct scsi_pointer *SCp)
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c = *SCp->ptr;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCp->ptr += 1;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCp->this_residual -= 1;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return c;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
620a04137e75204e370dbdf2376033853eea126de7Christoph Hellwigstatic inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*SCp->ptr = c;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCp->ptr += 1;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SCp->this_residual -= 1;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
69ee0ca6bab394fe41a2b4de58c4532b09a41c9165Henrik Kretzschmarstatic inline void init_SCp(struct scsi_cmnd *SCpnt)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (SCpnt->use_sg) {
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long len = 0;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int buf;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
77574dc0abab6650c5371df15ac708e48fa25bed89Russell King		SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCpnt->SCp.ptr = (char *)
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 (page_address(SCpnt->SCp.buffer->page) +
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  SCpnt->SCp.buffer->offset);
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef BELT_AND_BRACES
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Calculate correct buffer length.  Some commands
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * come in with the wrong request_bufflen.
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++)
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len += SCpnt->SCp.buffer[buf].length;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (SCpnt->request_bufflen != len)
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "scsi%d.%c: bad request buffer "
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "length %d, should be %ld\n", SCpnt->device->host->host_no,
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       '0' + SCpnt->device->id, SCpnt->request_bufflen, len);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCpnt->request_bufflen = len;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCpnt->SCp.this_residual = SCpnt->request_bufflen;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If the upper SCSI layers pass a buffer, but zero length,
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * we aren't interested in the buffer pointer.
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) {
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 //def BELT_AND_BRACES
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for "
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "command ", SCpnt->host->host_no, '0' + SCpnt->target);
111db9dff366ba78085d0323364fadbf09bec0e77ee<hch@lst.de>		__scsi_print_command(SCpnt->cmnd);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		SCpnt->SCp.ptr = NULL;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
116