18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/drivers/acorn/scsi/scsi.h
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2002 Russell King
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Commonly used scsi driver functions.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define BELT_AND_BRACES
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * The scatter-gather list handling.  This contains all
168c2ecf20Sopenharmony_ci * the yucky stuff that needs to be fixed properly.
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * copy_SCp_to_sg() Assumes contiguous allocation at @sg of at-most @max
218c2ecf20Sopenharmony_ci * entries of uninitialized memory. SCp is from scsi-ml and has a valid
228c2ecf20Sopenharmony_ci * (possibly chained) sg-list
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_cistatic inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	int bufs = SCp->buffers_residual;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	/* FIXME: It should be easy for drivers to loop on copy_SCp_to_sg().
298c2ecf20Sopenharmony_ci	 * and to remove this BUG_ON. Use min() in-its-place
308c2ecf20Sopenharmony_ci	 */
318c2ecf20Sopenharmony_ci	BUG_ON(bufs + 1 > max);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	sg_set_buf(sg, SCp->ptr, SCp->this_residual);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	if (bufs) {
368c2ecf20Sopenharmony_ci		struct scatterlist *src_sg;
378c2ecf20Sopenharmony_ci		unsigned i;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci		for_each_sg(sg_next(SCp->buffer), src_sg, bufs, i)
408c2ecf20Sopenharmony_ci			*(++sg) = *src_sg;
418c2ecf20Sopenharmony_ci		sg_mark_end(sg);
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	return bufs + 1;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic inline int next_SCp(struct scsi_pointer *SCp)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	int ret = SCp->buffers_residual;
508c2ecf20Sopenharmony_ci	if (ret) {
518c2ecf20Sopenharmony_ci		SCp->buffer = sg_next(SCp->buffer);
528c2ecf20Sopenharmony_ci		SCp->buffers_residual--;
538c2ecf20Sopenharmony_ci		SCp->ptr = sg_virt(SCp->buffer);
548c2ecf20Sopenharmony_ci		SCp->this_residual = SCp->buffer->length;
558c2ecf20Sopenharmony_ci	} else {
568c2ecf20Sopenharmony_ci		SCp->ptr = NULL;
578c2ecf20Sopenharmony_ci		SCp->this_residual = 0;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci	return ret;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic inline unsigned char get_next_SCp_byte(struct scsi_pointer *SCp)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	char c = *SCp->ptr;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	SCp->ptr += 1;
678c2ecf20Sopenharmony_ci	SCp->this_residual -= 1;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	return c;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	*SCp->ptr = c;
758c2ecf20Sopenharmony_ci	SCp->ptr += 1;
768c2ecf20Sopenharmony_ci	SCp->this_residual -= 1;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic inline void init_SCp(struct scsi_cmnd *SCpnt)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (scsi_bufflen(SCpnt)) {
848c2ecf20Sopenharmony_ci		unsigned long len = 0;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		SCpnt->SCp.buffer = scsi_sglist(SCpnt);
878c2ecf20Sopenharmony_ci		SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
888c2ecf20Sopenharmony_ci		SCpnt->SCp.ptr = sg_virt(SCpnt->SCp.buffer);
898c2ecf20Sopenharmony_ci		SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
908c2ecf20Sopenharmony_ci		SCpnt->SCp.phase = scsi_bufflen(SCpnt);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#ifdef BELT_AND_BRACES
938c2ecf20Sopenharmony_ci		{	/*
948c2ecf20Sopenharmony_ci			 * Calculate correct buffer length.  Some commands
958c2ecf20Sopenharmony_ci			 * come in with the wrong scsi_bufflen.
968c2ecf20Sopenharmony_ci			 */
978c2ecf20Sopenharmony_ci			struct scatterlist *sg;
988c2ecf20Sopenharmony_ci			unsigned i, sg_count = scsi_sg_count(SCpnt);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci			scsi_for_each_sg(SCpnt, sg, sg_count, i)
1018c2ecf20Sopenharmony_ci				len += sg->length;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci			if (scsi_bufflen(SCpnt) != len) {
1048c2ecf20Sopenharmony_ci				printk(KERN_WARNING
1058c2ecf20Sopenharmony_ci				       "scsi%d.%c: bad request buffer "
1068c2ecf20Sopenharmony_ci				       "length %d, should be %ld\n",
1078c2ecf20Sopenharmony_ci					SCpnt->device->host->host_no,
1088c2ecf20Sopenharmony_ci					'0' + SCpnt->device->id,
1098c2ecf20Sopenharmony_ci					scsi_bufflen(SCpnt), len);
1108c2ecf20Sopenharmony_ci				/*
1118c2ecf20Sopenharmony_ci				 * FIXME: Totaly naive fixup. We should abort
1128c2ecf20Sopenharmony_ci				 * with error
1138c2ecf20Sopenharmony_ci				 */
1148c2ecf20Sopenharmony_ci				SCpnt->SCp.phase =
1158c2ecf20Sopenharmony_ci					min_t(unsigned long, len,
1168c2ecf20Sopenharmony_ci					      scsi_bufflen(SCpnt));
1178c2ecf20Sopenharmony_ci			}
1188c2ecf20Sopenharmony_ci		}
1198c2ecf20Sopenharmony_ci#endif
1208c2ecf20Sopenharmony_ci	} else {
1218c2ecf20Sopenharmony_ci		SCpnt->SCp.ptr = NULL;
1228c2ecf20Sopenharmony_ci		SCpnt->SCp.this_residual = 0;
1238c2ecf20Sopenharmony_ci		SCpnt->SCp.phase = 0;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci}
126