xref: /openbmc/linux/drivers/scsi/scsi_debug.c (revision 185dd232)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
31da177e4SLinus Torvalds  *  Copyright (C) 1992  Eric Youngdale
41da177e4SLinus Torvalds  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
51da177e4SLinus Torvalds  *  to make sure that we are not getting blocks mixed up, and PANIC if
61da177e4SLinus Torvalds  *  anything out of the ordinary is seen.
71da177e4SLinus Torvalds  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
81da177e4SLinus Torvalds  *
9773642d9SDouglas Gilbert  * Copyright (C) 2001 - 2016 Douglas Gilbert
101da177e4SLinus Torvalds  *
11773642d9SDouglas Gilbert  * This program is free software; you can redistribute it and/or modify
12773642d9SDouglas Gilbert  * it under the terms of the GNU General Public License as published by
13773642d9SDouglas Gilbert  * the Free Software Foundation; either version 2, or (at your option)
14773642d9SDouglas Gilbert  * any later version.
151da177e4SLinus Torvalds  *
1678d4e5a0SDouglas Gilbert  *  For documentation see http://sg.danny.cz/sg/sdebug26.html
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  */
191da177e4SLinus Torvalds 
20c1287970STomas Winkler 
21c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22c1287970STomas Winkler 
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <linux/kernel.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
271da177e4SLinus Torvalds #include <linux/timer.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
291da177e4SLinus Torvalds #include <linux/types.h>
301da177e4SLinus Torvalds #include <linux/string.h>
311da177e4SLinus Torvalds #include <linux/genhd.h>
321da177e4SLinus Torvalds #include <linux/fs.h>
331da177e4SLinus Torvalds #include <linux/init.h>
341da177e4SLinus Torvalds #include <linux/proc_fs.h>
351da177e4SLinus Torvalds #include <linux/vmalloc.h>
361da177e4SLinus Torvalds #include <linux/moduleparam.h>
37852e034dSJens Axboe #include <linux/scatterlist.h>
381da177e4SLinus Torvalds #include <linux/blkdev.h>
39c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h>
40cbf67842SDouglas Gilbert #include <linux/spinlock.h>
41cbf67842SDouglas Gilbert #include <linux/interrupt.h>
42cbf67842SDouglas Gilbert #include <linux/atomic.h>
43cbf67842SDouglas Gilbert #include <linux/hrtimer.h>
44c6a44287SMartin K. Petersen 
45c6a44287SMartin K. Petersen #include <net/checksum.h>
469ff26eefSFUJITA Tomonori 
4744d92694SMartin K. Petersen #include <asm/unaligned.h>
4844d92694SMartin K. Petersen 
499ff26eefSFUJITA Tomonori #include <scsi/scsi.h>
509ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h>
519ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h>
521da177e4SLinus Torvalds #include <scsi/scsi_host.h>
531da177e4SLinus Torvalds #include <scsi/scsicam.h>
54a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h>
55cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h>
56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h>
571da177e4SLinus Torvalds 
58c6a44287SMartin K. Petersen #include "sd.h"
591da177e4SLinus Torvalds #include "scsi_logging.h"
601da177e4SLinus Torvalds 
61773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */
62773642d9SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.86"
63773642d9SDouglas Gilbert static const char *sdebug_version_date = "20160422";
64cbf67842SDouglas Gilbert 
65cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug"
661da177e4SLinus Torvalds 
676f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */
68c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0
69c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4
70c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
711da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11
72c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a
731da177e4SLinus Torvalds #define INVALID_OPCODE 0x20
7422017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21
751da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24
76c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26
77cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29
78cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a
7919c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f
8019c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e
8122017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55
8222017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3
83cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0
84cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
85cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
8622017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9
871da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39
886f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b
89c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d
90c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e
9122017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d
92acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
93acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
941da177e4SLinus Torvalds 
956f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */
966f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3
976f3cbf55SDouglas Gilbert 
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds /* Default values for driver parameters */
1001da177e4SLinus Torvalds #define DEF_NUM_HOST   1
1011da177e4SLinus Torvalds #define DEF_NUM_TGTS   1
1021da177e4SLinus Torvalds #define DEF_MAX_LUNS   1
1031da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target
1041da177e4SLinus Torvalds  * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1051da177e4SLinus Torvalds  */
1065b94e232SMartin K. Petersen #define DEF_ATO 1
107cbf67842SDouglas Gilbert #define DEF_DELAY   1		/* if > 0 unit is a jiffy */
1081da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB   8
1095b94e232SMartin K. Petersen #define DEF_DIF 0
1105b94e232SMartin K. Petersen #define DEF_DIX 0
1115b94e232SMartin K. Petersen #define DEF_D_SENSE   0
1121da177e4SLinus Torvalds #define DEF_EVERY_NTH   0
1135b94e232SMartin K. Petersen #define DEF_FAKE_RW	0
1145b94e232SMartin K. Petersen #define DEF_GUARD 0
115cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0
1165b94e232SMartin K. Petersen #define DEF_LBPU 0
1175b94e232SMartin K. Petersen #define DEF_LBPWS 0
1185b94e232SMartin K. Petersen #define DEF_LBPWS10 0
119be1dd78dSEric Sandeen #define DEF_LBPRZ 1
1205b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0
121cbf67842SDouglas Gilbert #define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1225b94e232SMartin K. Petersen #define DEF_NO_LUN_0   0
1231da177e4SLinus Torvalds #define DEF_NUM_PARTS   0
1241da177e4SLinus Torvalds #define DEF_OPTS   0
12532c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024
1265b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0
1275b94e232SMartin K. Petersen #define DEF_PTYPE   0
128d986788bSMartin Pitt #define DEF_REMOVABLE false
129e46b0344SDouglas Gilbert #define DEF_SCSI_LEVEL   6    /* INQUIRY, byte2 [6->SPC-4] */
1305b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512
1315b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0
1325b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1
1336014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1346014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256
1355b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB   0
1365b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1
1375b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF
138c2248fc9SDouglas Gilbert #define DEF_STRICT 0
139cbf67842SDouglas Gilbert #define DELAY_OVERRIDDEN -9999
1401da177e4SLinus Torvalds 
141773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */
142773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE		1
143773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR		2
144773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT		4
145773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR	8
146773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR	16
147773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR		32
148773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR		64
149773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT		128
150773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER	0x100
151773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE		0x200
152773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF		0x400
153773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF		0x800
154773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE		0x1000
155773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE		0x2000
156773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE		0x4000
157773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
158773642d9SDouglas Gilbert 			      SDEBUG_OPT_RESET_NOISE)
159773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
160773642d9SDouglas Gilbert 				  SDEBUG_OPT_TRANSPORT_ERR | \
161773642d9SDouglas Gilbert 				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
162773642d9SDouglas Gilbert 				  SDEBUG_OPT_SHORT_TRANSFER)
1631da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands:
164773642d9SDouglas Gilbert  *   - a no response is simulated if SDEBUG_OPT_TIMEOUT is set
1651da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
166773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1676f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
168773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_TRANSPORT_ERR is set.
1691da177e4SLinus Torvalds  *
1701da177e4SLinus Torvalds  * When "every_nth" < 0 then after "- every_nth" commands:
171773642d9SDouglas Gilbert  *   - a no response is simulated if SDEBUG_OPT_TIMEOUT is set
1721da177e4SLinus Torvalds  *   - a RECOVERED_ERROR is simulated on successful read and write
173773642d9SDouglas Gilbert  *     commands if SDEBUG_OPT_RECOVERED_ERR is set.
1746f3cbf55SDouglas Gilbert  *   - a TRANSPORT_ERROR is simulated on successful read and write
175773642d9SDouglas Gilbert  *     commands if _DEBUG_OPT_TRANSPORT_ERR is set.
176773642d9SDouglas Gilbert  * This will continue on every subsequent command until some other action
177773642d9SDouglas Gilbert  * occurs (e.g. the user * writing a new value (other than -1 or 1) to
178773642d9SDouglas Gilbert  * every_nth via sysfs).
1791da177e4SLinus Torvalds  */
1801da177e4SLinus Torvalds 
181cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in
182cbf67842SDouglas Gilbert  * priority order. In the subset implemented here lower numbers have higher
183cbf67842SDouglas Gilbert  * priority. The UA numbers should be a sequence starting from 0 with
184cbf67842SDouglas Gilbert  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
185cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
186cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1
187cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2
1880d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3
18919c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4
190acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
191acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
192acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7
193cbf67842SDouglas Gilbert 
194cbf67842SDouglas Gilbert /* for check_readiness() */
195c2248fc9SDouglas Gilbert #define UAS_ONLY 1	/* check for UAs only */
196c2248fc9SDouglas Gilbert #define UAS_TUR 0	/* if no UAs then check if media access possible */
197cbf67842SDouglas Gilbert 
198773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
1991da177e4SLinus Torvalds  * sector on read commands: */
2001da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
20132f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
2041da177e4SLinus Torvalds  * or "peripheral device" addressing (value 0) */
2051da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0
2061da177e4SLinus Torvalds 
207cbf67842SDouglas Gilbert /* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
208cbf67842SDouglas Gilbert  * (for response) at one time. Can be reduced by max_queue option. Command
209cbf67842SDouglas Gilbert  * responses are not queued when delay=0 and ndelay=0. The per-device
210cbf67842SDouglas Gilbert  * DEF_CMD_PER_LUN can be changed via sysfs:
211cbf67842SDouglas Gilbert  * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
212cbf67842SDouglas Gilbert  * SCSI_DEBUG_CANQUEUE. */
213cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE_WORDS  9	/* a WORD is bits in a long */
214cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE  (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
215cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN  255
216cbf67842SDouglas Gilbert 
217cbf67842SDouglas Gilbert #if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
218cbf67842SDouglas Gilbert #warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
219cbf67842SDouglas Gilbert #endif
22078d4e5a0SDouglas Gilbert 
221c2248fc9SDouglas Gilbert /* SCSI opcodes (first byte of cdb) mapped onto these indexes */
222c2248fc9SDouglas Gilbert enum sdeb_opcode_index {
223c2248fc9SDouglas Gilbert 	SDEB_I_INVALID_OPCODE =	0,
224c2248fc9SDouglas Gilbert 	SDEB_I_INQUIRY = 1,
225c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS = 2,
226c2248fc9SDouglas Gilbert 	SDEB_I_REQUEST_SENSE = 3,
227c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY = 4,
228c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
229c2248fc9SDouglas Gilbert 	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
230c2248fc9SDouglas Gilbert 	SDEB_I_LOG_SENSE = 7,
231c2248fc9SDouglas Gilbert 	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
232c2248fc9SDouglas Gilbert 	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
233c2248fc9SDouglas Gilbert 	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
234c2248fc9SDouglas Gilbert 	SDEB_I_START_STOP = 11,
235c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_IN = 12,	/* 12, 16 */
236c2248fc9SDouglas Gilbert 	SDEB_I_SERV_ACT_OUT = 13,	/* 12, 16 */
237c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_IN = 14,
238c2248fc9SDouglas Gilbert 	SDEB_I_MAINT_OUT = 15,
239c2248fc9SDouglas Gilbert 	SDEB_I_VERIFY = 16,		/* 10 only */
240c2248fc9SDouglas Gilbert 	SDEB_I_VARIABLE_LEN = 17,
241c2248fc9SDouglas Gilbert 	SDEB_I_RESERVE = 18,		/* 6, 10 */
242c2248fc9SDouglas Gilbert 	SDEB_I_RELEASE = 19,		/* 6, 10 */
243c2248fc9SDouglas Gilbert 	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
244c2248fc9SDouglas Gilbert 	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
245c2248fc9SDouglas Gilbert 	SDEB_I_ATA_PT = 22,		/* 12, 16 */
246c2248fc9SDouglas Gilbert 	SDEB_I_SEND_DIAG = 23,
247c2248fc9SDouglas Gilbert 	SDEB_I_UNMAP = 24,
248c2248fc9SDouglas Gilbert 	SDEB_I_XDWRITEREAD = 25,	/* 10 only */
249c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_BUFFER = 26,
250c2248fc9SDouglas Gilbert 	SDEB_I_WRITE_SAME = 27,		/* 10, 16 */
251c2248fc9SDouglas Gilbert 	SDEB_I_SYNC_CACHE = 28,		/* 10 only */
252c2248fc9SDouglas Gilbert 	SDEB_I_COMP_WRITE = 29,
253c2248fc9SDouglas Gilbert 	SDEB_I_LAST_ELEMENT = 30,	/* keep this last */
254c2248fc9SDouglas Gilbert };
255c2248fc9SDouglas Gilbert 
256c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = {
257c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */
258c2248fc9SDouglas Gilbert 	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
259c2248fc9SDouglas Gilbert 	    0, 0, 0, 0,
260c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
261c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
262c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
263c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
264c2248fc9SDouglas Gilbert 	    SDEB_I_ALLOW_REMOVAL, 0,
265c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */
266c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
267c2248fc9SDouglas Gilbert 	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
268c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
269c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
270c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */
271c2248fc9SDouglas Gilbert 	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
272c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
273c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
274c2248fc9SDouglas Gilbert 	    SDEB_I_RELEASE,
275c2248fc9SDouglas Gilbert 	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
276c2248fc9SDouglas Gilbert /* 0x60; 0x60->0x7d are reserved */
277c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
279c2248fc9SDouglas Gilbert 	0, SDEB_I_VARIABLE_LEN,
280c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */
281c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
282c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
283c2248fc9SDouglas Gilbert 	0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
284c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
285c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */
286c2248fc9SDouglas Gilbert 	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
287c2248fc9SDouglas Gilbert 	     SDEB_I_MAINT_OUT, 0, 0, 0,
288c2248fc9SDouglas Gilbert 	SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
289c2248fc9SDouglas Gilbert 	     0, 0, 0, 0,
290c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
291c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0,
292c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */
293c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
294c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
295c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296c2248fc9SDouglas Gilbert 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
297c2248fc9SDouglas Gilbert };
298c2248fc9SDouglas Gilbert 
299c2248fc9SDouglas Gilbert #define F_D_IN			1
300c2248fc9SDouglas Gilbert #define F_D_OUT			2
301c2248fc9SDouglas Gilbert #define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
302c2248fc9SDouglas Gilbert #define F_D_UNKN		8
303c2248fc9SDouglas Gilbert #define F_RL_WLUN_OK		0x10
304c2248fc9SDouglas Gilbert #define F_SKIP_UA		0x20
305c2248fc9SDouglas Gilbert #define F_DELAY_OVERR		0x40
306c2248fc9SDouglas Gilbert #define F_SA_LOW		0x80	/* cdb byte 1, bits 4 to 0 */
307c2248fc9SDouglas Gilbert #define F_SA_HIGH		0x100	/* as used by variable length cdbs */
308c2248fc9SDouglas Gilbert #define F_INV_OP		0x200
309c2248fc9SDouglas Gilbert #define F_FAKE_RW		0x400
310c2248fc9SDouglas Gilbert #define F_M_ACCESS		0x800	/* media access */
311c2248fc9SDouglas Gilbert 
312c2248fc9SDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
313c2248fc9SDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
314c2248fc9SDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW)
315c2248fc9SDouglas Gilbert 
316c2248fc9SDouglas Gilbert struct sdebug_dev_info;
317c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
318c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
319c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
320c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
321c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
322c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
323c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
324c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
325c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
326c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
327c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
328c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
329c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
330c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
33138d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
33238d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
333c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
334c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
335c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
33638d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
337acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
338c2248fc9SDouglas Gilbert 
339c2248fc9SDouglas Gilbert struct opcode_info_t {
340c2248fc9SDouglas Gilbert 	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff
341c2248fc9SDouglas Gilbert 				 * for terminating element */
342c2248fc9SDouglas Gilbert 	u8 opcode;		/* if num_attached > 0, preferred */
343c2248fc9SDouglas Gilbert 	u16 sa;			/* service action */
344c2248fc9SDouglas Gilbert 	u32 flags;		/* OR-ed set of SDEB_F_* */
345c2248fc9SDouglas Gilbert 	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
346c2248fc9SDouglas Gilbert 	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
347c2248fc9SDouglas Gilbert 	u8 len_mask[16];	/* len=len_mask[0], then mask for cdb[1]... */
348c2248fc9SDouglas Gilbert 				/* ignore cdb bytes after position 15 */
349c2248fc9SDouglas Gilbert };
350c2248fc9SDouglas Gilbert 
351c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = {
352c2248fc9SDouglas Gilbert 	{0, 0x1a, 0, F_D_IN, NULL, NULL,
353c2248fc9SDouglas Gilbert 	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
354c2248fc9SDouglas Gilbert };
355c2248fc9SDouglas Gilbert 
356c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = {
357c2248fc9SDouglas Gilbert 	{0, 0x15, 0, F_D_OUT, NULL, NULL,
358c2248fc9SDouglas Gilbert 	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
359c2248fc9SDouglas Gilbert };
360c2248fc9SDouglas Gilbert 
361c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = {
362c2248fc9SDouglas Gilbert 	{0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
363c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
364c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
365c2248fc9SDouglas Gilbert 	{0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
366c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
367c2248fc9SDouglas Gilbert 	{0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
368c2248fc9SDouglas Gilbert 	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
369c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
370c2248fc9SDouglas Gilbert };
371c2248fc9SDouglas Gilbert 
372c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = {
373c2248fc9SDouglas Gilbert 	{0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 10 */
374c2248fc9SDouglas Gilbert 	    {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
375c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
376c2248fc9SDouglas Gilbert 	{0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,    /* 6 */
377c2248fc9SDouglas Gilbert 	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
378c2248fc9SDouglas Gilbert 	{0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL,   /* 12 */
379c2248fc9SDouglas Gilbert 	    {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
380c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
381c2248fc9SDouglas Gilbert };
382c2248fc9SDouglas Gilbert 
383c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = {
384c2248fc9SDouglas Gilbert 	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
385c2248fc9SDouglas Gilbert 	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
386c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0, 0xc7} },
387c2248fc9SDouglas Gilbert };
388c2248fc9SDouglas Gilbert 
389c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = {	/* VARIABLE LENGTH */
390c2248fc9SDouglas Gilbert 	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
391c2248fc9SDouglas Gilbert 	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
392c2248fc9SDouglas Gilbert 		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
393c2248fc9SDouglas Gilbert };
394c2248fc9SDouglas Gilbert 
395c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = {
39638d5c833SDouglas Gilbert 	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
397c2248fc9SDouglas Gilbert 	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
398c2248fc9SDouglas Gilbert 	     0xc7, 0, 0, 0, 0} },
39938d5c833SDouglas Gilbert 	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
400c2248fc9SDouglas Gilbert 	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
401c2248fc9SDouglas Gilbert 	     0, 0} },
402c2248fc9SDouglas Gilbert };
403c2248fc9SDouglas Gilbert 
404c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = {
405c2248fc9SDouglas Gilbert 	{0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
406c2248fc9SDouglas Gilbert 	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
407c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1f, 0xc7} },
408c2248fc9SDouglas Gilbert };
409c2248fc9SDouglas Gilbert 
410c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = {
411c2248fc9SDouglas Gilbert 	{0, 0x16, 0, F_D_OUT, NULL, NULL,	/* RESERVE(6) */
412c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
413c2248fc9SDouglas Gilbert };
414c2248fc9SDouglas Gilbert 
415c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = {
416c2248fc9SDouglas Gilbert 	{0, 0x17, 0, F_D_OUT, NULL, NULL,	/* RELEASE(6) */
417c2248fc9SDouglas Gilbert 	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
418c2248fc9SDouglas Gilbert };
419c2248fc9SDouglas Gilbert 
420c2248fc9SDouglas Gilbert 
421c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped,
422c2248fc9SDouglas Gilbert  * plus the terminating elements for logic that scans this table such as
423c2248fc9SDouglas Gilbert  * REPORT SUPPORTED OPERATION CODES. */
424c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
425c2248fc9SDouglas Gilbert /* 0 */
426c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
427c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
428c2248fc9SDouglas Gilbert 	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
429c2248fc9SDouglas Gilbert 	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
430c2248fc9SDouglas Gilbert 	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
431c2248fc9SDouglas Gilbert 	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
432c2248fc9SDouglas Gilbert 	     0, 0} },
433c2248fc9SDouglas Gilbert 	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
434c2248fc9SDouglas Gilbert 	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
435c2248fc9SDouglas Gilbert 	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
436c2248fc9SDouglas Gilbert 	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
437c2248fc9SDouglas Gilbert 	{1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
438c2248fc9SDouglas Gilbert 	    {10,  0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
439c2248fc9SDouglas Gilbert 	     0} },
440c2248fc9SDouglas Gilbert 	{1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
441c2248fc9SDouglas Gilbert 	    {10,  0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
442c2248fc9SDouglas Gilbert 	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
443c2248fc9SDouglas Gilbert 	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
444c2248fc9SDouglas Gilbert 	     0, 0, 0} },
445c2248fc9SDouglas Gilbert 	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,
446c2248fc9SDouglas Gilbert 	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
447c2248fc9SDouglas Gilbert 	     0, 0} },
448c2248fc9SDouglas Gilbert 	{3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
449c2248fc9SDouglas Gilbert 	    {16,  0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
450c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* READ(16) */
451c2248fc9SDouglas Gilbert /* 10 */
452c2248fc9SDouglas Gilbert 	{3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
453c2248fc9SDouglas Gilbert 	    {16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
454c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x9f, 0xc7} },		/* WRITE(16) */
455c2248fc9SDouglas Gilbert 	{0, 0x1b, 0, 0, resp_start_stop, NULL,		/* START STOP UNIT */
456c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
457c2248fc9SDouglas Gilbert 	{1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
458c2248fc9SDouglas Gilbert 	    {16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
459c2248fc9SDouglas Gilbert 	     0xff, 0xff, 0xff, 0x1, 0xc7} },	/* READ CAPACITY(16) */
460c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
461c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
462c2248fc9SDouglas Gilbert 	{2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
463c2248fc9SDouglas Gilbert 	    {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
464c2248fc9SDouglas Gilbert 	     0} },
465c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
466c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
467f7f9f26bSDouglas Gilbert 	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
468f7f9f26bSDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
469f7f9f26bSDouglas Gilbert 	     0, 0, 0, 0, 0, 0} },
470c2248fc9SDouglas Gilbert 	{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
471c2248fc9SDouglas Gilbert 	    vl_iarr, {32,  0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
472c2248fc9SDouglas Gilbert 		      0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
473c2248fc9SDouglas Gilbert 	{1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
474c2248fc9SDouglas Gilbert 	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
475c2248fc9SDouglas Gilbert 	     0} },
476c2248fc9SDouglas Gilbert 	{1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
477c2248fc9SDouglas Gilbert 	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
478c2248fc9SDouglas Gilbert 	     0} },
479c2248fc9SDouglas Gilbert /* 20 */
480f7f9f26bSDouglas Gilbert 	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
481f7f9f26bSDouglas Gilbert 	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
482c2248fc9SDouglas Gilbert 	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
483c2248fc9SDouglas Gilbert 	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
484c2248fc9SDouglas Gilbert 	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
485c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
486c2248fc9SDouglas Gilbert 	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
487c2248fc9SDouglas Gilbert 	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
488c2248fc9SDouglas Gilbert 	{0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
489c2248fc9SDouglas Gilbert 	    {10,  0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
490c2248fc9SDouglas Gilbert 	{0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
491c2248fc9SDouglas Gilbert 	    NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
492c2248fc9SDouglas Gilbert 		   0, 0, 0, 0, 0, 0} },
493acafd0b9SEwan D. Milne 	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
494acafd0b9SEwan D. Milne 	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
495acafd0b9SEwan D. Milne 	     0, 0, 0, 0} },			/* WRITE_BUFFER */
496c2248fc9SDouglas Gilbert 	{1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
497c2248fc9SDouglas Gilbert 	    write_same_iarr, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
498c2248fc9SDouglas Gilbert 			      0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
499c2248fc9SDouglas Gilbert 	{0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
500c2248fc9SDouglas Gilbert 	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
501c2248fc9SDouglas Gilbert 	     0, 0, 0, 0} },
50238d5c833SDouglas Gilbert 	{0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
503c2248fc9SDouglas Gilbert 	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
504c2248fc9SDouglas Gilbert 	     0, 0xff, 0x1f, 0xc7} },		/* COMPARE AND WRITE */
505c2248fc9SDouglas Gilbert 
506c2248fc9SDouglas Gilbert /* 30 */
507c2248fc9SDouglas Gilbert 	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
508c2248fc9SDouglas Gilbert 	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
509c2248fc9SDouglas Gilbert };
510c2248fc9SDouglas Gilbert 
511817fd66bSDouglas Gilbert struct sdebug_scmd_extra_t {
512817fd66bSDouglas Gilbert 	bool inj_recovered;
513817fd66bSDouglas Gilbert 	bool inj_transport;
514817fd66bSDouglas Gilbert 	bool inj_dif;
515817fd66bSDouglas Gilbert 	bool inj_dix;
516817fd66bSDouglas Gilbert 	bool inj_short;
517817fd66bSDouglas Gilbert };
518817fd66bSDouglas Gilbert 
519773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST;
520773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO;
521773642d9SDouglas Gilbert static int sdebug_delay = DEF_DELAY;
522773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
523773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF;
524773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX;
525773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE;
526773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH;
527773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW;
528773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD;
529773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
530773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS;
531773642d9SDouglas Gilbert static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE;
532cbf67842SDouglas Gilbert static atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
533773642d9SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY;
534773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0;
535773642d9SDouglas Gilbert static int sdebug_no_uld;
536773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS;
537773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
538773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS;
539773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS;
540773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
541773642d9SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
542773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL;
543773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE;
544773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
545773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
546773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU;
547773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS;
548773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
549773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ;
550773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
551773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
552773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
553773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
554773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
555773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE;
556773642d9SDouglas Gilbert static bool sdebug_clustering;
557773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK;
558773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT;
559817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt;
560773642d9SDouglas Gilbert static bool sdebug_verbose;
5611da177e4SLinus Torvalds 
562cbf67842SDouglas Gilbert static atomic_t sdebug_cmnd_count;
563cbf67842SDouglas Gilbert static atomic_t sdebug_completions;
564cbf67842SDouglas Gilbert static atomic_t sdebug_a_tsf;		/* counter of 'almost' TSFs */
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds #define DEV_READONLY(TGT)      (0)
5671da177e4SLinus Torvalds 
568c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors;
5691da177e4SLinus Torvalds static sector_t sdebug_capacity;	/* in sectors */
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages
5721da177e4SLinus Torvalds    may still need them */
5731da177e4SLinus Torvalds static int sdebug_heads;		/* heads per disk */
5741da177e4SLinus Torvalds static int sdebug_cylinders_per;	/* cylinders per surface */
5751da177e4SLinus Torvalds static int sdebug_sectors_per;		/* sectors per cylinder */
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4
5781da177e4SLinus Torvalds 
579395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32
5809e603ca0SFUJITA Tomonori 
5815b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void)
5825b94e232SMartin K. Petersen {
583773642d9SDouglas Gilbert 	return 0 == sdebug_fake_rw &&
584773642d9SDouglas Gilbert 		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
5855b94e232SMartin K. Petersen }
5865b94e232SMartin K. Petersen 
5871da177e4SLinus Torvalds struct sdebug_dev_info {
5881da177e4SLinus Torvalds 	struct list_head dev_list;
5891da177e4SLinus Torvalds 	unsigned int channel;
5901da177e4SLinus Torvalds 	unsigned int target;
5919cb78c16SHannes Reinecke 	u64 lun;
5921da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
593cbf67842SDouglas Gilbert 	unsigned long uas_bm[1];
594cbf67842SDouglas Gilbert 	atomic_t num_in_q;
595c2248fc9SDouglas Gilbert 	char stopped;		/* TODO: should be atomic */
596c2248fc9SDouglas Gilbert 	bool used;
5971da177e4SLinus Torvalds };
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds struct sdebug_host_info {
6001da177e4SLinus Torvalds 	struct list_head host_list;
6011da177e4SLinus Torvalds 	struct Scsi_Host *shost;
6021da177e4SLinus Torvalds 	struct device dev;
6031da177e4SLinus Torvalds 	struct list_head dev_info_list;
6041da177e4SLinus Torvalds };
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds #define to_sdebug_host(d)	\
6071da177e4SLinus Torvalds 	container_of(d, struct sdebug_host_info, dev)
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list);
6101da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock);
6111da177e4SLinus Torvalds 
612cbf67842SDouglas Gilbert 
613cbf67842SDouglas Gilbert struct sdebug_hrtimer {		/* ... is derived from hrtimer */
614cbf67842SDouglas Gilbert 	struct hrtimer hrt;	/* must be first element */
615cbf67842SDouglas Gilbert 	int qa_indx;
616cbf67842SDouglas Gilbert };
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds struct sdebug_queued_cmd {
619cbf67842SDouglas Gilbert 	/* in_use flagged by a bit in queued_in_use_bm[] */
620cbf67842SDouglas Gilbert 	struct timer_list *cmnd_timerp;
621cbf67842SDouglas Gilbert 	struct tasklet_struct *tletp;
622cbf67842SDouglas Gilbert 	struct sdebug_hrtimer *sd_hrtp;
6231da177e4SLinus Torvalds 	struct scsi_cmnd * a_cmnd;
6241da177e4SLinus Torvalds };
6251da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
626cbf67842SDouglas Gilbert static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
627cbf67842SDouglas Gilbert 
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds static unsigned char * fake_storep;	/* ramdisk storage */
630e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep;	/* protection info */
63144d92694SMartin K. Petersen static void *map_storep;		/* provisioning map */
6321da177e4SLinus Torvalds 
63344d92694SMartin K. Petersen static unsigned long map_size;
634cbf67842SDouglas Gilbert static int num_aborts;
635cbf67842SDouglas Gilbert static int num_dev_resets;
636cbf67842SDouglas Gilbert static int num_target_resets;
637cbf67842SDouglas Gilbert static int num_bus_resets;
638cbf67842SDouglas Gilbert static int num_host_resets;
639c6a44287SMartin K. Petersen static int dix_writes;
640c6a44287SMartin K. Petersen static int dix_reads;
641c6a44287SMartin K. Petersen static int dif_errors;
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock);
6441da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw);
6451da177e4SLinus Torvalds 
646cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME;
647cbf67842SDouglas Gilbert static const char *my_name = MY_NAME;
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus;
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = {
6521da177e4SLinus Torvalds 	.name 		= sdebug_proc_name,
6531da177e4SLinus Torvalds 	.bus		= &pseudo_lld_bus,
6541da177e4SLinus Torvalds };
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds static const int check_condition_result =
6571da177e4SLinus Torvalds 		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
6581da177e4SLinus Torvalds 
659c6a44287SMartin K. Petersen static const int illegal_condition_result =
660c6a44287SMartin K. Petersen 	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
661c6a44287SMartin K. Petersen 
662cbf67842SDouglas Gilbert static const int device_qfull_result =
663cbf67842SDouglas Gilbert 	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
664cbf67842SDouglas Gilbert 
665cbf67842SDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
666cbf67842SDouglas Gilbert 				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
667cbf67842SDouglas Gilbert 				     0, 0, 0, 0};
668c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
669c65b1445SDouglas Gilbert 				    0, 0, 0x2, 0x4b};
670c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
671c65b1445SDouglas Gilbert 			           0, 0, 0x0, 0x0};
672c65b1445SDouglas Gilbert 
67314faa944SAkinobu Mita static void *fake_store(unsigned long long lba)
67414faa944SAkinobu Mita {
67514faa944SAkinobu Mita 	lba = do_div(lba, sdebug_store_sectors);
67614faa944SAkinobu Mita 
677773642d9SDouglas Gilbert 	return fake_storep + lba * sdebug_sector_size;
67814faa944SAkinobu Mita }
67914faa944SAkinobu Mita 
68014faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector)
68114faa944SAkinobu Mita {
68249413112SArnd Bergmann 	sector = sector_div(sector, sdebug_store_sectors);
68314faa944SAkinobu Mita 
68414faa944SAkinobu Mita 	return dif_storep + sector;
68514faa944SAkinobu Mita }
68614faa944SAkinobu Mita 
6871da177e4SLinus Torvalds static int sdebug_add_adapter(void);
6881da177e4SLinus Torvalds static void sdebug_remove_adapter(void);
6891da177e4SLinus Torvalds 
6908dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void)
6918dea0d02SFUJITA Tomonori {
6928dea0d02SFUJITA Tomonori 	struct sdebug_host_info *sdbg_host;
6938dea0d02SFUJITA Tomonori 	struct Scsi_Host *hpnt;
6948dea0d02SFUJITA Tomonori 
6958dea0d02SFUJITA Tomonori 	spin_lock(&sdebug_host_list_lock);
6968dea0d02SFUJITA Tomonori 	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
6978dea0d02SFUJITA Tomonori 		hpnt = sdbg_host->shost;
6988dea0d02SFUJITA Tomonori 		if ((hpnt->this_id >= 0) &&
699773642d9SDouglas Gilbert 		    (sdebug_num_tgts > hpnt->this_id))
700773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts + 1;
7018dea0d02SFUJITA Tomonori 		else
702773642d9SDouglas Gilbert 			hpnt->max_id = sdebug_num_tgts;
703773642d9SDouglas Gilbert 		/* sdebug_max_luns; */
704f2d3fd29STomas Winkler 		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
7058dea0d02SFUJITA Tomonori 	}
7068dea0d02SFUJITA Tomonori 	spin_unlock(&sdebug_host_list_lock);
7078dea0d02SFUJITA Tomonori }
7088dea0d02SFUJITA Tomonori 
70922017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
71022017ed2SDouglas Gilbert 
71122017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */
71222017ed2SDouglas Gilbert static void
71322017ed2SDouglas Gilbert mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d,
71422017ed2SDouglas Gilbert 		     int in_byte, int in_bit)
71522017ed2SDouglas Gilbert {
71622017ed2SDouglas Gilbert 	unsigned char *sbuff;
71722017ed2SDouglas Gilbert 	u8 sks[4];
71822017ed2SDouglas Gilbert 	int sl, asc;
71922017ed2SDouglas Gilbert 
72022017ed2SDouglas Gilbert 	sbuff = scp->sense_buffer;
72122017ed2SDouglas Gilbert 	if (!sbuff) {
72222017ed2SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
72322017ed2SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
72422017ed2SDouglas Gilbert 		return;
72522017ed2SDouglas Gilbert 	}
72622017ed2SDouglas Gilbert 	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
72722017ed2SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
728773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
72922017ed2SDouglas Gilbert 	memset(sks, 0, sizeof(sks));
73022017ed2SDouglas Gilbert 	sks[0] = 0x80;
73122017ed2SDouglas Gilbert 	if (c_d)
73222017ed2SDouglas Gilbert 		sks[0] |= 0x40;
73322017ed2SDouglas Gilbert 	if (in_bit >= 0) {
73422017ed2SDouglas Gilbert 		sks[0] |= 0x8;
73522017ed2SDouglas Gilbert 		sks[0] |= 0x7 & in_bit;
73622017ed2SDouglas Gilbert 	}
73722017ed2SDouglas Gilbert 	put_unaligned_be16(in_byte, sks + 1);
738773642d9SDouglas Gilbert 	if (sdebug_dsense) {
73922017ed2SDouglas Gilbert 		sl = sbuff[7] + 8;
74022017ed2SDouglas Gilbert 		sbuff[7] = sl;
74122017ed2SDouglas Gilbert 		sbuff[sl] = 0x2;
74222017ed2SDouglas Gilbert 		sbuff[sl + 1] = 0x6;
74322017ed2SDouglas Gilbert 		memcpy(sbuff + sl + 4, sks, 3);
74422017ed2SDouglas Gilbert 	} else
74522017ed2SDouglas Gilbert 		memcpy(sbuff + 15, sks, 3);
746773642d9SDouglas Gilbert 	if (sdebug_verbose)
74722017ed2SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
74822017ed2SDouglas Gilbert 			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
74922017ed2SDouglas Gilbert 			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
75022017ed2SDouglas Gilbert }
75122017ed2SDouglas Gilbert 
752cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
7538dea0d02SFUJITA Tomonori {
7548dea0d02SFUJITA Tomonori 	unsigned char *sbuff;
7558dea0d02SFUJITA Tomonori 
756cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
757cbf67842SDouglas Gilbert 	if (!sbuff) {
758cbf67842SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device,
759cbf67842SDouglas Gilbert 			    "%s: sense_buffer is NULL\n", __func__);
760cbf67842SDouglas Gilbert 		return;
761cbf67842SDouglas Gilbert 	}
762cbf67842SDouglas Gilbert 	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
7638dea0d02SFUJITA Tomonori 
764773642d9SDouglas Gilbert 	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
7658dea0d02SFUJITA Tomonori 
766773642d9SDouglas Gilbert 	if (sdebug_verbose)
767cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
768cbf67842SDouglas Gilbert 			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
769cbf67842SDouglas Gilbert 			    my_name, key, asc, asq);
7708dea0d02SFUJITA Tomonori }
7711da177e4SLinus Torvalds 
77222017ed2SDouglas Gilbert static void
77322017ed2SDouglas Gilbert mk_sense_invalid_opcode(struct scsi_cmnd *scp)
77422017ed2SDouglas Gilbert {
77522017ed2SDouglas Gilbert 	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
77622017ed2SDouglas Gilbert }
77722017ed2SDouglas Gilbert 
7781da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
7791da177e4SLinus Torvalds {
780773642d9SDouglas Gilbert 	if (sdebug_verbose) {
781cbf67842SDouglas Gilbert 		if (0x1261 == cmd)
782cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
783cbf67842SDouglas Gilbert 				    "%s: BLKFLSBUF [0x1261]\n", __func__);
784cbf67842SDouglas Gilbert 		else if (0x5331 == cmd)
785cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev,
786cbf67842SDouglas Gilbert 				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
787cbf67842SDouglas Gilbert 				    __func__);
788cbf67842SDouglas Gilbert 		else
789cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
790cbf67842SDouglas Gilbert 				    __func__, cmd);
7911da177e4SLinus Torvalds 	}
7921da177e4SLinus Torvalds 	return -EINVAL;
7931da177e4SLinus Torvalds 	/* return -ENOTTY; // correct return but upsets fdisk */
7941da177e4SLinus Torvalds }
7951da177e4SLinus Torvalds 
79619c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
79719c8ead7SEwan D. Milne {
79819c8ead7SEwan D. Milne 	struct sdebug_host_info *sdhp;
79919c8ead7SEwan D. Milne 	struct sdebug_dev_info *dp;
80019c8ead7SEwan D. Milne 
80119c8ead7SEwan D. Milne 	spin_lock(&sdebug_host_list_lock);
80219c8ead7SEwan D. Milne 	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
80319c8ead7SEwan D. Milne 		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
80419c8ead7SEwan D. Milne 			if ((devip->sdbg_host == dp->sdbg_host) &&
80519c8ead7SEwan D. Milne 			    (devip->target == dp->target))
80619c8ead7SEwan D. Milne 				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
80719c8ead7SEwan D. Milne 		}
80819c8ead7SEwan D. Milne 	}
80919c8ead7SEwan D. Milne 	spin_unlock(&sdebug_host_list_lock);
81019c8ead7SEwan D. Milne }
81119c8ead7SEwan D. Milne 
812cbf67842SDouglas Gilbert static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
813c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
8141da177e4SLinus Torvalds {
815cbf67842SDouglas Gilbert 	int k;
816cbf67842SDouglas Gilbert 
817cbf67842SDouglas Gilbert 	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
818cbf67842SDouglas Gilbert 	if (k != SDEBUG_NUM_UAS) {
819cbf67842SDouglas Gilbert 		const char *cp = NULL;
820cbf67842SDouglas Gilbert 
821cbf67842SDouglas Gilbert 		switch (k) {
822cbf67842SDouglas Gilbert 		case SDEBUG_UA_POR:
823cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
824cbf67842SDouglas Gilbert 					UA_RESET_ASC, POWER_ON_RESET_ASCQ);
825773642d9SDouglas Gilbert 			if (sdebug_verbose)
826cbf67842SDouglas Gilbert 				cp = "power on reset";
827cbf67842SDouglas Gilbert 			break;
828cbf67842SDouglas Gilbert 		case SDEBUG_UA_BUS_RESET:
829cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
830cbf67842SDouglas Gilbert 					UA_RESET_ASC, BUS_RESET_ASCQ);
831773642d9SDouglas Gilbert 			if (sdebug_verbose)
832cbf67842SDouglas Gilbert 				cp = "bus reset";
833cbf67842SDouglas Gilbert 			break;
834cbf67842SDouglas Gilbert 		case SDEBUG_UA_MODE_CHANGED:
835cbf67842SDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
836cbf67842SDouglas Gilbert 					UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
837773642d9SDouglas Gilbert 			if (sdebug_verbose)
838cbf67842SDouglas Gilbert 				cp = "mode parameters changed";
839cbf67842SDouglas Gilbert 			break;
8400d01c5dfSDouglas Gilbert 		case SDEBUG_UA_CAPACITY_CHANGED:
8410d01c5dfSDouglas Gilbert 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
8420d01c5dfSDouglas Gilbert 					UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ);
843773642d9SDouglas Gilbert 			if (sdebug_verbose)
8440d01c5dfSDouglas Gilbert 				cp = "capacity data changed";
845f49accf1SEwan D. Milne 			break;
846acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED:
847acafd0b9SEwan D. Milne 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
848acafd0b9SEwan D. Milne 				 TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
849773642d9SDouglas Gilbert 			if (sdebug_verbose)
850acafd0b9SEwan D. Milne 				cp = "microcode has been changed";
851acafd0b9SEwan D. Milne 			break;
852acafd0b9SEwan D. Milne 		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
853acafd0b9SEwan D. Milne 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
854acafd0b9SEwan D. Milne 					TARGET_CHANGED_ASC,
855acafd0b9SEwan D. Milne 					MICROCODE_CHANGED_WO_RESET_ASCQ);
856773642d9SDouglas Gilbert 			if (sdebug_verbose)
857acafd0b9SEwan D. Milne 				cp = "microcode has been changed without reset";
858acafd0b9SEwan D. Milne 			break;
85919c8ead7SEwan D. Milne 		case SDEBUG_UA_LUNS_CHANGED:
86019c8ead7SEwan D. Milne 			/*
86119c8ead7SEwan D. Milne 			 * SPC-3 behavior is to report a UNIT ATTENTION with
86219c8ead7SEwan D. Milne 			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
86319c8ead7SEwan D. Milne 			 * on the target, until a REPORT LUNS command is
86419c8ead7SEwan D. Milne 			 * received.  SPC-4 behavior is to report it only once.
865773642d9SDouglas Gilbert 			 * NOTE:  sdebug_scsi_level does not use the same
86619c8ead7SEwan D. Milne 			 * values as struct scsi_device->scsi_level.
86719c8ead7SEwan D. Milne 			 */
868773642d9SDouglas Gilbert 			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
86919c8ead7SEwan D. Milne 				clear_luns_changed_on_target(devip);
87019c8ead7SEwan D. Milne 			mk_sense_buffer(SCpnt, UNIT_ATTENTION,
87119c8ead7SEwan D. Milne 					TARGET_CHANGED_ASC,
87219c8ead7SEwan D. Milne 					LUNS_CHANGED_ASCQ);
873773642d9SDouglas Gilbert 			if (sdebug_verbose)
87419c8ead7SEwan D. Milne 				cp = "reported luns data has changed";
87519c8ead7SEwan D. Milne 			break;
876cbf67842SDouglas Gilbert 		default:
877773642d9SDouglas Gilbert 			pr_warn("unexpected unit attention code=%d\n", k);
878773642d9SDouglas Gilbert 			if (sdebug_verbose)
879cbf67842SDouglas Gilbert 				cp = "unknown";
880cbf67842SDouglas Gilbert 			break;
881cbf67842SDouglas Gilbert 		}
882cbf67842SDouglas Gilbert 		clear_bit(k, devip->uas_bm);
883773642d9SDouglas Gilbert 		if (sdebug_verbose)
884cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
885cbf67842SDouglas Gilbert 				   "%s reports: Unit attention: %s\n",
886cbf67842SDouglas Gilbert 				   my_name, cp);
8871da177e4SLinus Torvalds 		return check_condition_result;
8881da177e4SLinus Torvalds 	}
889cbf67842SDouglas Gilbert 	if ((UAS_TUR == uas_only) && devip->stopped) {
890cbf67842SDouglas Gilbert 		mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
891c65b1445SDouglas Gilbert 				0x2);
892773642d9SDouglas Gilbert 		if (sdebug_verbose)
893cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device,
894cbf67842SDouglas Gilbert 				    "%s reports: Not ready: %s\n", my_name,
895cbf67842SDouglas Gilbert 				    "initializing command required");
896c65b1445SDouglas Gilbert 		return check_condition_result;
897c65b1445SDouglas Gilbert 	}
8981da177e4SLinus Torvalds 	return 0;
8991da177e4SLinus Torvalds }
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
9021da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
9031da177e4SLinus Torvalds 				int arr_len)
9041da177e4SLinus Torvalds {
90521a61829SFUJITA Tomonori 	int act_len;
906072d0bb3SFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
9071da177e4SLinus Torvalds 
908072d0bb3SFUJITA Tomonori 	if (!sdb->length)
9091da177e4SLinus Torvalds 		return 0;
910072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
911773642d9SDouglas Gilbert 		return DID_ERROR << 16;
91221a61829SFUJITA Tomonori 
91321a61829SFUJITA Tomonori 	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
91421a61829SFUJITA Tomonori 				      arr, arr_len);
91521a61829SFUJITA Tomonori 	sdb->resid = scsi_bufflen(scp) - act_len;
91621a61829SFUJITA Tomonori 
9171da177e4SLinus Torvalds 	return 0;
9181da177e4SLinus Torvalds }
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */
9211da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
92221a61829SFUJITA Tomonori 			       int arr_len)
9231da177e4SLinus Torvalds {
92421a61829SFUJITA Tomonori 	if (!scsi_bufflen(scp))
9251da177e4SLinus Torvalds 		return 0;
926072d0bb3SFUJITA Tomonori 	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
9271da177e4SLinus Torvalds 		return -1;
92821a61829SFUJITA Tomonori 
92921a61829SFUJITA Tomonori 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
9301da177e4SLinus Torvalds }
9311da177e4SLinus Torvalds 
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux   ";
9341da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug      ";
935773642d9SDouglas Gilbert static const char *inq_product_rev = "0186";	/* version less '.' */
936773642d9SDouglas Gilbert static const u64 naa5_comp_a = 0x5222222000000000ULL;
937773642d9SDouglas Gilbert static const u64 naa5_comp_b = 0x5333333000000000ULL;
938773642d9SDouglas Gilbert static const u64 naa5_comp_c = 0x5111111000000000ULL;
9391da177e4SLinus Torvalds 
940cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */
9415a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
9425a09e398SHannes Reinecke 			   int target_dev_id, int dev_id_num,
9435a09e398SHannes Reinecke 			   const char * dev_id_str,
944c65b1445SDouglas Gilbert 			   int dev_id_str_len)
9451da177e4SLinus Torvalds {
946c65b1445SDouglas Gilbert 	int num, port_a;
947c65b1445SDouglas Gilbert 	char b[32];
9481da177e4SLinus Torvalds 
949c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
9501da177e4SLinus Torvalds 	/* T10 vendor identifier field format (faked) */
9511da177e4SLinus Torvalds 	arr[0] = 0x2;	/* ASCII */
9521da177e4SLinus Torvalds 	arr[1] = 0x1;
9531da177e4SLinus Torvalds 	arr[2] = 0x0;
9541da177e4SLinus Torvalds 	memcpy(&arr[4], inq_vendor_id, 8);
9551da177e4SLinus Torvalds 	memcpy(&arr[12], inq_product_id, 16);
9561da177e4SLinus Torvalds 	memcpy(&arr[28], dev_id_str, dev_id_str_len);
9571da177e4SLinus Torvalds 	num = 8 + 16 + dev_id_str_len;
9581da177e4SLinus Torvalds 	arr[3] = num;
9591da177e4SLinus Torvalds 	num += 4;
960c65b1445SDouglas Gilbert 	if (dev_id_num >= 0) {
961c65b1445SDouglas Gilbert 		/* NAA-5, Logical unit identifier (binary) */
962c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* binary (not necessarily sas) */
963c65b1445SDouglas Gilbert 		arr[num++] = 0x3;	/* PIV=0, lu, naa */
964c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
965c65b1445SDouglas Gilbert 		arr[num++] = 0x8;
966773642d9SDouglas Gilbert 		put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
967773642d9SDouglas Gilbert 		num += 8;
968c65b1445SDouglas Gilbert 		/* Target relative port number */
969c65b1445SDouglas Gilbert 		arr[num++] = 0x61;	/* proto=sas, binary */
970c65b1445SDouglas Gilbert 		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
971c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
972c65b1445SDouglas Gilbert 		arr[num++] = 0x4;	/* length */
973c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
974c65b1445SDouglas Gilbert 		arr[num++] = 0x0;	/* reserved */
975c65b1445SDouglas Gilbert 		arr[num++] = 0x0;
976c65b1445SDouglas Gilbert 		arr[num++] = 0x1;	/* relative port A */
977c65b1445SDouglas Gilbert 	}
978c65b1445SDouglas Gilbert 	/* NAA-5, Target port identifier */
979c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
980c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* piv=1, target port, naa */
981c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
982c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
983773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + port_a, arr + num);
984773642d9SDouglas Gilbert 	num += 8;
9855a09e398SHannes Reinecke 	/* NAA-5, Target port group identifier */
9865a09e398SHannes Reinecke 	arr[num++] = 0x61;	/* proto=sas, binary */
9875a09e398SHannes Reinecke 	arr[num++] = 0x95;	/* piv=1, target port group id */
9885a09e398SHannes Reinecke 	arr[num++] = 0x0;
9895a09e398SHannes Reinecke 	arr[num++] = 0x4;
9905a09e398SHannes Reinecke 	arr[num++] = 0;
9915a09e398SHannes Reinecke 	arr[num++] = 0;
992773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_id, arr + num);
993773642d9SDouglas Gilbert 	num += 2;
994c65b1445SDouglas Gilbert 	/* NAA-5, Target device identifier */
995c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
996c65b1445SDouglas Gilbert 	arr[num++] = 0xa3;	/* piv=1, target device, naa */
997c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
998c65b1445SDouglas Gilbert 	arr[num++] = 0x8;
999773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
1000773642d9SDouglas Gilbert 	num += 8;
1001c65b1445SDouglas Gilbert 	/* SCSI name string: Target device identifier */
1002c65b1445SDouglas Gilbert 	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
1003c65b1445SDouglas Gilbert 	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
1004c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1005c65b1445SDouglas Gilbert 	arr[num++] = 24;
1006c65b1445SDouglas Gilbert 	memcpy(arr + num, "naa.52222220", 12);
1007c65b1445SDouglas Gilbert 	num += 12;
1008c65b1445SDouglas Gilbert 	snprintf(b, sizeof(b), "%08X", target_dev_id);
1009c65b1445SDouglas Gilbert 	memcpy(arr + num, b, 8);
1010c65b1445SDouglas Gilbert 	num += 8;
1011c65b1445SDouglas Gilbert 	memset(arr + num, 0, 4);
1012c65b1445SDouglas Gilbert 	num += 4;
1013c65b1445SDouglas Gilbert 	return num;
1014c65b1445SDouglas Gilbert }
1015c65b1445SDouglas Gilbert 
1016c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = {
1017c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1018c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x1,
1019c65b1445SDouglas Gilbert     0x22,0x22,0x22,0x0,0xbb,0x2,
1020c65b1445SDouglas Gilbert };
1021c65b1445SDouglas Gilbert 
1022cbf67842SDouglas Gilbert /*  Software interface identification VPD page */
1023c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr)
1024c65b1445SDouglas Gilbert {
1025c65b1445SDouglas Gilbert 	memcpy(arr, vpd84_data, sizeof(vpd84_data));
1026c65b1445SDouglas Gilbert 	return sizeof(vpd84_data);
1027c65b1445SDouglas Gilbert }
1028c65b1445SDouglas Gilbert 
1029cbf67842SDouglas Gilbert /* Management network addresses VPD page */
1030c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr)
1031c65b1445SDouglas Gilbert {
1032c65b1445SDouglas Gilbert 	int num = 0;
1033c65b1445SDouglas Gilbert 	const char * na1 = "https://www.kernel.org/config";
1034c65b1445SDouglas Gilbert 	const char * na2 = "http://www.kernel.org/log";
1035c65b1445SDouglas Gilbert 	int plen, olen;
1036c65b1445SDouglas Gilbert 
1037c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* lu, storage config */
1038c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1039c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1040c65b1445SDouglas Gilbert 	olen = strlen(na1);
1041c65b1445SDouglas Gilbert 	plen = olen + 1;
1042c65b1445SDouglas Gilbert 	if (plen % 4)
1043c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1044c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null termianted, padded */
1045c65b1445SDouglas Gilbert 	memcpy(arr + num, na1, olen);
1046c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1047c65b1445SDouglas Gilbert 	num += plen;
1048c65b1445SDouglas Gilbert 
1049c65b1445SDouglas Gilbert 	arr[num++] = 0x4;	/* lu, logging */
1050c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1051c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1052c65b1445SDouglas Gilbert 	olen = strlen(na2);
1053c65b1445SDouglas Gilbert 	plen = olen + 1;
1054c65b1445SDouglas Gilbert 	if (plen % 4)
1055c65b1445SDouglas Gilbert 		plen = ((plen / 4) + 1) * 4;
1056c65b1445SDouglas Gilbert 	arr[num++] = plen;	/* length, null terminated, padded */
1057c65b1445SDouglas Gilbert 	memcpy(arr + num, na2, olen);
1058c65b1445SDouglas Gilbert 	memset(arr + num + olen, 0, plen - olen);
1059c65b1445SDouglas Gilbert 	num += plen;
1060c65b1445SDouglas Gilbert 
1061c65b1445SDouglas Gilbert 	return num;
1062c65b1445SDouglas Gilbert }
1063c65b1445SDouglas Gilbert 
1064c65b1445SDouglas Gilbert /* SCSI ports VPD page */
1065c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1066c65b1445SDouglas Gilbert {
1067c65b1445SDouglas Gilbert 	int num = 0;
1068c65b1445SDouglas Gilbert 	int port_a, port_b;
1069c65b1445SDouglas Gilbert 
1070c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1071c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1072c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1073c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1074c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1075c65b1445SDouglas Gilbert 	arr[num++] = 0x1;	/* relative port 1 (primary) */
1076c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1077c65b1445SDouglas Gilbert 	num += 6;
1078c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1079c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1080c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (A) */
1081c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1082c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1083c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1084c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1085773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1086773642d9SDouglas Gilbert 	num += 8;
1087c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1088c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1089c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1090c65b1445SDouglas Gilbert 	arr[num++] = 0x2;	/* relative port 2 (secondary) */
1091c65b1445SDouglas Gilbert 	memset(arr + num, 0, 6);
1092c65b1445SDouglas Gilbert 	num += 6;
1093c65b1445SDouglas Gilbert 	arr[num++] = 0x0;
1094c65b1445SDouglas Gilbert 	arr[num++] = 12;	/* length tp descriptor */
1095c65b1445SDouglas Gilbert 	/* naa-5 target port identifier (B) */
1096c65b1445SDouglas Gilbert 	arr[num++] = 0x61;	/* proto=sas, binary */
1097c65b1445SDouglas Gilbert 	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
1098c65b1445SDouglas Gilbert 	arr[num++] = 0x0;	/* reserved */
1099c65b1445SDouglas Gilbert 	arr[num++] = 0x8;	/* length */
1100773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1101773642d9SDouglas Gilbert 	num += 8;
1102c65b1445SDouglas Gilbert 
1103c65b1445SDouglas Gilbert 	return num;
1104c65b1445SDouglas Gilbert }
1105c65b1445SDouglas Gilbert 
1106c65b1445SDouglas Gilbert 
1107c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = {
1108c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0,
1109c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ',
1110c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1111c65b1445SDouglas Gilbert '1','2','3','4',
1112c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
1113c65b1445SDouglas Gilbert 0xec,0,0,0,
1114c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
1115c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
1116c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
1117c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
1118c65b1445SDouglas Gilbert 0x53,0x41,
1119c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1120c65b1445SDouglas Gilbert 0x20,0x20,
1121c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
1122c65b1445SDouglas Gilbert 0x10,0x80,
1123c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
1124c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
1125c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
1126c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
1127c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
1128c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
1129c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
1130c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1131c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1132c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1133c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
1134c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
1135c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
1136c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
1137c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1138c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1139c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1140c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1141c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1142c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1143c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1144c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1145c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1146c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1147c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1148c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1149c65b1445SDouglas Gilbert };
1150c65b1445SDouglas Gilbert 
1151cbf67842SDouglas Gilbert /* ATA Information VPD page */
1152c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr)
1153c65b1445SDouglas Gilbert {
1154c65b1445SDouglas Gilbert 	memcpy(arr, vpd89_data, sizeof(vpd89_data));
1155c65b1445SDouglas Gilbert 	return sizeof(vpd89_data);
1156c65b1445SDouglas Gilbert }
1157c65b1445SDouglas Gilbert 
1158c65b1445SDouglas Gilbert 
1159c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = {
11601e49f785SDouglas Gilbert 	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
11611e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11621e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11631e49f785SDouglas Gilbert 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1164c65b1445SDouglas Gilbert };
1165c65b1445SDouglas Gilbert 
1166cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */
1167c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr)
1168c65b1445SDouglas Gilbert {
1169ea61fca5SMartin K. Petersen 	unsigned int gran;
1170ea61fca5SMartin K. Petersen 
1171c65b1445SDouglas Gilbert 	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
1172e308b3d1SMartin K. Petersen 
1173e308b3d1SMartin K. Petersen 	/* Optimal transfer length granularity */
1174773642d9SDouglas Gilbert 	gran = 1 << sdebug_physblk_exp;
1175773642d9SDouglas Gilbert 	put_unaligned_be16(gran, arr + 2);
1176e308b3d1SMartin K. Petersen 
1177e308b3d1SMartin K. Petersen 	/* Maximum Transfer Length */
1178773642d9SDouglas Gilbert 	if (sdebug_store_sectors > 0x400)
1179773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_store_sectors, arr + 4);
118044d92694SMartin K. Petersen 
1181e308b3d1SMartin K. Petersen 	/* Optimal Transfer Length */
1182773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
1183e308b3d1SMartin K. Petersen 
1184773642d9SDouglas Gilbert 	if (sdebug_lbpu) {
1185e308b3d1SMartin K. Petersen 		/* Maximum Unmap LBA Count */
1186773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
1187e308b3d1SMartin K. Petersen 
1188e308b3d1SMartin K. Petersen 		/* Maximum Unmap Block Descriptor Count */
1189773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
119044d92694SMartin K. Petersen 	}
119144d92694SMartin K. Petersen 
1192e308b3d1SMartin K. Petersen 	/* Unmap Granularity Alignment */
1193773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment) {
1194773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
119544d92694SMartin K. Petersen 		arr[28] |= 0x80; /* UGAVALID */
119644d92694SMartin K. Petersen 	}
119744d92694SMartin K. Petersen 
1198e308b3d1SMartin K. Petersen 	/* Optimal Unmap Granularity */
1199773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
12006014759cSMartin K. Petersen 
12015b94e232SMartin K. Petersen 	/* Maximum WRITE SAME Length */
1202773642d9SDouglas Gilbert 	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
12035b94e232SMartin K. Petersen 
12045b94e232SMartin K. Petersen 	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
120544d92694SMartin K. Petersen 
1206c65b1445SDouglas Gilbert 	return sizeof(vpdb0_data);
12071da177e4SLinus Torvalds }
12081da177e4SLinus Torvalds 
12091e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */
1210eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr)
1211eac6e8e4SMatthew Wilcox {
1212eac6e8e4SMatthew Wilcox 	memset(arr, 0, 0x3c);
1213eac6e8e4SMatthew Wilcox 	arr[0] = 0;
12141e49f785SDouglas Gilbert 	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
12151e49f785SDouglas Gilbert 	arr[2] = 0;
12161e49f785SDouglas Gilbert 	arr[3] = 5;	/* less than 1.8" */
1217eac6e8e4SMatthew Wilcox 
1218eac6e8e4SMatthew Wilcox 	return 0x3c;
1219eac6e8e4SMatthew Wilcox }
12201da177e4SLinus Torvalds 
1221be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */
12226014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr)
12236014759cSMartin K. Petersen {
12243f0bc3b3SMartin K. Petersen 	memset(arr, 0, 0x4);
12256014759cSMartin K. Petersen 	arr[0] = 0;			/* threshold exponent */
12266014759cSMartin K. Petersen 
1227773642d9SDouglas Gilbert 	if (sdebug_lbpu)
12286014759cSMartin K. Petersen 		arr[1] = 1 << 7;
12296014759cSMartin K. Petersen 
1230773642d9SDouglas Gilbert 	if (sdebug_lbpws)
12316014759cSMartin K. Petersen 		arr[1] |= 1 << 6;
12326014759cSMartin K. Petersen 
1233773642d9SDouglas Gilbert 	if (sdebug_lbpws10)
12345b94e232SMartin K. Petersen 		arr[1] |= 1 << 5;
12355b94e232SMartin K. Petersen 
1236773642d9SDouglas Gilbert 	if (sdebug_lbprz)
1237be1dd78dSEric Sandeen 		arr[1] |= 1 << 2;
1238be1dd78dSEric Sandeen 
12393f0bc3b3SMartin K. Petersen 	return 0x4;
12406014759cSMartin K. Petersen }
12416014759cSMartin K. Petersen 
12421da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96
1243c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584
12441da177e4SLinus Torvalds 
1245c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
12461da177e4SLinus Torvalds {
12471da177e4SLinus Torvalds 	unsigned char pq_pdt;
12485a09e398SHannes Reinecke 	unsigned char * arr;
124901123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
12505a09e398SHannes Reinecke 	int alloc_len, n, ret;
1251c2248fc9SDouglas Gilbert 	bool have_wlun;
12521da177e4SLinus Torvalds 
1253773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 3);
12546f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
12556f3cbf55SDouglas Gilbert 	if (! arr)
12566f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
125734d55434STomas Winkler 	have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
1258c2248fc9SDouglas Gilbert 	if (have_wlun)
1259c65b1445SDouglas Gilbert 		pq_pdt = 0x1e;	/* present, wlun */
1260773642d9SDouglas Gilbert 	else if (sdebug_no_lun_0 && (0 == devip->lun))
1261c65b1445SDouglas Gilbert 		pq_pdt = 0x7f;	/* not present, no device type */
1262c65b1445SDouglas Gilbert 	else
1263773642d9SDouglas Gilbert 		pq_pdt = (sdebug_ptype & 0x1f);
12641da177e4SLinus Torvalds 	arr[0] = pq_pdt;
12651da177e4SLinus Torvalds 	if (0x2 & cmd[1]) {  /* CMDDT bit set */
126622017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
12675a09e398SHannes Reinecke 		kfree(arr);
12681da177e4SLinus Torvalds 		return check_condition_result;
12691da177e4SLinus Torvalds 	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
12705a09e398SHannes Reinecke 		int lu_id_num, port_group_id, target_dev_id, len;
1271c65b1445SDouglas Gilbert 		char lu_id_str[6];
1272c65b1445SDouglas Gilbert 		int host_no = devip->sdbg_host->shost->host_no;
12731da177e4SLinus Torvalds 
12745a09e398SHannes Reinecke 		port_group_id = (((host_no + 1) & 0x7f) << 8) +
12755a09e398SHannes Reinecke 		    (devip->channel & 0x7f);
1276773642d9SDouglas Gilbert 		if (0 == sdebug_vpd_use_hostno)
127723183910SDouglas Gilbert 			host_no = 0;
1278c2248fc9SDouglas Gilbert 		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
1279c65b1445SDouglas Gilbert 			    (devip->target * 1000) + devip->lun);
1280c65b1445SDouglas Gilbert 		target_dev_id = ((host_no + 1) * 2000) +
1281c65b1445SDouglas Gilbert 				 (devip->target * 1000) - 3;
1282c65b1445SDouglas Gilbert 		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
12831da177e4SLinus Torvalds 		if (0 == cmd[2]) { /* supported vital product data pages */
1284c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1285c65b1445SDouglas Gilbert 			n = 4;
1286c65b1445SDouglas Gilbert 			arr[n++] = 0x0;   /* this page */
1287c65b1445SDouglas Gilbert 			arr[n++] = 0x80;  /* unit serial number */
1288c65b1445SDouglas Gilbert 			arr[n++] = 0x83;  /* device identification */
1289c65b1445SDouglas Gilbert 			arr[n++] = 0x84;  /* software interface ident. */
1290c65b1445SDouglas Gilbert 			arr[n++] = 0x85;  /* management network addresses */
1291c65b1445SDouglas Gilbert 			arr[n++] = 0x86;  /* extended inquiry */
1292c65b1445SDouglas Gilbert 			arr[n++] = 0x87;  /* mode page policy */
1293c65b1445SDouglas Gilbert 			arr[n++] = 0x88;  /* SCSI ports */
1294c65b1445SDouglas Gilbert 			arr[n++] = 0x89;  /* ATA information */
1295c65b1445SDouglas Gilbert 			arr[n++] = 0xb0;  /* Block limits (SBC) */
1296eac6e8e4SMatthew Wilcox 			arr[n++] = 0xb1;  /* Block characteristics (SBC) */
12975b94e232SMartin K. Petersen 			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
12985b94e232SMartin K. Petersen 				arr[n++] = 0xb2;
1299c65b1445SDouglas Gilbert 			arr[3] = n - 4;	  /* number of supported VPD pages */
13001da177e4SLinus Torvalds 		} else if (0x80 == cmd[2]) { /* unit serial number */
1301c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
13021da177e4SLinus Torvalds 			arr[3] = len;
1303c65b1445SDouglas Gilbert 			memcpy(&arr[4], lu_id_str, len);
13041da177e4SLinus Torvalds 		} else if (0x83 == cmd[2]) { /* device identification */
1305c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
13065a09e398SHannes Reinecke 			arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
13075a09e398SHannes Reinecke 						 target_dev_id, lu_id_num,
13085a09e398SHannes Reinecke 						 lu_id_str, len);
1309c65b1445SDouglas Gilbert 		} else if (0x84 == cmd[2]) { /* Software interface ident. */
1310c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1311c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_84(&arr[4]);
1312c65b1445SDouglas Gilbert 		} else if (0x85 == cmd[2]) { /* Management network addresses */
1313c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1314c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_85(&arr[4]);
1315c65b1445SDouglas Gilbert 		} else if (0x86 == cmd[2]) { /* extended inquiry */
1316c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1317c65b1445SDouglas Gilbert 			arr[3] = 0x3c;	/* number of following entries */
1318773642d9SDouglas Gilbert 			if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
1319c6a44287SMartin K. Petersen 				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
1320773642d9SDouglas Gilbert 			else if (sdebug_dif)
1321c6a44287SMartin K. Petersen 				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
1322c6a44287SMartin K. Petersen 			else
1323c65b1445SDouglas Gilbert 				arr[4] = 0x0;   /* no protection stuff */
1324c65b1445SDouglas Gilbert 			arr[5] = 0x7;   /* head of q, ordered + simple q's */
1325c65b1445SDouglas Gilbert 		} else if (0x87 == cmd[2]) { /* mode page policy */
1326c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1327c65b1445SDouglas Gilbert 			arr[3] = 0x8;	/* number of following entries */
1328c65b1445SDouglas Gilbert 			arr[4] = 0x2;	/* disconnect-reconnect mp */
1329c65b1445SDouglas Gilbert 			arr[6] = 0x80;	/* mlus, shared */
1330c65b1445SDouglas Gilbert 			arr[8] = 0x18;	 /* protocol specific lu */
1331c65b1445SDouglas Gilbert 			arr[10] = 0x82;	 /* mlus, per initiator port */
1332c65b1445SDouglas Gilbert 		} else if (0x88 == cmd[2]) { /* SCSI Ports */
1333c65b1445SDouglas Gilbert 			arr[1] = cmd[2];	/*sanity */
1334c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1335c65b1445SDouglas Gilbert 		} else if (0x89 == cmd[2]) { /* ATA information */
1336c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1337c65b1445SDouglas Gilbert 			n = inquiry_evpd_89(&arr[4]);
1338773642d9SDouglas Gilbert 			put_unaligned_be16(n, arr + 2);
1339c65b1445SDouglas Gilbert 		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1340c65b1445SDouglas Gilbert 			arr[1] = cmd[2];        /*sanity */
1341c65b1445SDouglas Gilbert 			arr[3] = inquiry_evpd_b0(&arr[4]);
1342eac6e8e4SMatthew Wilcox 		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1343eac6e8e4SMatthew Wilcox 			arr[1] = cmd[2];        /*sanity */
1344eac6e8e4SMatthew Wilcox 			arr[3] = inquiry_evpd_b1(&arr[4]);
13455b94e232SMartin K. Petersen 		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
13466014759cSMartin K. Petersen 			arr[1] = cmd[2];        /*sanity */
13476014759cSMartin K. Petersen 			arr[3] = inquiry_evpd_b2(&arr[4]);
13481da177e4SLinus Torvalds 		} else {
134922017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
13505a09e398SHannes Reinecke 			kfree(arr);
13511da177e4SLinus Torvalds 			return check_condition_result;
13521da177e4SLinus Torvalds 		}
1353773642d9SDouglas Gilbert 		len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
13545a09e398SHannes Reinecke 		ret = fill_from_dev_buffer(scp, arr,
1355c65b1445SDouglas Gilbert 			    min(len, SDEBUG_MAX_INQ_ARR_SZ));
13565a09e398SHannes Reinecke 		kfree(arr);
13575a09e398SHannes Reinecke 		return ret;
13581da177e4SLinus Torvalds 	}
13591da177e4SLinus Torvalds 	/* drops through here for a standard inquiry */
1360773642d9SDouglas Gilbert 	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
1361773642d9SDouglas Gilbert 	arr[2] = sdebug_scsi_level;
13621da177e4SLinus Torvalds 	arr[3] = 2;    /* response_data_format==2 */
13631da177e4SLinus Torvalds 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
1364773642d9SDouglas Gilbert 	arr[5] = sdebug_dif ? 1 : 0; /* PROTECT bit */
1365773642d9SDouglas Gilbert 	if (0 == sdebug_vpd_use_hostno)
13665a09e398SHannes Reinecke 		arr[5] = 0x10; /* claim: implicit TGPS */
1367c65b1445SDouglas Gilbert 	arr[6] = 0x10; /* claim: MultiP */
13681da177e4SLinus Torvalds 	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
1369c65b1445SDouglas Gilbert 	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
13701da177e4SLinus Torvalds 	memcpy(&arr[8], inq_vendor_id, 8);
13711da177e4SLinus Torvalds 	memcpy(&arr[16], inq_product_id, 16);
13721da177e4SLinus Torvalds 	memcpy(&arr[32], inq_product_rev, 4);
13731da177e4SLinus Torvalds 	/* version descriptors (2 bytes each) follow */
1374e46b0344SDouglas Gilbert 	arr[58] = 0x0; arr[59] = 0xa2;  /* SAM-5 rev 4 */
1375e46b0344SDouglas Gilbert 	arr[60] = 0x4; arr[61] = 0x68;  /* SPC-4 rev 37 */
1376c65b1445SDouglas Gilbert 	n = 62;
1377773642d9SDouglas Gilbert 	if (sdebug_ptype == 0) {
1378e46b0344SDouglas Gilbert 		arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
1379773642d9SDouglas Gilbert 	} else if (sdebug_ptype == 1) {
1380e46b0344SDouglas Gilbert 		arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
13811da177e4SLinus Torvalds 	}
1382e46b0344SDouglas Gilbert 	arr[n++] = 0x20; arr[n++] = 0xe6;  /* SPL-3 rev 7 */
13835a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
13841da177e4SLinus Torvalds 			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
13855a09e398SHannes Reinecke 	kfree(arr);
13865a09e398SHannes Reinecke 	return ret;
13871da177e4SLinus Torvalds }
13881da177e4SLinus Torvalds 
13891da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp,
13901da177e4SLinus Torvalds 			 struct sdebug_dev_info * devip)
13911da177e4SLinus Torvalds {
13921da177e4SLinus Torvalds 	unsigned char * sbuff;
139301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1394cbf67842SDouglas Gilbert 	unsigned char arr[SCSI_SENSE_BUFFERSIZE];
13952492fc09STomas Winkler 	bool dsense;
13961da177e4SLinus Torvalds 	int len = 18;
13971da177e4SLinus Torvalds 
1398c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
1399c2248fc9SDouglas Gilbert 	dsense = !!(cmd[1] & 1);
1400cbf67842SDouglas Gilbert 	sbuff = scp->sense_buffer;
1401c65b1445SDouglas Gilbert 	if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1402c2248fc9SDouglas Gilbert 		if (dsense) {
1403c65b1445SDouglas Gilbert 			arr[0] = 0x72;
1404c65b1445SDouglas Gilbert 			arr[1] = 0x0;		/* NO_SENSE in sense_key */
1405c65b1445SDouglas Gilbert 			arr[2] = THRESHOLD_EXCEEDED;
1406c65b1445SDouglas Gilbert 			arr[3] = 0xff;		/* TEST set and MRIE==6 */
1407c2248fc9SDouglas Gilbert 			len = 8;
1408c65b1445SDouglas Gilbert 		} else {
1409c65b1445SDouglas Gilbert 			arr[0] = 0x70;
1410c65b1445SDouglas Gilbert 			arr[2] = 0x0;		/* NO_SENSE in sense_key */
1411c65b1445SDouglas Gilbert 			arr[7] = 0xa;   	/* 18 byte sense buffer */
1412c65b1445SDouglas Gilbert 			arr[12] = THRESHOLD_EXCEEDED;
1413c65b1445SDouglas Gilbert 			arr[13] = 0xff;		/* TEST set and MRIE==6 */
1414c65b1445SDouglas Gilbert 		}
1415c65b1445SDouglas Gilbert 	} else {
1416cbf67842SDouglas Gilbert 		memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
1417773642d9SDouglas Gilbert 		if (arr[0] >= 0x70 && dsense == sdebug_dsense)
1418c2248fc9SDouglas Gilbert 			;	/* have sense and formats match */
1419c2248fc9SDouglas Gilbert 		else if (arr[0] <= 0x70) {
1420c2248fc9SDouglas Gilbert 			if (dsense) {
1421c2248fc9SDouglas Gilbert 				memset(arr, 0, 8);
1422c2248fc9SDouglas Gilbert 				arr[0] = 0x72;
1423c2248fc9SDouglas Gilbert 				len = 8;
1424c2248fc9SDouglas Gilbert 			} else {
1425c2248fc9SDouglas Gilbert 				memset(arr, 0, 18);
1426c2248fc9SDouglas Gilbert 				arr[0] = 0x70;
1427c2248fc9SDouglas Gilbert 				arr[7] = 0xa;
1428c2248fc9SDouglas Gilbert 			}
1429c2248fc9SDouglas Gilbert 		} else if (dsense) {
1430c2248fc9SDouglas Gilbert 			memset(arr, 0, 8);
14311da177e4SLinus Torvalds 			arr[0] = 0x72;
14321da177e4SLinus Torvalds 			arr[1] = sbuff[2];     /* sense key */
14331da177e4SLinus Torvalds 			arr[2] = sbuff[12];    /* asc */
14341da177e4SLinus Torvalds 			arr[3] = sbuff[13];    /* ascq */
14351da177e4SLinus Torvalds 			len = 8;
1436c2248fc9SDouglas Gilbert 		} else {
1437c2248fc9SDouglas Gilbert 			memset(arr, 0, 18);
1438c2248fc9SDouglas Gilbert 			arr[0] = 0x70;
1439c2248fc9SDouglas Gilbert 			arr[2] = sbuff[1];
1440c2248fc9SDouglas Gilbert 			arr[7] = 0xa;
1441c2248fc9SDouglas Gilbert 			arr[12] = sbuff[1];
1442c2248fc9SDouglas Gilbert 			arr[13] = sbuff[3];
1443c65b1445SDouglas Gilbert 		}
1444c2248fc9SDouglas Gilbert 
1445c65b1445SDouglas Gilbert 	}
1446cbf67842SDouglas Gilbert 	mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
14471da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, len);
14481da177e4SLinus Torvalds }
14491da177e4SLinus Torvalds 
1450c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp,
1451c65b1445SDouglas Gilbert 			   struct sdebug_dev_info * devip)
1452c65b1445SDouglas Gilbert {
145301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1454c2248fc9SDouglas Gilbert 	int power_cond, start;
1455c65b1445SDouglas Gilbert 
1456c65b1445SDouglas Gilbert 	power_cond = (cmd[4] & 0xf0) >> 4;
1457c65b1445SDouglas Gilbert 	if (power_cond) {
145822017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
1459c65b1445SDouglas Gilbert 		return check_condition_result;
1460c65b1445SDouglas Gilbert 	}
1461c65b1445SDouglas Gilbert 	start = cmd[4] & 1;
1462c65b1445SDouglas Gilbert 	if (start == devip->stopped)
1463c65b1445SDouglas Gilbert 		devip->stopped = !start;
1464c65b1445SDouglas Gilbert 	return 0;
1465c65b1445SDouglas Gilbert }
1466c65b1445SDouglas Gilbert 
146728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void)
146828898873SFUJITA Tomonori {
1469773642d9SDouglas Gilbert 	static const unsigned int gibibyte = 1073741824;
1470773642d9SDouglas Gilbert 
1471773642d9SDouglas Gilbert 	if (sdebug_virtual_gb > 0)
1472773642d9SDouglas Gilbert 		return (sector_t)sdebug_virtual_gb *
1473773642d9SDouglas Gilbert 			(gibibyte / sdebug_sector_size);
147428898873SFUJITA Tomonori 	else
147528898873SFUJITA Tomonori 		return sdebug_store_sectors;
147628898873SFUJITA Tomonori }
147728898873SFUJITA Tomonori 
14781da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8
14791da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp,
14801da177e4SLinus Torvalds 			struct sdebug_dev_info * devip)
14811da177e4SLinus Torvalds {
14821da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
1483c65b1445SDouglas Gilbert 	unsigned int capac;
14841da177e4SLinus Torvalds 
1485c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
148628898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
14871da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
1488c65b1445SDouglas Gilbert 	if (sdebug_capacity < 0xffffffff) {
1489c65b1445SDouglas Gilbert 		capac = (unsigned int)sdebug_capacity - 1;
1490773642d9SDouglas Gilbert 		put_unaligned_be32(capac, arr + 0);
1491773642d9SDouglas Gilbert 	} else
1492773642d9SDouglas Gilbert 		put_unaligned_be32(0xffffffff, arr + 0);
1493773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, arr + 6);
14941da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
14951da177e4SLinus Torvalds }
14961da177e4SLinus Torvalds 
1497c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32
1498c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp,
1499c65b1445SDouglas Gilbert 			  struct sdebug_dev_info * devip)
1500c65b1445SDouglas Gilbert {
150101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
1502c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1503773642d9SDouglas Gilbert 	int alloc_len;
1504c65b1445SDouglas Gilbert 
1505773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
1506c65b1445SDouglas Gilbert 	/* following just in case virtual_gb changed */
150728898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
1508c65b1445SDouglas Gilbert 	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1509773642d9SDouglas Gilbert 	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1510773642d9SDouglas Gilbert 	put_unaligned_be32(sdebug_sector_size, arr + 8);
1511773642d9SDouglas Gilbert 	arr[13] = sdebug_physblk_exp & 0xf;
1512773642d9SDouglas Gilbert 	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
151344d92694SMartin K. Petersen 
1514be1dd78dSEric Sandeen 	if (scsi_debug_lbp()) {
15155b94e232SMartin K. Petersen 		arr[14] |= 0x80; /* LBPME */
1516773642d9SDouglas Gilbert 		if (sdebug_lbprz)
1517be1dd78dSEric Sandeen 			arr[14] |= 0x40; /* LBPRZ */
1518be1dd78dSEric Sandeen 	}
151944d92694SMartin K. Petersen 
1520773642d9SDouglas Gilbert 	arr[15] = sdebug_lowest_aligned & 0xff;
1521c6a44287SMartin K. Petersen 
1522773642d9SDouglas Gilbert 	if (sdebug_dif) {
1523773642d9SDouglas Gilbert 		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
1524c6a44287SMartin K. Petersen 		arr[12] |= 1; /* PROT_EN */
1525c6a44287SMartin K. Petersen 	}
1526c6a44287SMartin K. Petersen 
1527c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
1528c65b1445SDouglas Gilbert 				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1529c65b1445SDouglas Gilbert }
1530c65b1445SDouglas Gilbert 
15315a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
15325a09e398SHannes Reinecke 
15335a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp,
15345a09e398SHannes Reinecke 			      struct sdebug_dev_info * devip)
15355a09e398SHannes Reinecke {
153601123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
15375a09e398SHannes Reinecke 	unsigned char * arr;
15385a09e398SHannes Reinecke 	int host_no = devip->sdbg_host->shost->host_no;
15395a09e398SHannes Reinecke 	int n, ret, alen, rlen;
15405a09e398SHannes Reinecke 	int port_group_a, port_group_b, port_a, port_b;
15415a09e398SHannes Reinecke 
1542773642d9SDouglas Gilbert 	alen = get_unaligned_be32(cmd + 6);
15436f3cbf55SDouglas Gilbert 	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
15446f3cbf55SDouglas Gilbert 	if (! arr)
15456f3cbf55SDouglas Gilbert 		return DID_REQUEUE << 16;
15465a09e398SHannes Reinecke 	/*
15475a09e398SHannes Reinecke 	 * EVPD page 0x88 states we have two ports, one
15485a09e398SHannes Reinecke 	 * real and a fake port with no device connected.
15495a09e398SHannes Reinecke 	 * So we create two port groups with one port each
15505a09e398SHannes Reinecke 	 * and set the group with port B to unavailable.
15515a09e398SHannes Reinecke 	 */
15525a09e398SHannes Reinecke 	port_a = 0x1; /* relative port A */
15535a09e398SHannes Reinecke 	port_b = 0x2; /* relative port B */
15545a09e398SHannes Reinecke 	port_group_a = (((host_no + 1) & 0x7f) << 8) +
15555a09e398SHannes Reinecke 			(devip->channel & 0x7f);
15565a09e398SHannes Reinecke 	port_group_b = (((host_no + 1) & 0x7f) << 8) +
15575a09e398SHannes Reinecke 			(devip->channel & 0x7f) + 0x80;
15585a09e398SHannes Reinecke 
15595a09e398SHannes Reinecke 	/*
15605a09e398SHannes Reinecke 	 * The asymmetric access state is cycled according to the host_id.
15615a09e398SHannes Reinecke 	 */
15625a09e398SHannes Reinecke 	n = 4;
1563773642d9SDouglas Gilbert 	if (0 == sdebug_vpd_use_hostno) {
15645a09e398SHannes Reinecke 		arr[n++] = host_no % 3; /* Asymm access state */
15655a09e398SHannes Reinecke 		arr[n++] = 0x0F; /* claim: all states are supported */
15665a09e398SHannes Reinecke 	} else {
15675a09e398SHannes Reinecke 		arr[n++] = 0x0; /* Active/Optimized path */
1568773642d9SDouglas Gilbert 		arr[n++] = 0x01; /* only support active/optimized paths */
15695a09e398SHannes Reinecke 	}
1570773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_a, arr + n);
1571773642d9SDouglas Gilbert 	n += 2;
15725a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15735a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
15745a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
15755a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
15765a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15775a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1578773642d9SDouglas Gilbert 	put_unaligned_be16(port_a, arr + n);
1579773642d9SDouglas Gilbert 	n += 2;
15805a09e398SHannes Reinecke 	arr[n++] = 3;    /* Port unavailable */
15815a09e398SHannes Reinecke 	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1582773642d9SDouglas Gilbert 	put_unaligned_be16(port_group_b, arr + n);
1583773642d9SDouglas Gilbert 	n += 2;
15845a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15855a09e398SHannes Reinecke 	arr[n++] = 0;    /* Status code */
15865a09e398SHannes Reinecke 	arr[n++] = 0;    /* Vendor unique */
15875a09e398SHannes Reinecke 	arr[n++] = 0x1;  /* One port per group */
15885a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
15895a09e398SHannes Reinecke 	arr[n++] = 0;    /* Reserved */
1590773642d9SDouglas Gilbert 	put_unaligned_be16(port_b, arr + n);
1591773642d9SDouglas Gilbert 	n += 2;
15925a09e398SHannes Reinecke 
15935a09e398SHannes Reinecke 	rlen = n - 4;
1594773642d9SDouglas Gilbert 	put_unaligned_be32(rlen, arr + 0);
15955a09e398SHannes Reinecke 
15965a09e398SHannes Reinecke 	/*
15975a09e398SHannes Reinecke 	 * Return the smallest value of either
15985a09e398SHannes Reinecke 	 * - The allocated length
15995a09e398SHannes Reinecke 	 * - The constructed command length
16005a09e398SHannes Reinecke 	 * - The maximum array size
16015a09e398SHannes Reinecke 	 */
16025a09e398SHannes Reinecke 	rlen = min(alen,n);
16035a09e398SHannes Reinecke 	ret = fill_from_dev_buffer(scp, arr,
16045a09e398SHannes Reinecke 				   min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
16055a09e398SHannes Reinecke 	kfree(arr);
16065a09e398SHannes Reinecke 	return ret;
16075a09e398SHannes Reinecke }
16085a09e398SHannes Reinecke 
160938d5c833SDouglas Gilbert static int
161038d5c833SDouglas Gilbert resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
161138d5c833SDouglas Gilbert {
161238d5c833SDouglas Gilbert 	bool rctd;
161338d5c833SDouglas Gilbert 	u8 reporting_opts, req_opcode, sdeb_i, supp;
161438d5c833SDouglas Gilbert 	u16 req_sa, u;
161538d5c833SDouglas Gilbert 	u32 alloc_len, a_len;
161638d5c833SDouglas Gilbert 	int k, offset, len, errsts, count, bump, na;
161738d5c833SDouglas Gilbert 	const struct opcode_info_t *oip;
161838d5c833SDouglas Gilbert 	const struct opcode_info_t *r_oip;
161938d5c833SDouglas Gilbert 	u8 *arr;
162038d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
162138d5c833SDouglas Gilbert 
162238d5c833SDouglas Gilbert 	rctd = !!(cmd[2] & 0x80);
162338d5c833SDouglas Gilbert 	reporting_opts = cmd[2] & 0x7;
162438d5c833SDouglas Gilbert 	req_opcode = cmd[3];
162538d5c833SDouglas Gilbert 	req_sa = get_unaligned_be16(cmd + 4);
162638d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
16276d310dfbSColin Ian King 	if (alloc_len < 4 || alloc_len > 0xffff) {
162838d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
162938d5c833SDouglas Gilbert 		return check_condition_result;
163038d5c833SDouglas Gilbert 	}
163138d5c833SDouglas Gilbert 	if (alloc_len > 8192)
163238d5c833SDouglas Gilbert 		a_len = 8192;
163338d5c833SDouglas Gilbert 	else
163438d5c833SDouglas Gilbert 		a_len = alloc_len;
163599531e60SSasha Levin 	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
163638d5c833SDouglas Gilbert 	if (NULL == arr) {
163738d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
163838d5c833SDouglas Gilbert 				INSUFF_RES_ASCQ);
163938d5c833SDouglas Gilbert 		return check_condition_result;
164038d5c833SDouglas Gilbert 	}
164138d5c833SDouglas Gilbert 	switch (reporting_opts) {
164238d5c833SDouglas Gilbert 	case 0:	/* all commands */
164338d5c833SDouglas Gilbert 		/* count number of commands */
164438d5c833SDouglas Gilbert 		for (count = 0, oip = opcode_info_arr;
164538d5c833SDouglas Gilbert 		     oip->num_attached != 0xff; ++oip) {
164638d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
164738d5c833SDouglas Gilbert 				continue;
164838d5c833SDouglas Gilbert 			count += (oip->num_attached + 1);
164938d5c833SDouglas Gilbert 		}
165038d5c833SDouglas Gilbert 		bump = rctd ? 20 : 8;
165138d5c833SDouglas Gilbert 		put_unaligned_be32(count * bump, arr);
165238d5c833SDouglas Gilbert 		for (offset = 4, oip = opcode_info_arr;
165338d5c833SDouglas Gilbert 		     oip->num_attached != 0xff && offset < a_len; ++oip) {
165438d5c833SDouglas Gilbert 			if (F_INV_OP & oip->flags)
165538d5c833SDouglas Gilbert 				continue;
165638d5c833SDouglas Gilbert 			na = oip->num_attached;
165738d5c833SDouglas Gilbert 			arr[offset] = oip->opcode;
165838d5c833SDouglas Gilbert 			put_unaligned_be16(oip->sa, arr + offset + 2);
165938d5c833SDouglas Gilbert 			if (rctd)
166038d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x2;
166138d5c833SDouglas Gilbert 			if (FF_SA & oip->flags)
166238d5c833SDouglas Gilbert 				arr[offset + 5] |= 0x1;
166338d5c833SDouglas Gilbert 			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
166438d5c833SDouglas Gilbert 			if (rctd)
166538d5c833SDouglas Gilbert 				put_unaligned_be16(0xa, arr + offset + 8);
166638d5c833SDouglas Gilbert 			r_oip = oip;
166738d5c833SDouglas Gilbert 			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
166838d5c833SDouglas Gilbert 				if (F_INV_OP & oip->flags)
166938d5c833SDouglas Gilbert 					continue;
167038d5c833SDouglas Gilbert 				offset += bump;
167138d5c833SDouglas Gilbert 				arr[offset] = oip->opcode;
167238d5c833SDouglas Gilbert 				put_unaligned_be16(oip->sa, arr + offset + 2);
167338d5c833SDouglas Gilbert 				if (rctd)
167438d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x2;
167538d5c833SDouglas Gilbert 				if (FF_SA & oip->flags)
167638d5c833SDouglas Gilbert 					arr[offset + 5] |= 0x1;
167738d5c833SDouglas Gilbert 				put_unaligned_be16(oip->len_mask[0],
167838d5c833SDouglas Gilbert 						   arr + offset + 6);
167938d5c833SDouglas Gilbert 				if (rctd)
168038d5c833SDouglas Gilbert 					put_unaligned_be16(0xa,
168138d5c833SDouglas Gilbert 							   arr + offset + 8);
168238d5c833SDouglas Gilbert 			}
168338d5c833SDouglas Gilbert 			oip = r_oip;
168438d5c833SDouglas Gilbert 			offset += bump;
168538d5c833SDouglas Gilbert 		}
168638d5c833SDouglas Gilbert 		break;
168738d5c833SDouglas Gilbert 	case 1:	/* one command: opcode only */
168838d5c833SDouglas Gilbert 	case 2:	/* one command: opcode plus service action */
168938d5c833SDouglas Gilbert 	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
169038d5c833SDouglas Gilbert 		sdeb_i = opcode_ind_arr[req_opcode];
169138d5c833SDouglas Gilbert 		oip = &opcode_info_arr[sdeb_i];
169238d5c833SDouglas Gilbert 		if (F_INV_OP & oip->flags) {
169338d5c833SDouglas Gilbert 			supp = 1;
169438d5c833SDouglas Gilbert 			offset = 4;
169538d5c833SDouglas Gilbert 		} else {
169638d5c833SDouglas Gilbert 			if (1 == reporting_opts) {
169738d5c833SDouglas Gilbert 				if (FF_SA & oip->flags) {
169838d5c833SDouglas Gilbert 					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
169938d5c833SDouglas Gilbert 							     2, 2);
170038d5c833SDouglas Gilbert 					kfree(arr);
170138d5c833SDouglas Gilbert 					return check_condition_result;
170238d5c833SDouglas Gilbert 				}
170338d5c833SDouglas Gilbert 				req_sa = 0;
170438d5c833SDouglas Gilbert 			} else if (2 == reporting_opts &&
170538d5c833SDouglas Gilbert 				   0 == (FF_SA & oip->flags)) {
170638d5c833SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
170738d5c833SDouglas Gilbert 				kfree(arr);	/* point at requested sa */
170838d5c833SDouglas Gilbert 				return check_condition_result;
170938d5c833SDouglas Gilbert 			}
171038d5c833SDouglas Gilbert 			if (0 == (FF_SA & oip->flags) &&
171138d5c833SDouglas Gilbert 			    req_opcode == oip->opcode)
171238d5c833SDouglas Gilbert 				supp = 3;
171338d5c833SDouglas Gilbert 			else if (0 == (FF_SA & oip->flags)) {
171438d5c833SDouglas Gilbert 				na = oip->num_attached;
171538d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
171638d5c833SDouglas Gilbert 				     ++k, ++oip) {
171738d5c833SDouglas Gilbert 					if (req_opcode == oip->opcode)
171838d5c833SDouglas Gilbert 						break;
171938d5c833SDouglas Gilbert 				}
172038d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
172138d5c833SDouglas Gilbert 			} else if (req_sa != oip->sa) {
172238d5c833SDouglas Gilbert 				na = oip->num_attached;
172338d5c833SDouglas Gilbert 				for (k = 0, oip = oip->arrp; k < na;
172438d5c833SDouglas Gilbert 				     ++k, ++oip) {
172538d5c833SDouglas Gilbert 					if (req_sa == oip->sa)
172638d5c833SDouglas Gilbert 						break;
172738d5c833SDouglas Gilbert 				}
172838d5c833SDouglas Gilbert 				supp = (k >= na) ? 1 : 3;
172938d5c833SDouglas Gilbert 			} else
173038d5c833SDouglas Gilbert 				supp = 3;
173138d5c833SDouglas Gilbert 			if (3 == supp) {
173238d5c833SDouglas Gilbert 				u = oip->len_mask[0];
173338d5c833SDouglas Gilbert 				put_unaligned_be16(u, arr + 2);
173438d5c833SDouglas Gilbert 				arr[4] = oip->opcode;
173538d5c833SDouglas Gilbert 				for (k = 1; k < u; ++k)
173638d5c833SDouglas Gilbert 					arr[4 + k] = (k < 16) ?
173738d5c833SDouglas Gilbert 						 oip->len_mask[k] : 0xff;
173838d5c833SDouglas Gilbert 				offset = 4 + u;
173938d5c833SDouglas Gilbert 			} else
174038d5c833SDouglas Gilbert 				offset = 4;
174138d5c833SDouglas Gilbert 		}
174238d5c833SDouglas Gilbert 		arr[1] = (rctd ? 0x80 : 0) | supp;
174338d5c833SDouglas Gilbert 		if (rctd) {
174438d5c833SDouglas Gilbert 			put_unaligned_be16(0xa, arr + offset);
174538d5c833SDouglas Gilbert 			offset += 12;
174638d5c833SDouglas Gilbert 		}
174738d5c833SDouglas Gilbert 		break;
174838d5c833SDouglas Gilbert 	default:
174938d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
175038d5c833SDouglas Gilbert 		kfree(arr);
175138d5c833SDouglas Gilbert 		return check_condition_result;
175238d5c833SDouglas Gilbert 	}
175338d5c833SDouglas Gilbert 	offset = (offset < a_len) ? offset : a_len;
175438d5c833SDouglas Gilbert 	len = (offset < alloc_len) ? offset : alloc_len;
175538d5c833SDouglas Gilbert 	errsts = fill_from_dev_buffer(scp, arr, len);
175638d5c833SDouglas Gilbert 	kfree(arr);
175738d5c833SDouglas Gilbert 	return errsts;
175838d5c833SDouglas Gilbert }
175938d5c833SDouglas Gilbert 
176038d5c833SDouglas Gilbert static int
176138d5c833SDouglas Gilbert resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
176238d5c833SDouglas Gilbert {
176338d5c833SDouglas Gilbert 	bool repd;
176438d5c833SDouglas Gilbert 	u32 alloc_len, len;
176538d5c833SDouglas Gilbert 	u8 arr[16];
176638d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
176738d5c833SDouglas Gilbert 
176838d5c833SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
176938d5c833SDouglas Gilbert 	repd = !!(cmd[2] & 0x80);
177038d5c833SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 6);
177138d5c833SDouglas Gilbert 	if (alloc_len < 4) {
177238d5c833SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
177338d5c833SDouglas Gilbert 		return check_condition_result;
177438d5c833SDouglas Gilbert 	}
177538d5c833SDouglas Gilbert 	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
177638d5c833SDouglas Gilbert 	arr[1] = 0x1;		/* ITNRS */
177738d5c833SDouglas Gilbert 	if (repd) {
177838d5c833SDouglas Gilbert 		arr[3] = 0xc;
177938d5c833SDouglas Gilbert 		len = 16;
178038d5c833SDouglas Gilbert 	} else
178138d5c833SDouglas Gilbert 		len = 4;
178238d5c833SDouglas Gilbert 
178338d5c833SDouglas Gilbert 	len = (len < alloc_len) ? len : alloc_len;
178438d5c833SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, len);
178538d5c833SDouglas Gilbert }
178638d5c833SDouglas Gilbert 
17871da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */
17881da177e4SLinus Torvalds 
17891da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
17901da177e4SLinus Torvalds {	/* Read-Write Error Recovery page for mode_sense */
17911da177e4SLinus Torvalds 	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
17921da177e4SLinus Torvalds 					5, 0, 0xff, 0xff};
17931da177e4SLinus Torvalds 
17941da177e4SLinus Torvalds 	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
17951da177e4SLinus Torvalds 	if (1 == pcontrol)
17961da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
17971da177e4SLinus Torvalds 	return sizeof(err_recov_pg);
17981da177e4SLinus Torvalds }
17991da177e4SLinus Torvalds 
18001da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
18011da177e4SLinus Torvalds { 	/* Disconnect-Reconnect page for mode_sense */
18021da177e4SLinus Torvalds 	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
18031da177e4SLinus Torvalds 					 0, 0, 0, 0, 0, 0, 0, 0};
18041da177e4SLinus Torvalds 
18051da177e4SLinus Torvalds 	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
18061da177e4SLinus Torvalds 	if (1 == pcontrol)
18071da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
18081da177e4SLinus Torvalds 	return sizeof(disconnect_pg);
18091da177e4SLinus Torvalds }
18101da177e4SLinus Torvalds 
18111da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target)
18121da177e4SLinus Torvalds {       /* Format device page for mode_sense */
18131da177e4SLinus Torvalds 	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
18141da177e4SLinus Torvalds 				     0, 0, 0, 0, 0, 0, 0, 0,
18151da177e4SLinus Torvalds 				     0, 0, 0, 0, 0x40, 0, 0, 0};
18161da177e4SLinus Torvalds 
18171da177e4SLinus Torvalds 	memcpy(p, format_pg, sizeof(format_pg));
1818773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sectors_per, p + 10);
1819773642d9SDouglas Gilbert 	put_unaligned_be16(sdebug_sector_size, p + 12);
1820773642d9SDouglas Gilbert 	if (sdebug_removable)
18211da177e4SLinus Torvalds 		p[20] |= 0x20; /* should agree with INQUIRY */
18221da177e4SLinus Torvalds 	if (1 == pcontrol)
18231da177e4SLinus Torvalds 		memset(p + 2, 0, sizeof(format_pg) - 2);
18241da177e4SLinus Torvalds 	return sizeof(format_pg);
18251da177e4SLinus Torvalds }
18261da177e4SLinus Torvalds 
18271da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
18281da177e4SLinus Torvalds { 	/* Caching page for mode_sense */
1829cbf67842SDouglas Gilbert 	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1830cbf67842SDouglas Gilbert 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1831cbf67842SDouglas Gilbert 	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
18321da177e4SLinus Torvalds 		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
18331da177e4SLinus Torvalds 
1834773642d9SDouglas Gilbert 	if (SDEBUG_OPT_N_WCE & sdebug_opts)
1835cbf67842SDouglas Gilbert 		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
18361da177e4SLinus Torvalds 	memcpy(p, caching_pg, sizeof(caching_pg));
18371da177e4SLinus Torvalds 	if (1 == pcontrol)
1838cbf67842SDouglas Gilbert 		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1839cbf67842SDouglas Gilbert 	else if (2 == pcontrol)
1840cbf67842SDouglas Gilbert 		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
18411da177e4SLinus Torvalds 	return sizeof(caching_pg);
18421da177e4SLinus Torvalds }
18431da177e4SLinus Torvalds 
18441da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
18451da177e4SLinus Torvalds { 	/* Control mode page for mode_sense */
1846c65b1445SDouglas Gilbert 	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1847c65b1445SDouglas Gilbert 				        0, 0, 0, 0};
1848c65b1445SDouglas Gilbert 	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
18491da177e4SLinus Torvalds 				     0, 0, 0x2, 0x4b};
18501da177e4SLinus Torvalds 
1851773642d9SDouglas Gilbert 	if (sdebug_dsense)
18521da177e4SLinus Torvalds 		ctrl_m_pg[2] |= 0x4;
1853c65b1445SDouglas Gilbert 	else
1854c65b1445SDouglas Gilbert 		ctrl_m_pg[2] &= ~0x4;
1855c6a44287SMartin K. Petersen 
1856773642d9SDouglas Gilbert 	if (sdebug_ato)
1857c6a44287SMartin K. Petersen 		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1858c6a44287SMartin K. Petersen 
18591da177e4SLinus Torvalds 	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
18601da177e4SLinus Torvalds 	if (1 == pcontrol)
1861c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1862c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1863c65b1445SDouglas Gilbert 		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
18641da177e4SLinus Torvalds 	return sizeof(ctrl_m_pg);
18651da177e4SLinus Torvalds }
18661da177e4SLinus Torvalds 
1867c65b1445SDouglas Gilbert 
18681da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
18691da177e4SLinus Torvalds {	/* Informational Exceptions control mode page for mode_sense */
1870c65b1445SDouglas Gilbert 	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
18711da177e4SLinus Torvalds 				       0, 0, 0x0, 0x0};
1872c65b1445SDouglas Gilbert 	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1873c65b1445SDouglas Gilbert 				      0, 0, 0x0, 0x0};
1874c65b1445SDouglas Gilbert 
18751da177e4SLinus Torvalds 	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
18761da177e4SLinus Torvalds 	if (1 == pcontrol)
1877c65b1445SDouglas Gilbert 		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1878c65b1445SDouglas Gilbert 	else if (2 == pcontrol)
1879c65b1445SDouglas Gilbert 		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
18801da177e4SLinus Torvalds 	return sizeof(iec_m_pg);
18811da177e4SLinus Torvalds }
18821da177e4SLinus Torvalds 
1883c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1884c65b1445SDouglas Gilbert {	/* SAS SSP mode page - short format for mode_sense */
1885c65b1445SDouglas Gilbert 	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1886c65b1445SDouglas Gilbert 		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1887c65b1445SDouglas Gilbert 
1888c65b1445SDouglas Gilbert 	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1889c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1890c65b1445SDouglas Gilbert 		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1891c65b1445SDouglas Gilbert 	return sizeof(sas_sf_m_pg);
1892c65b1445SDouglas Gilbert }
1893c65b1445SDouglas Gilbert 
1894c65b1445SDouglas Gilbert 
1895c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1896c65b1445SDouglas Gilbert 			      int target_dev_id)
1897c65b1445SDouglas Gilbert {	/* SAS phy control and discover mode page for mode_sense */
1898c65b1445SDouglas Gilbert 	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1899c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1900773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1901773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1902c65b1445SDouglas Gilbert 		    0x2, 0, 0, 0, 0, 0, 0, 0,
1903c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1904c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1905c65b1445SDouglas Gilbert 		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1906773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1907773642d9SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
1908c65b1445SDouglas Gilbert 		    0x3, 0, 0, 0, 0, 0, 0, 0,
1909c65b1445SDouglas Gilbert 		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
1910c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1911c65b1445SDouglas Gilbert 		};
1912c65b1445SDouglas Gilbert 	int port_a, port_b;
1913c65b1445SDouglas Gilbert 
1914773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1915773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1916773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1917773642d9SDouglas Gilbert 	put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
1918c65b1445SDouglas Gilbert 	port_a = target_dev_id + 1;
1919c65b1445SDouglas Gilbert 	port_b = port_a + 1;
1920c65b1445SDouglas Gilbert 	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1921773642d9SDouglas Gilbert 	put_unaligned_be32(port_a, p + 20);
1922773642d9SDouglas Gilbert 	put_unaligned_be32(port_b, p + 48 + 20);
1923c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1924c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1925c65b1445SDouglas Gilbert 	return sizeof(sas_pcd_m_pg);
1926c65b1445SDouglas Gilbert }
1927c65b1445SDouglas Gilbert 
1928c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1929c65b1445SDouglas Gilbert {	/* SAS SSP shared protocol specific port mode subpage */
1930c65b1445SDouglas Gilbert 	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1931c65b1445SDouglas Gilbert 		    0, 0, 0, 0, 0, 0, 0, 0,
1932c65b1445SDouglas Gilbert 		};
1933c65b1445SDouglas Gilbert 
1934c65b1445SDouglas Gilbert 	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1935c65b1445SDouglas Gilbert 	if (1 == pcontrol)
1936c65b1445SDouglas Gilbert 		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1937c65b1445SDouglas Gilbert 	return sizeof(sas_sha_m_pg);
1938c65b1445SDouglas Gilbert }
1939c65b1445SDouglas Gilbert 
19401da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256
19411da177e4SLinus Torvalds 
1942c2248fc9SDouglas Gilbert static int
1943c2248fc9SDouglas Gilbert resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
19441da177e4SLinus Torvalds {
194523183910SDouglas Gilbert 	unsigned char dbd, llbaa;
194623183910SDouglas Gilbert 	int pcontrol, pcode, subpcode, bd_len;
19471da177e4SLinus Torvalds 	unsigned char dev_spec;
1948773642d9SDouglas Gilbert 	int alloc_len, msense_6, offset, len, target_dev_id;
1949c2248fc9SDouglas Gilbert 	int target = scp->device->id;
19501da177e4SLinus Torvalds 	unsigned char * ap;
19511da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
195201123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
19531da177e4SLinus Torvalds 
195423183910SDouglas Gilbert 	dbd = !!(cmd[1] & 0x8);
19551da177e4SLinus Torvalds 	pcontrol = (cmd[2] & 0xc0) >> 6;
19561da177e4SLinus Torvalds 	pcode = cmd[2] & 0x3f;
19571da177e4SLinus Torvalds 	subpcode = cmd[3];
19581da177e4SLinus Torvalds 	msense_6 = (MODE_SENSE == cmd[0]);
195923183910SDouglas Gilbert 	llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1960773642d9SDouglas Gilbert 	if ((0 == sdebug_ptype) && (0 == dbd))
196123183910SDouglas Gilbert 		bd_len = llbaa ? 16 : 8;
196223183910SDouglas Gilbert 	else
196323183910SDouglas Gilbert 		bd_len = 0;
1964773642d9SDouglas Gilbert 	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
19651da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
19661da177e4SLinus Torvalds 	if (0x3 == pcontrol) {  /* Saving values not supported */
1967cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
19681da177e4SLinus Torvalds 		return check_condition_result;
19691da177e4SLinus Torvalds 	}
1970c65b1445SDouglas Gilbert 	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1971c65b1445SDouglas Gilbert 			(devip->target * 1000) - 3;
197223183910SDouglas Gilbert 	/* set DPOFUA bit for disks */
1973773642d9SDouglas Gilbert 	if (0 == sdebug_ptype)
197423183910SDouglas Gilbert 		dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
197523183910SDouglas Gilbert 	else
197623183910SDouglas Gilbert 		dev_spec = 0x0;
19771da177e4SLinus Torvalds 	if (msense_6) {
19781da177e4SLinus Torvalds 		arr[2] = dev_spec;
197923183910SDouglas Gilbert 		arr[3] = bd_len;
19801da177e4SLinus Torvalds 		offset = 4;
19811da177e4SLinus Torvalds 	} else {
19821da177e4SLinus Torvalds 		arr[3] = dev_spec;
198323183910SDouglas Gilbert 		if (16 == bd_len)
198423183910SDouglas Gilbert 			arr[4] = 0x1;	/* set LONGLBA bit */
198523183910SDouglas Gilbert 		arr[7] = bd_len;	/* assume 255 or less */
19861da177e4SLinus Torvalds 		offset = 8;
19871da177e4SLinus Torvalds 	}
19881da177e4SLinus Torvalds 	ap = arr + offset;
198928898873SFUJITA Tomonori 	if ((bd_len > 0) && (!sdebug_capacity))
199028898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
199128898873SFUJITA Tomonori 
199223183910SDouglas Gilbert 	if (8 == bd_len) {
1993773642d9SDouglas Gilbert 		if (sdebug_capacity > 0xfffffffe)
1994773642d9SDouglas Gilbert 			put_unaligned_be32(0xffffffff, ap + 0);
1995773642d9SDouglas Gilbert 		else
1996773642d9SDouglas Gilbert 			put_unaligned_be32(sdebug_capacity, ap + 0);
1997773642d9SDouglas Gilbert 		put_unaligned_be16(sdebug_sector_size, ap + 6);
199823183910SDouglas Gilbert 		offset += bd_len;
199923183910SDouglas Gilbert 		ap = arr + offset;
200023183910SDouglas Gilbert 	} else if (16 == bd_len) {
2001773642d9SDouglas Gilbert 		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2002773642d9SDouglas Gilbert 		put_unaligned_be32(sdebug_sector_size, ap + 12);
200323183910SDouglas Gilbert 		offset += bd_len;
200423183910SDouglas Gilbert 		ap = arr + offset;
200523183910SDouglas Gilbert 	}
20061da177e4SLinus Torvalds 
2007c65b1445SDouglas Gilbert 	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2008c65b1445SDouglas Gilbert 		/* TODO: Control Extension page */
200922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
20101da177e4SLinus Torvalds 		return check_condition_result;
20111da177e4SLinus Torvalds 	}
20121da177e4SLinus Torvalds 	switch (pcode) {
20131da177e4SLinus Torvalds 	case 0x1:	/* Read-Write error recovery page, direct access */
20141da177e4SLinus Torvalds 		len = resp_err_recov_pg(ap, pcontrol, target);
20151da177e4SLinus Torvalds 		offset += len;
20161da177e4SLinus Torvalds 		break;
20171da177e4SLinus Torvalds 	case 0x2:	/* Disconnect-Reconnect page, all devices */
20181da177e4SLinus Torvalds 		len = resp_disconnect_pg(ap, pcontrol, target);
20191da177e4SLinus Torvalds 		offset += len;
20201da177e4SLinus Torvalds 		break;
20211da177e4SLinus Torvalds         case 0x3:       /* Format device page, direct access */
20221da177e4SLinus Torvalds                 len = resp_format_pg(ap, pcontrol, target);
20231da177e4SLinus Torvalds                 offset += len;
20241da177e4SLinus Torvalds                 break;
20251da177e4SLinus Torvalds 	case 0x8:	/* Caching page, direct access */
20261da177e4SLinus Torvalds 		len = resp_caching_pg(ap, pcontrol, target);
20271da177e4SLinus Torvalds 		offset += len;
20281da177e4SLinus Torvalds 		break;
20291da177e4SLinus Torvalds 	case 0xa:	/* Control Mode page, all devices */
20301da177e4SLinus Torvalds 		len = resp_ctrl_m_pg(ap, pcontrol, target);
20311da177e4SLinus Torvalds 		offset += len;
20321da177e4SLinus Torvalds 		break;
2033c65b1445SDouglas Gilbert 	case 0x19:	/* if spc==1 then sas phy, control+discover */
2034c65b1445SDouglas Gilbert 		if ((subpcode > 0x2) && (subpcode < 0xff)) {
203522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2036c65b1445SDouglas Gilbert 			return check_condition_result;
2037c65b1445SDouglas Gilbert 	        }
2038c65b1445SDouglas Gilbert 		len = 0;
2039c65b1445SDouglas Gilbert 		if ((0x0 == subpcode) || (0xff == subpcode))
2040c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2041c65b1445SDouglas Gilbert 		if ((0x1 == subpcode) || (0xff == subpcode))
2042c65b1445SDouglas Gilbert 			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2043c65b1445SDouglas Gilbert 						  target_dev_id);
2044c65b1445SDouglas Gilbert 		if ((0x2 == subpcode) || (0xff == subpcode))
2045c65b1445SDouglas Gilbert 			len += resp_sas_sha_m_spg(ap + len, pcontrol);
2046c65b1445SDouglas Gilbert 		offset += len;
2047c65b1445SDouglas Gilbert 		break;
20481da177e4SLinus Torvalds 	case 0x1c:	/* Informational Exceptions Mode page, all devices */
20491da177e4SLinus Torvalds 		len = resp_iec_m_pg(ap, pcontrol, target);
20501da177e4SLinus Torvalds 		offset += len;
20511da177e4SLinus Torvalds 		break;
20521da177e4SLinus Torvalds 	case 0x3f:	/* Read all Mode pages */
2053c65b1445SDouglas Gilbert 		if ((0 == subpcode) || (0xff == subpcode)) {
20541da177e4SLinus Torvalds 			len = resp_err_recov_pg(ap, pcontrol, target);
20551da177e4SLinus Torvalds 			len += resp_disconnect_pg(ap + len, pcontrol, target);
20561da177e4SLinus Torvalds 			len += resp_format_pg(ap + len, pcontrol, target);
20571da177e4SLinus Torvalds 			len += resp_caching_pg(ap + len, pcontrol, target);
20581da177e4SLinus Torvalds 			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2059c65b1445SDouglas Gilbert 			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2060c65b1445SDouglas Gilbert 			if (0xff == subpcode) {
2061c65b1445SDouglas Gilbert 				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2062c65b1445SDouglas Gilbert 						  target, target_dev_id);
2063c65b1445SDouglas Gilbert 				len += resp_sas_sha_m_spg(ap + len, pcontrol);
2064c65b1445SDouglas Gilbert 			}
20651da177e4SLinus Torvalds 			len += resp_iec_m_pg(ap + len, pcontrol, target);
2066c65b1445SDouglas Gilbert 		} else {
206722017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
2068c65b1445SDouglas Gilbert 			return check_condition_result;
2069c65b1445SDouglas Gilbert                 }
20701da177e4SLinus Torvalds 		offset += len;
20711da177e4SLinus Torvalds 		break;
20721da177e4SLinus Torvalds 	default:
207322017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
20741da177e4SLinus Torvalds 		return check_condition_result;
20751da177e4SLinus Torvalds 	}
20761da177e4SLinus Torvalds 	if (msense_6)
20771da177e4SLinus Torvalds 		arr[0] = offset - 1;
2078773642d9SDouglas Gilbert 	else
2079773642d9SDouglas Gilbert 		put_unaligned_be16((offset - 2), arr + 0);
20801da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
20811da177e4SLinus Torvalds }
20821da177e4SLinus Torvalds 
2083c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512
2084c65b1445SDouglas Gilbert 
2085c2248fc9SDouglas Gilbert static int
2086c2248fc9SDouglas Gilbert resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2087c65b1445SDouglas Gilbert {
2088c65b1445SDouglas Gilbert 	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
2089c2248fc9SDouglas Gilbert 	int param_len, res, mpage;
2090c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
209101123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2092c2248fc9SDouglas Gilbert 	int mselect6 = (MODE_SELECT == cmd[0]);
2093c65b1445SDouglas Gilbert 
2094c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2095c65b1445SDouglas Gilbert 	pf = cmd[1] & 0x10;
2096c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2097773642d9SDouglas Gilbert 	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
2098c65b1445SDouglas Gilbert 	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
209922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
2100c65b1445SDouglas Gilbert 		return check_condition_result;
2101c65b1445SDouglas Gilbert 	}
2102c65b1445SDouglas Gilbert         res = fetch_to_dev_buffer(scp, arr, param_len);
2103c65b1445SDouglas Gilbert         if (-1 == res)
2104773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2105773642d9SDouglas Gilbert 	else if (sdebug_verbose && (res < param_len))
2106cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2107cbf67842SDouglas Gilbert 			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
2108cbf67842SDouglas Gilbert 			    __func__, param_len, res);
2109773642d9SDouglas Gilbert 	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2110773642d9SDouglas Gilbert 	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
211123183910SDouglas Gilbert 	if (md_len > 2) {
211222017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
2113c65b1445SDouglas Gilbert 		return check_condition_result;
2114c65b1445SDouglas Gilbert 	}
2115c65b1445SDouglas Gilbert 	off = bd_len + (mselect6 ? 4 : 8);
2116c65b1445SDouglas Gilbert 	mpage = arr[off] & 0x3f;
2117c65b1445SDouglas Gilbert 	ps = !!(arr[off] & 0x80);
2118c65b1445SDouglas Gilbert 	if (ps) {
211922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
2120c65b1445SDouglas Gilbert 		return check_condition_result;
2121c65b1445SDouglas Gilbert 	}
2122c65b1445SDouglas Gilbert 	spf = !!(arr[off] & 0x40);
2123773642d9SDouglas Gilbert 	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
2124c65b1445SDouglas Gilbert 		       (arr[off + 1] + 2);
2125c65b1445SDouglas Gilbert 	if ((pg_len + off) > param_len) {
2126cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST,
2127c65b1445SDouglas Gilbert 				PARAMETER_LIST_LENGTH_ERR, 0);
2128c65b1445SDouglas Gilbert 		return check_condition_result;
2129c65b1445SDouglas Gilbert 	}
2130c65b1445SDouglas Gilbert 	switch (mpage) {
2131cbf67842SDouglas Gilbert 	case 0x8:      /* Caching Mode page */
2132cbf67842SDouglas Gilbert 		if (caching_pg[1] == arr[off + 1]) {
2133cbf67842SDouglas Gilbert 			memcpy(caching_pg + 2, arr + off + 2,
2134cbf67842SDouglas Gilbert 			       sizeof(caching_pg) - 2);
2135cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2136cbf67842SDouglas Gilbert 		}
2137cbf67842SDouglas Gilbert 		break;
2138c65b1445SDouglas Gilbert 	case 0xa:      /* Control Mode page */
2139c65b1445SDouglas Gilbert 		if (ctrl_m_pg[1] == arr[off + 1]) {
2140c65b1445SDouglas Gilbert 			memcpy(ctrl_m_pg + 2, arr + off + 2,
2141c65b1445SDouglas Gilbert 			       sizeof(ctrl_m_pg) - 2);
2142773642d9SDouglas Gilbert 			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
2143cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2144c65b1445SDouglas Gilbert 		}
2145c65b1445SDouglas Gilbert 		break;
2146c65b1445SDouglas Gilbert 	case 0x1c:      /* Informational Exceptions Mode page */
2147c65b1445SDouglas Gilbert 		if (iec_m_pg[1] == arr[off + 1]) {
2148c65b1445SDouglas Gilbert 			memcpy(iec_m_pg + 2, arr + off + 2,
2149c65b1445SDouglas Gilbert 			       sizeof(iec_m_pg) - 2);
2150cbf67842SDouglas Gilbert 			goto set_mode_changed_ua;
2151c65b1445SDouglas Gilbert 		}
2152c65b1445SDouglas Gilbert 		break;
2153c65b1445SDouglas Gilbert 	default:
2154c65b1445SDouglas Gilbert 		break;
2155c65b1445SDouglas Gilbert 	}
215622017ed2SDouglas Gilbert 	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
2157c65b1445SDouglas Gilbert 	return check_condition_result;
2158cbf67842SDouglas Gilbert set_mode_changed_ua:
2159cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2160cbf67842SDouglas Gilbert 	return 0;
2161c65b1445SDouglas Gilbert }
2162c65b1445SDouglas Gilbert 
2163c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr)
2164c65b1445SDouglas Gilbert {
2165c65b1445SDouglas Gilbert 	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2166c65b1445SDouglas Gilbert 				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
2167c65b1445SDouglas Gilbert 		};
2168c65b1445SDouglas Gilbert 
2169c65b1445SDouglas Gilbert         memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2170c65b1445SDouglas Gilbert         return sizeof(temp_l_pg);
2171c65b1445SDouglas Gilbert }
2172c65b1445SDouglas Gilbert 
2173c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr)
2174c65b1445SDouglas Gilbert {
2175c65b1445SDouglas Gilbert 	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2176c65b1445SDouglas Gilbert 		};
2177c65b1445SDouglas Gilbert 
2178c65b1445SDouglas Gilbert         memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2179c65b1445SDouglas Gilbert 	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
2180c65b1445SDouglas Gilbert 		arr[4] = THRESHOLD_EXCEEDED;
2181c65b1445SDouglas Gilbert 		arr[5] = 0xff;
2182c65b1445SDouglas Gilbert 	}
2183c65b1445SDouglas Gilbert         return sizeof(ie_l_pg);
2184c65b1445SDouglas Gilbert }
2185c65b1445SDouglas Gilbert 
2186c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512
2187c65b1445SDouglas Gilbert 
2188c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp,
2189c65b1445SDouglas Gilbert                           struct sdebug_dev_info * devip)
2190c65b1445SDouglas Gilbert {
2191c2248fc9SDouglas Gilbert 	int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
2192c65b1445SDouglas Gilbert 	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
219301123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
2194c65b1445SDouglas Gilbert 
2195c65b1445SDouglas Gilbert 	memset(arr, 0, sizeof(arr));
2196c65b1445SDouglas Gilbert 	ppc = cmd[1] & 0x2;
2197c65b1445SDouglas Gilbert 	sp = cmd[1] & 0x1;
2198c65b1445SDouglas Gilbert 	if (ppc || sp) {
219922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
2200c65b1445SDouglas Gilbert 		return check_condition_result;
2201c65b1445SDouglas Gilbert 	}
2202c65b1445SDouglas Gilbert 	pcontrol = (cmd[2] & 0xc0) >> 6;
2203c65b1445SDouglas Gilbert 	pcode = cmd[2] & 0x3f;
220423183910SDouglas Gilbert 	subpcode = cmd[3] & 0xff;
2205773642d9SDouglas Gilbert 	alloc_len = get_unaligned_be16(cmd + 7);
2206c65b1445SDouglas Gilbert 	arr[0] = pcode;
220723183910SDouglas Gilbert 	if (0 == subpcode) {
2208c65b1445SDouglas Gilbert 		switch (pcode) {
2209c65b1445SDouglas Gilbert 		case 0x0:	/* Supported log pages log page */
2210c65b1445SDouglas Gilbert 			n = 4;
2211c65b1445SDouglas Gilbert 			arr[n++] = 0x0;		/* this page */
2212c65b1445SDouglas Gilbert 			arr[n++] = 0xd;		/* Temperature */
2213c65b1445SDouglas Gilbert 			arr[n++] = 0x2f;	/* Informational exceptions */
2214c65b1445SDouglas Gilbert 			arr[3] = n - 4;
2215c65b1445SDouglas Gilbert 			break;
2216c65b1445SDouglas Gilbert 		case 0xd:	/* Temperature log page */
2217c65b1445SDouglas Gilbert 			arr[3] = resp_temp_l_pg(arr + 4);
2218c65b1445SDouglas Gilbert 			break;
2219c65b1445SDouglas Gilbert 		case 0x2f:	/* Informational exceptions log page */
2220c65b1445SDouglas Gilbert 			arr[3] = resp_ie_l_pg(arr + 4);
2221c65b1445SDouglas Gilbert 			break;
2222c65b1445SDouglas Gilbert 		default:
222322017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
2224c65b1445SDouglas Gilbert 			return check_condition_result;
2225c65b1445SDouglas Gilbert 		}
222623183910SDouglas Gilbert 	} else if (0xff == subpcode) {
222723183910SDouglas Gilbert 		arr[0] |= 0x40;
222823183910SDouglas Gilbert 		arr[1] = subpcode;
222923183910SDouglas Gilbert 		switch (pcode) {
223023183910SDouglas Gilbert 		case 0x0:	/* Supported log pages and subpages log page */
223123183910SDouglas Gilbert 			n = 4;
223223183910SDouglas Gilbert 			arr[n++] = 0x0;
223323183910SDouglas Gilbert 			arr[n++] = 0x0;		/* 0,0 page */
223423183910SDouglas Gilbert 			arr[n++] = 0x0;
223523183910SDouglas Gilbert 			arr[n++] = 0xff;	/* this page */
223623183910SDouglas Gilbert 			arr[n++] = 0xd;
223723183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
223823183910SDouglas Gilbert 			arr[n++] = 0x2f;
223923183910SDouglas Gilbert 			arr[n++] = 0x0;	/* Informational exceptions */
224023183910SDouglas Gilbert 			arr[3] = n - 4;
224123183910SDouglas Gilbert 			break;
224223183910SDouglas Gilbert 		case 0xd:	/* Temperature subpages */
224323183910SDouglas Gilbert 			n = 4;
224423183910SDouglas Gilbert 			arr[n++] = 0xd;
224523183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Temperature */
224623183910SDouglas Gilbert 			arr[3] = n - 4;
224723183910SDouglas Gilbert 			break;
224823183910SDouglas Gilbert 		case 0x2f:	/* Informational exceptions subpages */
224923183910SDouglas Gilbert 			n = 4;
225023183910SDouglas Gilbert 			arr[n++] = 0x2f;
225123183910SDouglas Gilbert 			arr[n++] = 0x0;		/* Informational exceptions */
225223183910SDouglas Gilbert 			arr[3] = n - 4;
225323183910SDouglas Gilbert 			break;
225423183910SDouglas Gilbert 		default:
225522017ed2SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
225623183910SDouglas Gilbert 			return check_condition_result;
225723183910SDouglas Gilbert 		}
225823183910SDouglas Gilbert 	} else {
225922017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
226023183910SDouglas Gilbert 		return check_condition_result;
226123183910SDouglas Gilbert 	}
2262773642d9SDouglas Gilbert 	len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
2263c65b1445SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr,
2264c65b1445SDouglas Gilbert 		    min(len, SDEBUG_MAX_INQ_ARR_SZ));
2265c65b1445SDouglas Gilbert }
2266c65b1445SDouglas Gilbert 
2267cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp,
226819789100SFUJITA Tomonori 				      unsigned long long lba, unsigned int num)
22691da177e4SLinus Torvalds {
2270c65b1445SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
227122017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
22721da177e4SLinus Torvalds 		return check_condition_result;
22731da177e4SLinus Torvalds 	}
2274c65b1445SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2275c65b1445SDouglas Gilbert 	if (num > sdebug_store_sectors) {
227622017ed2SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2277cbf67842SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2278c65b1445SDouglas Gilbert 		return check_condition_result;
2279c65b1445SDouglas Gilbert 	}
228019789100SFUJITA Tomonori 	return 0;
228119789100SFUJITA Tomonori }
228219789100SFUJITA Tomonori 
2283a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */
2284c2248fc9SDouglas Gilbert static int
2285c2248fc9SDouglas Gilbert do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write)
228619789100SFUJITA Tomonori {
228719789100SFUJITA Tomonori 	int ret;
2288c2248fc9SDouglas Gilbert 	u64 block, rest = 0;
2289a4517511SAkinobu Mita 	struct scsi_data_buffer *sdb;
2290a4517511SAkinobu Mita 	enum dma_data_direction dir;
229119789100SFUJITA Tomonori 
2292c2248fc9SDouglas Gilbert 	if (do_write) {
2293a4517511SAkinobu Mita 		sdb = scsi_out(scmd);
2294a4517511SAkinobu Mita 		dir = DMA_TO_DEVICE;
2295a4517511SAkinobu Mita 	} else {
2296a4517511SAkinobu Mita 		sdb = scsi_in(scmd);
2297a4517511SAkinobu Mita 		dir = DMA_FROM_DEVICE;
2298a4517511SAkinobu Mita 	}
2299a4517511SAkinobu Mita 
2300a4517511SAkinobu Mita 	if (!sdb->length)
2301a4517511SAkinobu Mita 		return 0;
2302a4517511SAkinobu Mita 	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2303a4517511SAkinobu Mita 		return -1;
230419789100SFUJITA Tomonori 
230519789100SFUJITA Tomonori 	block = do_div(lba, sdebug_store_sectors);
230619789100SFUJITA Tomonori 	if (block + num > sdebug_store_sectors)
230719789100SFUJITA Tomonori 		rest = block + num - sdebug_store_sectors;
230819789100SFUJITA Tomonori 
2309386ecb12SDave Gordon 	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2310773642d9SDouglas Gilbert 		   fake_storep + (block * sdebug_sector_size),
2311773642d9SDouglas Gilbert 		   (num - rest) * sdebug_sector_size, 0, do_write);
2312773642d9SDouglas Gilbert 	if (ret != (num - rest) * sdebug_sector_size)
2313a4517511SAkinobu Mita 		return ret;
2314a4517511SAkinobu Mita 
2315a4517511SAkinobu Mita 	if (rest) {
2316386ecb12SDave Gordon 		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
2317773642d9SDouglas Gilbert 			    fake_storep, rest * sdebug_sector_size,
2318773642d9SDouglas Gilbert 			    (num - rest) * sdebug_sector_size, do_write);
2319a4517511SAkinobu Mita 	}
232019789100SFUJITA Tomonori 
232119789100SFUJITA Tomonori 	return ret;
232219789100SFUJITA Tomonori }
232319789100SFUJITA Tomonori 
232438d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of
232538d5c833SDouglas Gilbert  * arr into fake_store(lba,num) and return true. If comparison fails then
232638d5c833SDouglas Gilbert  * return false. */
232738d5c833SDouglas Gilbert static bool
232838d5c833SDouglas Gilbert comp_write_worker(u64 lba, u32 num, const u8 *arr)
232938d5c833SDouglas Gilbert {
233038d5c833SDouglas Gilbert 	bool res;
233138d5c833SDouglas Gilbert 	u64 block, rest = 0;
233238d5c833SDouglas Gilbert 	u32 store_blks = sdebug_store_sectors;
2333773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
233438d5c833SDouglas Gilbert 
233538d5c833SDouglas Gilbert 	block = do_div(lba, store_blks);
233638d5c833SDouglas Gilbert 	if (block + num > store_blks)
233738d5c833SDouglas Gilbert 		rest = block + num - store_blks;
233838d5c833SDouglas Gilbert 
233938d5c833SDouglas Gilbert 	res = !memcmp(fake_storep + (block * lb_size), arr,
234038d5c833SDouglas Gilbert 		      (num - rest) * lb_size);
234138d5c833SDouglas Gilbert 	if (!res)
234238d5c833SDouglas Gilbert 		return res;
234338d5c833SDouglas Gilbert 	if (rest)
234438d5c833SDouglas Gilbert 		res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
234538d5c833SDouglas Gilbert 			     rest * lb_size);
234638d5c833SDouglas Gilbert 	if (!res)
234738d5c833SDouglas Gilbert 		return res;
234838d5c833SDouglas Gilbert 	arr += num * lb_size;
234938d5c833SDouglas Gilbert 	memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
235038d5c833SDouglas Gilbert 	if (rest)
235138d5c833SDouglas Gilbert 		memcpy(fake_storep, arr + ((num - rest) * lb_size),
235238d5c833SDouglas Gilbert 		       rest * lb_size);
235338d5c833SDouglas Gilbert 	return res;
235438d5c833SDouglas Gilbert }
235538d5c833SDouglas Gilbert 
235651d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len)
2357beb40ea4SAkinobu Mita {
235851d648afSAkinobu Mita 	__be16 csum;
2359beb40ea4SAkinobu Mita 
2360773642d9SDouglas Gilbert 	if (sdebug_guard)
236151d648afSAkinobu Mita 		csum = (__force __be16)ip_compute_csum(buf, len);
236251d648afSAkinobu Mita 	else
2363beb40ea4SAkinobu Mita 		csum = cpu_to_be16(crc_t10dif(buf, len));
236451d648afSAkinobu Mita 
2365beb40ea4SAkinobu Mita 	return csum;
2366beb40ea4SAkinobu Mita }
2367beb40ea4SAkinobu Mita 
2368beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2369beb40ea4SAkinobu Mita 		      sector_t sector, u32 ei_lba)
2370beb40ea4SAkinobu Mita {
2371773642d9SDouglas Gilbert 	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
2372beb40ea4SAkinobu Mita 
2373beb40ea4SAkinobu Mita 	if (sdt->guard_tag != csum) {
2374c1287970STomas Winkler 		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2375beb40ea4SAkinobu Mita 			(unsigned long)sector,
2376beb40ea4SAkinobu Mita 			be16_to_cpu(sdt->guard_tag),
2377beb40ea4SAkinobu Mita 			be16_to_cpu(csum));
2378beb40ea4SAkinobu Mita 		return 0x01;
2379beb40ea4SAkinobu Mita 	}
2380773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
2381beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2382c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2383c1287970STomas Winkler 			(unsigned long)sector);
2384beb40ea4SAkinobu Mita 		return 0x03;
2385beb40ea4SAkinobu Mita 	}
2386773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2387beb40ea4SAkinobu Mita 	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
2388c1287970STomas Winkler 		pr_err("REF check failed on sector %lu\n",
2389c1287970STomas Winkler 			(unsigned long)sector);
2390beb40ea4SAkinobu Mita 		return 0x03;
2391beb40ea4SAkinobu Mita 	}
2392beb40ea4SAkinobu Mita 	return 0;
2393beb40ea4SAkinobu Mita }
2394beb40ea4SAkinobu Mita 
2395bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
239665f72f2aSAkinobu Mita 			  unsigned int sectors, bool read)
2397c6a44287SMartin K. Petersen {
2398be4e11beSAkinobu Mita 	size_t resid;
2399c6a44287SMartin K. Petersen 	void *paddr;
240014faa944SAkinobu Mita 	const void *dif_store_end = dif_storep + sdebug_store_sectors;
2401be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
2402c6a44287SMartin K. Petersen 
2403e18d8beaSAkinobu Mita 	/* Bytes of protection data to copy into sgl */
2404e18d8beaSAkinobu Mita 	resid = sectors * sizeof(*dif_storep);
2405c6a44287SMartin K. Petersen 
2406be4e11beSAkinobu Mita 	sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2407be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2408be4e11beSAkinobu Mita 			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2409be4e11beSAkinobu Mita 
2410be4e11beSAkinobu Mita 	while (sg_miter_next(&miter) && resid > 0) {
2411be4e11beSAkinobu Mita 		size_t len = min(miter.length, resid);
241214faa944SAkinobu Mita 		void *start = dif_store(sector);
2413be4e11beSAkinobu Mita 		size_t rest = 0;
241414faa944SAkinobu Mita 
241514faa944SAkinobu Mita 		if (dif_store_end < start + len)
241614faa944SAkinobu Mita 			rest = start + len - dif_store_end;
2417c6a44287SMartin K. Petersen 
2418be4e11beSAkinobu Mita 		paddr = miter.addr;
241914faa944SAkinobu Mita 
242065f72f2aSAkinobu Mita 		if (read)
242165f72f2aSAkinobu Mita 			memcpy(paddr, start, len - rest);
242265f72f2aSAkinobu Mita 		else
242365f72f2aSAkinobu Mita 			memcpy(start, paddr, len - rest);
242465f72f2aSAkinobu Mita 
242565f72f2aSAkinobu Mita 		if (rest) {
242665f72f2aSAkinobu Mita 			if (read)
242714faa944SAkinobu Mita 				memcpy(paddr + len - rest, dif_storep, rest);
242865f72f2aSAkinobu Mita 			else
242965f72f2aSAkinobu Mita 				memcpy(dif_storep, paddr + len - rest, rest);
243065f72f2aSAkinobu Mita 		}
2431c6a44287SMartin K. Petersen 
2432e18d8beaSAkinobu Mita 		sector += len / sizeof(*dif_storep);
2433c6a44287SMartin K. Petersen 		resid -= len;
2434c6a44287SMartin K. Petersen 	}
2435be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
2436bb8c063cSAkinobu Mita }
2437c6a44287SMartin K. Petersen 
2438bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2439bb8c063cSAkinobu Mita 			    unsigned int sectors, u32 ei_lba)
2440bb8c063cSAkinobu Mita {
2441bb8c063cSAkinobu Mita 	unsigned int i;
2442bb8c063cSAkinobu Mita 	struct sd_dif_tuple *sdt;
2443bb8c063cSAkinobu Mita 	sector_t sector;
2444bb8c063cSAkinobu Mita 
2445c45eabecSAkinobu Mita 	for (i = 0; i < sectors; i++, ei_lba++) {
2446bb8c063cSAkinobu Mita 		int ret;
2447bb8c063cSAkinobu Mita 
2448bb8c063cSAkinobu Mita 		sector = start_sec + i;
2449bb8c063cSAkinobu Mita 		sdt = dif_store(sector);
2450bb8c063cSAkinobu Mita 
245151d648afSAkinobu Mita 		if (sdt->app_tag == cpu_to_be16(0xffff))
2452bb8c063cSAkinobu Mita 			continue;
2453bb8c063cSAkinobu Mita 
2454bb8c063cSAkinobu Mita 		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2455bb8c063cSAkinobu Mita 		if (ret) {
2456bb8c063cSAkinobu Mita 			dif_errors++;
2457bb8c063cSAkinobu Mita 			return ret;
2458bb8c063cSAkinobu Mita 		}
2459bb8c063cSAkinobu Mita 	}
2460bb8c063cSAkinobu Mita 
246165f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, true);
2462c6a44287SMartin K. Petersen 	dix_reads++;
2463c6a44287SMartin K. Petersen 
2464c6a44287SMartin K. Petersen 	return 0;
2465c6a44287SMartin K. Petersen }
2466c6a44287SMartin K. Petersen 
2467c2248fc9SDouglas Gilbert static int
2468c2248fc9SDouglas Gilbert resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
246919789100SFUJITA Tomonori {
2470c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2471c2248fc9SDouglas Gilbert 	u64 lba;
2472c2248fc9SDouglas Gilbert 	u32 num;
2473c2248fc9SDouglas Gilbert 	u32 ei_lba;
247419789100SFUJITA Tomonori 	unsigned long iflags;
247519789100SFUJITA Tomonori 	int ret;
2476c2248fc9SDouglas Gilbert 	bool check_prot;
247719789100SFUJITA Tomonori 
2478c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2479c2248fc9SDouglas Gilbert 	case READ_16:
2480c2248fc9SDouglas Gilbert 		ei_lba = 0;
2481c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2482c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2483c2248fc9SDouglas Gilbert 		check_prot = true;
2484c2248fc9SDouglas Gilbert 		break;
2485c2248fc9SDouglas Gilbert 	case READ_10:
2486c2248fc9SDouglas Gilbert 		ei_lba = 0;
2487c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2488c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2489c2248fc9SDouglas Gilbert 		check_prot = true;
2490c2248fc9SDouglas Gilbert 		break;
2491c2248fc9SDouglas Gilbert 	case READ_6:
2492c2248fc9SDouglas Gilbert 		ei_lba = 0;
2493c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2494c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2495c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2496c2248fc9SDouglas Gilbert 		check_prot = true;
2497c2248fc9SDouglas Gilbert 		break;
2498c2248fc9SDouglas Gilbert 	case READ_12:
2499c2248fc9SDouglas Gilbert 		ei_lba = 0;
2500c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2501c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2502c2248fc9SDouglas Gilbert 		check_prot = true;
2503c2248fc9SDouglas Gilbert 		break;
2504c2248fc9SDouglas Gilbert 	case XDWRITEREAD_10:
2505c2248fc9SDouglas Gilbert 		ei_lba = 0;
2506c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2507c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2508c2248fc9SDouglas Gilbert 		check_prot = false;
2509c2248fc9SDouglas Gilbert 		break;
2510c2248fc9SDouglas Gilbert 	default:	/* assume READ(32) */
2511c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2512c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2513c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2514c2248fc9SDouglas Gilbert 		check_prot = false;
2515c2248fc9SDouglas Gilbert 		break;
2516c2248fc9SDouglas Gilbert 	}
2517c2248fc9SDouglas Gilbert 	if (check_prot) {
2518773642d9SDouglas Gilbert 		if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2519c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2520c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2521c2248fc9SDouglas Gilbert 			return check_condition_result;
2522c2248fc9SDouglas Gilbert 		}
2523773642d9SDouglas Gilbert 		if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2524773642d9SDouglas Gilbert 		     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
2525c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2526c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2527c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2528c2248fc9SDouglas Gilbert 	}
2529c2248fc9SDouglas Gilbert 	if (sdebug_any_injecting_opt) {
2530c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2531c2248fc9SDouglas Gilbert 
2532c2248fc9SDouglas Gilbert 		if (ep->inj_short)
2533c2248fc9SDouglas Gilbert 			num /= 2;
2534c2248fc9SDouglas Gilbert 	}
2535c2248fc9SDouglas Gilbert 
2536c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2537c2248fc9SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
2538c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2539c2248fc9SDouglas Gilbert 		return check_condition_result;
2540c2248fc9SDouglas Gilbert 	}
2541c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2542c2248fc9SDouglas Gilbert 	if (num > sdebug_store_sectors) {
2543c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2544c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2545c2248fc9SDouglas Gilbert 		return check_condition_result;
2546c2248fc9SDouglas Gilbert 	}
254719789100SFUJITA Tomonori 
2548773642d9SDouglas Gilbert 	if ((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
254932f7ef73SDouglas Gilbert 	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2550c65b1445SDouglas Gilbert 	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2551c65b1445SDouglas Gilbert 		/* claim unrecoverable read error */
2552c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
2553c65b1445SDouglas Gilbert 		/* set info field and valid bit for fixed descriptor */
2554c2248fc9SDouglas Gilbert 		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2555c2248fc9SDouglas Gilbert 			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
255632f7ef73SDouglas Gilbert 			ret = (lba < OPT_MEDIUM_ERR_ADDR)
255732f7ef73SDouglas Gilbert 			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
2558c2248fc9SDouglas Gilbert 			put_unaligned_be32(ret, scp->sense_buffer + 3);
2559c65b1445SDouglas Gilbert 		}
2560c2248fc9SDouglas Gilbert 		scsi_set_resid(scp, scsi_bufflen(scp));
25611da177e4SLinus Torvalds 		return check_condition_result;
25621da177e4SLinus Torvalds 	}
2563c6a44287SMartin K. Petersen 
25646c78cc06SAkinobu Mita 	read_lock_irqsave(&atomic_rw, iflags);
25656c78cc06SAkinobu Mita 
2566c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2567773642d9SDouglas Gilbert 	if (sdebug_dix && scsi_prot_sg_count(scp)) {
2568c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
2569c6a44287SMartin K. Petersen 
2570c6a44287SMartin K. Petersen 		if (prot_ret) {
25716c78cc06SAkinobu Mita 			read_unlock_irqrestore(&atomic_rw, iflags);
2572c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
2573c6a44287SMartin K. Petersen 			return illegal_condition_result;
2574c6a44287SMartin K. Petersen 		}
2575c6a44287SMartin K. Petersen 	}
2576c6a44287SMartin K. Petersen 
2577c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, false);
25781da177e4SLinus Torvalds 	read_unlock_irqrestore(&atomic_rw, iflags);
2579a4517511SAkinobu Mita 	if (ret == -1)
2580a4517511SAkinobu Mita 		return DID_ERROR << 16;
2581a4517511SAkinobu Mita 
2582c2248fc9SDouglas Gilbert 	scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
2583a4517511SAkinobu Mita 
2584c2248fc9SDouglas Gilbert 	if (sdebug_any_injecting_opt) {
2585c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2586c2248fc9SDouglas Gilbert 
2587c2248fc9SDouglas Gilbert 		if (ep->inj_recovered) {
2588c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2589c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2590c2248fc9SDouglas Gilbert 			return check_condition_result;
2591c2248fc9SDouglas Gilbert 		} else if (ep->inj_transport) {
2592c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND,
2593c2248fc9SDouglas Gilbert 					TRANSPORT_PROBLEM, ACK_NAK_TO);
2594c2248fc9SDouglas Gilbert 			return check_condition_result;
2595c2248fc9SDouglas Gilbert 		} else if (ep->inj_dif) {
2596c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2597c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2598c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2599c2248fc9SDouglas Gilbert 		} else if (ep->inj_dix) {
2600c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2601c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2602c2248fc9SDouglas Gilbert 		}
2603c2248fc9SDouglas Gilbert 	}
2604a4517511SAkinobu Mita 	return 0;
26051da177e4SLinus Torvalds }
26061da177e4SLinus Torvalds 
260758a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len)
2608c6a44287SMartin K. Petersen {
2609cbf67842SDouglas Gilbert 	int i, j, n;
2610c6a44287SMartin K. Petersen 
2611cbf67842SDouglas Gilbert 	pr_err(">>> Sector Dump <<<\n");
2612c6a44287SMartin K. Petersen 	for (i = 0 ; i < len ; i += 16) {
2613cbf67842SDouglas Gilbert 		char b[128];
2614c6a44287SMartin K. Petersen 
2615cbf67842SDouglas Gilbert 		for (j = 0, n = 0; j < 16; j++) {
2616c6a44287SMartin K. Petersen 			unsigned char c = buf[i+j];
2617c6a44287SMartin K. Petersen 
2618cbf67842SDouglas Gilbert 			if (c >= 0x20 && c < 0x7e)
2619cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2620cbf67842SDouglas Gilbert 					       " %c ", buf[i+j]);
2621cbf67842SDouglas Gilbert 			else
2622cbf67842SDouglas Gilbert 				n += scnprintf(b + n, sizeof(b) - n,
2623cbf67842SDouglas Gilbert 					       "%02x ", buf[i+j]);
2624cbf67842SDouglas Gilbert 		}
2625cbf67842SDouglas Gilbert 		pr_err("%04d: %s\n", i, b);
2626c6a44287SMartin K. Petersen 	}
2627c6a44287SMartin K. Petersen }
2628c6a44287SMartin K. Petersen 
2629c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
2630395cef03SMartin K. Petersen 			     unsigned int sectors, u32 ei_lba)
2631c6a44287SMartin K. Petersen {
2632be4e11beSAkinobu Mita 	int ret;
2633c6a44287SMartin K. Petersen 	struct sd_dif_tuple *sdt;
2634be4e11beSAkinobu Mita 	void *daddr;
263565f72f2aSAkinobu Mita 	sector_t sector = start_sec;
2636c6a44287SMartin K. Petersen 	int ppage_offset;
2637be4e11beSAkinobu Mita 	int dpage_offset;
2638be4e11beSAkinobu Mita 	struct sg_mapping_iter diter;
2639be4e11beSAkinobu Mita 	struct sg_mapping_iter piter;
2640c6a44287SMartin K. Petersen 
2641c6a44287SMartin K. Petersen 	BUG_ON(scsi_sg_count(SCpnt) == 0);
2642c6a44287SMartin K. Petersen 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2643c6a44287SMartin K. Petersen 
2644be4e11beSAkinobu Mita 	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2645be4e11beSAkinobu Mita 			scsi_prot_sg_count(SCpnt),
2646be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2647be4e11beSAkinobu Mita 	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2648be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2649c6a44287SMartin K. Petersen 
2650be4e11beSAkinobu Mita 	/* For each protection page */
2651be4e11beSAkinobu Mita 	while (sg_miter_next(&piter)) {
2652be4e11beSAkinobu Mita 		dpage_offset = 0;
2653be4e11beSAkinobu Mita 		if (WARN_ON(!sg_miter_next(&diter))) {
2654be4e11beSAkinobu Mita 			ret = 0x01;
2655be4e11beSAkinobu Mita 			goto out;
2656c6a44287SMartin K. Petersen 		}
2657c6a44287SMartin K. Petersen 
2658be4e11beSAkinobu Mita 		for (ppage_offset = 0; ppage_offset < piter.length;
2659be4e11beSAkinobu Mita 		     ppage_offset += sizeof(struct sd_dif_tuple)) {
2660be4e11beSAkinobu Mita 			/* If we're at the end of the current
2661be4e11beSAkinobu Mita 			 * data page advance to the next one
2662be4e11beSAkinobu Mita 			 */
2663be4e11beSAkinobu Mita 			if (dpage_offset >= diter.length) {
2664be4e11beSAkinobu Mita 				if (WARN_ON(!sg_miter_next(&diter))) {
2665be4e11beSAkinobu Mita 					ret = 0x01;
2666be4e11beSAkinobu Mita 					goto out;
2667be4e11beSAkinobu Mita 				}
2668be4e11beSAkinobu Mita 				dpage_offset = 0;
2669be4e11beSAkinobu Mita 			}
2670c6a44287SMartin K. Petersen 
2671be4e11beSAkinobu Mita 			sdt = piter.addr + ppage_offset;
2672be4e11beSAkinobu Mita 			daddr = diter.addr + dpage_offset;
2673be4e11beSAkinobu Mita 
2674be4e11beSAkinobu Mita 			ret = dif_verify(sdt, daddr, sector, ei_lba);
2675beb40ea4SAkinobu Mita 			if (ret) {
2676773642d9SDouglas Gilbert 				dump_sector(daddr, sdebug_sector_size);
2677395cef03SMartin K. Petersen 				goto out;
2678395cef03SMartin K. Petersen 			}
2679395cef03SMartin K. Petersen 
2680c6a44287SMartin K. Petersen 			sector++;
2681395cef03SMartin K. Petersen 			ei_lba++;
2682773642d9SDouglas Gilbert 			dpage_offset += sdebug_sector_size;
2683c6a44287SMartin K. Petersen 		}
2684be4e11beSAkinobu Mita 		diter.consumed = dpage_offset;
2685be4e11beSAkinobu Mita 		sg_miter_stop(&diter);
2686c6a44287SMartin K. Petersen 	}
2687be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2688c6a44287SMartin K. Petersen 
268965f72f2aSAkinobu Mita 	dif_copy_prot(SCpnt, start_sec, sectors, false);
2690c6a44287SMartin K. Petersen 	dix_writes++;
2691c6a44287SMartin K. Petersen 
2692c6a44287SMartin K. Petersen 	return 0;
2693c6a44287SMartin K. Petersen 
2694c6a44287SMartin K. Petersen out:
2695c6a44287SMartin K. Petersen 	dif_errors++;
2696be4e11beSAkinobu Mita 	sg_miter_stop(&diter);
2697be4e11beSAkinobu Mita 	sg_miter_stop(&piter);
2698c6a44287SMartin K. Petersen 	return ret;
2699c6a44287SMartin K. Petersen }
2700c6a44287SMartin K. Petersen 
2701b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba)
2702b90ebc3dSAkinobu Mita {
2703773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2704773642d9SDouglas Gilbert 		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2705773642d9SDouglas Gilbert 	sector_div(lba, sdebug_unmap_granularity);
2706b90ebc3dSAkinobu Mita 	return lba;
2707b90ebc3dSAkinobu Mita }
2708b90ebc3dSAkinobu Mita 
2709b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index)
2710b90ebc3dSAkinobu Mita {
2711773642d9SDouglas Gilbert 	sector_t lba = index * sdebug_unmap_granularity;
2712a027b5b9SAkinobu Mita 
2713773642d9SDouglas Gilbert 	if (sdebug_unmap_alignment)
2714773642d9SDouglas Gilbert 		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
2715a027b5b9SAkinobu Mita 	return lba;
2716a027b5b9SAkinobu Mita }
2717a027b5b9SAkinobu Mita 
271844d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num)
271944d92694SMartin K. Petersen {
2720b90ebc3dSAkinobu Mita 	sector_t end;
2721b90ebc3dSAkinobu Mita 	unsigned int mapped;
2722b90ebc3dSAkinobu Mita 	unsigned long index;
2723b90ebc3dSAkinobu Mita 	unsigned long next;
272444d92694SMartin K. Petersen 
2725b90ebc3dSAkinobu Mita 	index = lba_to_map_index(lba);
2726b90ebc3dSAkinobu Mita 	mapped = test_bit(index, map_storep);
272744d92694SMartin K. Petersen 
272844d92694SMartin K. Petersen 	if (mapped)
2729b90ebc3dSAkinobu Mita 		next = find_next_zero_bit(map_storep, map_size, index);
273044d92694SMartin K. Petersen 	else
2731b90ebc3dSAkinobu Mita 		next = find_next_bit(map_storep, map_size, index);
273244d92694SMartin K. Petersen 
2733b90ebc3dSAkinobu Mita 	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
273444d92694SMartin K. Petersen 	*num = end - lba;
273544d92694SMartin K. Petersen 	return mapped;
273644d92694SMartin K. Petersen }
273744d92694SMartin K. Petersen 
273844d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len)
273944d92694SMartin K. Petersen {
274044d92694SMartin K. Petersen 	sector_t end = lba + len;
274144d92694SMartin K. Petersen 
274244d92694SMartin K. Petersen 	while (lba < end) {
2743b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
274444d92694SMartin K. Petersen 
2745b90ebc3dSAkinobu Mita 		if (index < map_size)
2746b90ebc3dSAkinobu Mita 			set_bit(index, map_storep);
274744d92694SMartin K. Petersen 
2748b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
274944d92694SMartin K. Petersen 	}
275044d92694SMartin K. Petersen }
275144d92694SMartin K. Petersen 
275244d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len)
275344d92694SMartin K. Petersen {
275444d92694SMartin K. Petersen 	sector_t end = lba + len;
275544d92694SMartin K. Petersen 
275644d92694SMartin K. Petersen 	while (lba < end) {
2757b90ebc3dSAkinobu Mita 		unsigned long index = lba_to_map_index(lba);
275844d92694SMartin K. Petersen 
2759b90ebc3dSAkinobu Mita 		if (lba == map_index_to_lba(index) &&
2760773642d9SDouglas Gilbert 		    lba + sdebug_unmap_granularity <= end &&
2761b90ebc3dSAkinobu Mita 		    index < map_size) {
2762b90ebc3dSAkinobu Mita 			clear_bit(index, map_storep);
2763773642d9SDouglas Gilbert 			if (sdebug_lbprz) {
2764be1dd78dSEric Sandeen 				memset(fake_storep +
2765773642d9SDouglas Gilbert 				       lba * sdebug_sector_size, 0,
2766773642d9SDouglas Gilbert 				       sdebug_sector_size *
2767773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2768be1dd78dSEric Sandeen 			}
2769e9926b43SAkinobu Mita 			if (dif_storep) {
2770e9926b43SAkinobu Mita 				memset(dif_storep + lba, 0xff,
2771e9926b43SAkinobu Mita 				       sizeof(*dif_storep) *
2772773642d9SDouglas Gilbert 				       sdebug_unmap_granularity);
2773e9926b43SAkinobu Mita 			}
2774b90ebc3dSAkinobu Mita 		}
2775b90ebc3dSAkinobu Mita 		lba = map_index_to_lba(index + 1);
277644d92694SMartin K. Petersen 	}
277744d92694SMartin K. Petersen }
277844d92694SMartin K. Petersen 
2779c2248fc9SDouglas Gilbert static int
2780c2248fc9SDouglas Gilbert resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
27811da177e4SLinus Torvalds {
2782c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2783c2248fc9SDouglas Gilbert 	u64 lba;
2784c2248fc9SDouglas Gilbert 	u32 num;
2785c2248fc9SDouglas Gilbert 	u32 ei_lba;
27861da177e4SLinus Torvalds 	unsigned long iflags;
278719789100SFUJITA Tomonori 	int ret;
2788c2248fc9SDouglas Gilbert 	bool check_prot;
27891da177e4SLinus Torvalds 
2790c2248fc9SDouglas Gilbert 	switch (cmd[0]) {
2791c2248fc9SDouglas Gilbert 	case WRITE_16:
2792c2248fc9SDouglas Gilbert 		ei_lba = 0;
2793c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 2);
2794c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 10);
2795c2248fc9SDouglas Gilbert 		check_prot = true;
2796c2248fc9SDouglas Gilbert 		break;
2797c2248fc9SDouglas Gilbert 	case WRITE_10:
2798c2248fc9SDouglas Gilbert 		ei_lba = 0;
2799c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2800c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2801c2248fc9SDouglas Gilbert 		check_prot = true;
2802c2248fc9SDouglas Gilbert 		break;
2803c2248fc9SDouglas Gilbert 	case WRITE_6:
2804c2248fc9SDouglas Gilbert 		ei_lba = 0;
2805c2248fc9SDouglas Gilbert 		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2806c2248fc9SDouglas Gilbert 		      (u32)(cmd[1] & 0x1f) << 16;
2807c2248fc9SDouglas Gilbert 		num = (0 == cmd[4]) ? 256 : cmd[4];
2808c2248fc9SDouglas Gilbert 		check_prot = true;
2809c2248fc9SDouglas Gilbert 		break;
2810c2248fc9SDouglas Gilbert 	case WRITE_12:
2811c2248fc9SDouglas Gilbert 		ei_lba = 0;
2812c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2813c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 6);
2814c2248fc9SDouglas Gilbert 		check_prot = true;
2815c2248fc9SDouglas Gilbert 		break;
2816c2248fc9SDouglas Gilbert 	case 0x53:	/* XDWRITEREAD(10) */
2817c2248fc9SDouglas Gilbert 		ei_lba = 0;
2818c2248fc9SDouglas Gilbert 		lba = get_unaligned_be32(cmd + 2);
2819c2248fc9SDouglas Gilbert 		num = get_unaligned_be16(cmd + 7);
2820c2248fc9SDouglas Gilbert 		check_prot = false;
2821c2248fc9SDouglas Gilbert 		break;
2822c2248fc9SDouglas Gilbert 	default:	/* assume WRITE(32) */
2823c2248fc9SDouglas Gilbert 		lba = get_unaligned_be64(cmd + 12);
2824c2248fc9SDouglas Gilbert 		ei_lba = get_unaligned_be32(cmd + 20);
2825c2248fc9SDouglas Gilbert 		num = get_unaligned_be32(cmd + 28);
2826c2248fc9SDouglas Gilbert 		check_prot = false;
2827c2248fc9SDouglas Gilbert 		break;
2828c2248fc9SDouglas Gilbert 	}
2829c2248fc9SDouglas Gilbert 	if (check_prot) {
2830773642d9SDouglas Gilbert 		if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
2831c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0)) {
2832c2248fc9SDouglas Gilbert 			mk_sense_invalid_opcode(scp);
2833c2248fc9SDouglas Gilbert 			return check_condition_result;
2834c2248fc9SDouglas Gilbert 		}
2835773642d9SDouglas Gilbert 		if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2836773642d9SDouglas Gilbert 		     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
2837c2248fc9SDouglas Gilbert 		    (cmd[1] & 0xe0) == 0)
2838c2248fc9SDouglas Gilbert 			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2839c2248fc9SDouglas Gilbert 				    "to DIF device\n");
2840c2248fc9SDouglas Gilbert 	}
2841c2248fc9SDouglas Gilbert 
2842c2248fc9SDouglas Gilbert 	/* inline check_device_access_params() */
2843c2248fc9SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
2844c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2845c2248fc9SDouglas Gilbert 		return check_condition_result;
2846c2248fc9SDouglas Gilbert 	}
2847c2248fc9SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
2848c2248fc9SDouglas Gilbert 	if (num > sdebug_store_sectors) {
2849c2248fc9SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
2850c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2851c2248fc9SDouglas Gilbert 		return check_condition_result;
2852c2248fc9SDouglas Gilbert 	}
28531da177e4SLinus Torvalds 
28546c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
28556c78cc06SAkinobu Mita 
2856c6a44287SMartin K. Petersen 	/* DIX + T10 DIF */
2857773642d9SDouglas Gilbert 	if (sdebug_dix && scsi_prot_sg_count(scp)) {
2858c2248fc9SDouglas Gilbert 		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
2859c6a44287SMartin K. Petersen 
2860c6a44287SMartin K. Petersen 		if (prot_ret) {
28616c78cc06SAkinobu Mita 			write_unlock_irqrestore(&atomic_rw, iflags);
2862c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
2863c6a44287SMartin K. Petersen 			return illegal_condition_result;
2864c6a44287SMartin K. Petersen 		}
2865c6a44287SMartin K. Petersen 	}
2866c6a44287SMartin K. Petersen 
2867c2248fc9SDouglas Gilbert 	ret = do_device_access(scp, lba, num, true);
28689ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
286944d92694SMartin K. Petersen 		map_region(lba, num);
28701da177e4SLinus Torvalds 	write_unlock_irqrestore(&atomic_rw, iflags);
287119789100SFUJITA Tomonori 	if (-1 == ret)
2872773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2873773642d9SDouglas Gilbert 	else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
2874c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2875cbf67842SDouglas Gilbert 			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2876773642d9SDouglas Gilbert 			    my_name, num * sdebug_sector_size, ret);
287744d92694SMartin K. Petersen 
2878c2248fc9SDouglas Gilbert 	if (sdebug_any_injecting_opt) {
2879c2248fc9SDouglas Gilbert 		struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2880c2248fc9SDouglas Gilbert 
2881c2248fc9SDouglas Gilbert 		if (ep->inj_recovered) {
2882c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, RECOVERED_ERROR,
2883c2248fc9SDouglas Gilbert 					THRESHOLD_EXCEEDED, 0);
2884c2248fc9SDouglas Gilbert 			return check_condition_result;
2885c2248fc9SDouglas Gilbert 		} else if (ep->inj_dif) {
2886c2248fc9SDouglas Gilbert 			/* Logical block guard check failed */
2887c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2888c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2889c2248fc9SDouglas Gilbert 		} else if (ep->inj_dix) {
2890c2248fc9SDouglas Gilbert 			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2891c2248fc9SDouglas Gilbert 			return illegal_condition_result;
2892c2248fc9SDouglas Gilbert 		}
2893c2248fc9SDouglas Gilbert 	}
28941da177e4SLinus Torvalds 	return 0;
28951da177e4SLinus Torvalds }
28961da177e4SLinus Torvalds 
2897c2248fc9SDouglas Gilbert static int
2898c2248fc9SDouglas Gilbert resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba,
2899c2248fc9SDouglas Gilbert 		bool unmap, bool ndob)
290044d92694SMartin K. Petersen {
290144d92694SMartin K. Petersen 	unsigned long iflags;
290244d92694SMartin K. Petersen 	unsigned long long i;
290344d92694SMartin K. Petersen 	int ret;
2904773642d9SDouglas Gilbert 	u64 lba_off;
290544d92694SMartin K. Petersen 
2906c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, num);
290744d92694SMartin K. Petersen 	if (ret)
290844d92694SMartin K. Petersen 		return ret;
290944d92694SMartin K. Petersen 
291044d92694SMartin K. Petersen 	write_lock_irqsave(&atomic_rw, iflags);
291144d92694SMartin K. Petersen 
29129ed8d3dcSAkinobu Mita 	if (unmap && scsi_debug_lbp()) {
291344d92694SMartin K. Petersen 		unmap_region(lba, num);
291444d92694SMartin K. Petersen 		goto out;
291544d92694SMartin K. Petersen 	}
291644d92694SMartin K. Petersen 
2917773642d9SDouglas Gilbert 	lba_off = lba * sdebug_sector_size;
2918c2248fc9SDouglas Gilbert 	/* if ndob then zero 1 logical block, else fetch 1 logical block */
2919c2248fc9SDouglas Gilbert 	if (ndob) {
2920773642d9SDouglas Gilbert 		memset(fake_storep + lba_off, 0, sdebug_sector_size);
2921c2248fc9SDouglas Gilbert 		ret = 0;
2922c2248fc9SDouglas Gilbert 	} else
2923773642d9SDouglas Gilbert 		ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2924773642d9SDouglas Gilbert 					  sdebug_sector_size);
292544d92694SMartin K. Petersen 
292644d92694SMartin K. Petersen 	if (-1 == ret) {
292744d92694SMartin K. Petersen 		write_unlock_irqrestore(&atomic_rw, iflags);
2928773642d9SDouglas Gilbert 		return DID_ERROR << 16;
2929773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
2930c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device,
2931cbf67842SDouglas Gilbert 			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2932cbf67842SDouglas Gilbert 			    my_name, "write same",
2933773642d9SDouglas Gilbert 			    num * sdebug_sector_size, ret);
293444d92694SMartin K. Petersen 
293544d92694SMartin K. Petersen 	/* Copy first sector to remaining blocks */
293644d92694SMartin K. Petersen 	for (i = 1 ; i < num ; i++)
2937773642d9SDouglas Gilbert 		memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2938773642d9SDouglas Gilbert 		       fake_storep + lba_off,
2939773642d9SDouglas Gilbert 		       sdebug_sector_size);
294044d92694SMartin K. Petersen 
29419ed8d3dcSAkinobu Mita 	if (scsi_debug_lbp())
294244d92694SMartin K. Petersen 		map_region(lba, num);
294344d92694SMartin K. Petersen out:
294444d92694SMartin K. Petersen 	write_unlock_irqrestore(&atomic_rw, iflags);
294544d92694SMartin K. Petersen 
294644d92694SMartin K. Petersen 	return 0;
294744d92694SMartin K. Petersen }
294844d92694SMartin K. Petersen 
2949c2248fc9SDouglas Gilbert static int
2950c2248fc9SDouglas Gilbert resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2951c2248fc9SDouglas Gilbert {
2952c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2953c2248fc9SDouglas Gilbert 	u32 lba;
2954c2248fc9SDouglas Gilbert 	u16 num;
2955c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
2956c2248fc9SDouglas Gilbert 	bool unmap = false;
2957c2248fc9SDouglas Gilbert 
2958c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {
2959773642d9SDouglas Gilbert 		if (sdebug_lbpws10 == 0) {
2960c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2961c2248fc9SDouglas Gilbert 			return check_condition_result;
2962c2248fc9SDouglas Gilbert 		} else
2963c2248fc9SDouglas Gilbert 			unmap = true;
2964c2248fc9SDouglas Gilbert 	}
2965c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
2966c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
2967773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
2968c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2969c2248fc9SDouglas Gilbert 		return check_condition_result;
2970c2248fc9SDouglas Gilbert 	}
2971c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2972c2248fc9SDouglas Gilbert }
2973c2248fc9SDouglas Gilbert 
2974c2248fc9SDouglas Gilbert static int
2975c2248fc9SDouglas Gilbert resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2976c2248fc9SDouglas Gilbert {
2977c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
2978c2248fc9SDouglas Gilbert 	u64 lba;
2979c2248fc9SDouglas Gilbert 	u32 num;
2980c2248fc9SDouglas Gilbert 	u32 ei_lba = 0;
2981c2248fc9SDouglas Gilbert 	bool unmap = false;
2982c2248fc9SDouglas Gilbert 	bool ndob = false;
2983c2248fc9SDouglas Gilbert 
2984c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x8) {	/* UNMAP */
2985773642d9SDouglas Gilbert 		if (sdebug_lbpws == 0) {
2986c2248fc9SDouglas Gilbert 			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2987c2248fc9SDouglas Gilbert 			return check_condition_result;
2988c2248fc9SDouglas Gilbert 		} else
2989c2248fc9SDouglas Gilbert 			unmap = true;
2990c2248fc9SDouglas Gilbert 	}
2991c2248fc9SDouglas Gilbert 	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
2992c2248fc9SDouglas Gilbert 		ndob = true;
2993c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
2994c2248fc9SDouglas Gilbert 	num = get_unaligned_be32(cmd + 10);
2995773642d9SDouglas Gilbert 	if (num > sdebug_write_same_length) {
2996c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
2997c2248fc9SDouglas Gilbert 		return check_condition_result;
2998c2248fc9SDouglas Gilbert 	}
2999c2248fc9SDouglas Gilbert 	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3000c2248fc9SDouglas Gilbert }
3001c2248fc9SDouglas Gilbert 
3002acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action
3003acafd0b9SEwan D. Milne  * field. For the Report supported operation codes command, SPC-4 suggests
3004acafd0b9SEwan D. Milne  * each mode of this command should be reported separately; for future. */
3005acafd0b9SEwan D. Milne static int
3006acafd0b9SEwan D. Milne resp_write_buffer(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3007acafd0b9SEwan D. Milne {
3008acafd0b9SEwan D. Milne 	u8 *cmd = scp->cmnd;
3009acafd0b9SEwan D. Milne 	struct scsi_device *sdp = scp->device;
3010acafd0b9SEwan D. Milne 	struct sdebug_dev_info *dp;
3011acafd0b9SEwan D. Milne 	u8 mode;
3012acafd0b9SEwan D. Milne 
3013acafd0b9SEwan D. Milne 	mode = cmd[1] & 0x1f;
3014acafd0b9SEwan D. Milne 	switch (mode) {
3015acafd0b9SEwan D. Milne 	case 0x4:	/* download microcode (MC) and activate (ACT) */
3016acafd0b9SEwan D. Milne 		/* set UAs on this device only */
3017acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3018acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3019acafd0b9SEwan D. Milne 		break;
3020acafd0b9SEwan D. Milne 	case 0x5:	/* download MC, save and ACT */
3021acafd0b9SEwan D. Milne 		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3022acafd0b9SEwan D. Milne 		break;
3023acafd0b9SEwan D. Milne 	case 0x6:	/* download MC with offsets and ACT */
3024acafd0b9SEwan D. Milne 		/* set UAs on most devices (LUs) in this target */
3025acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3026acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3027acafd0b9SEwan D. Milne 				    dev_list)
3028acafd0b9SEwan D. Milne 			if (dp->target == sdp->id) {
3029acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3030acafd0b9SEwan D. Milne 				if (devip != dp)
3031acafd0b9SEwan D. Milne 					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3032acafd0b9SEwan D. Milne 						dp->uas_bm);
3033acafd0b9SEwan D. Milne 			}
3034acafd0b9SEwan D. Milne 		break;
3035acafd0b9SEwan D. Milne 	case 0x7:	/* download MC with offsets, save, and ACT */
3036acafd0b9SEwan D. Milne 		/* set UA on all devices (LUs) in this target */
3037acafd0b9SEwan D. Milne 		list_for_each_entry(dp,
3038acafd0b9SEwan D. Milne 				    &devip->sdbg_host->dev_info_list,
3039acafd0b9SEwan D. Milne 				    dev_list)
3040acafd0b9SEwan D. Milne 			if (dp->target == sdp->id)
3041acafd0b9SEwan D. Milne 				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3042acafd0b9SEwan D. Milne 					dp->uas_bm);
3043acafd0b9SEwan D. Milne 		break;
3044acafd0b9SEwan D. Milne 	default:
3045acafd0b9SEwan D. Milne 		/* do nothing for this command for other mode values */
3046acafd0b9SEwan D. Milne 		break;
3047acafd0b9SEwan D. Milne 	}
3048acafd0b9SEwan D. Milne 	return 0;
3049acafd0b9SEwan D. Milne }
3050acafd0b9SEwan D. Milne 
305138d5c833SDouglas Gilbert static int
305238d5c833SDouglas Gilbert resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
305338d5c833SDouglas Gilbert {
305438d5c833SDouglas Gilbert 	u8 *cmd = scp->cmnd;
305538d5c833SDouglas Gilbert 	u8 *arr;
305638d5c833SDouglas Gilbert 	u8 *fake_storep_hold;
305738d5c833SDouglas Gilbert 	u64 lba;
305838d5c833SDouglas Gilbert 	u32 dnum;
3059773642d9SDouglas Gilbert 	u32 lb_size = sdebug_sector_size;
306038d5c833SDouglas Gilbert 	u8 num;
306138d5c833SDouglas Gilbert 	unsigned long iflags;
306238d5c833SDouglas Gilbert 	int ret;
3063d467d31fSDouglas Gilbert 	int retval = 0;
306438d5c833SDouglas Gilbert 
3065d467d31fSDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
306638d5c833SDouglas Gilbert 	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
306738d5c833SDouglas Gilbert 	if (0 == num)
306838d5c833SDouglas Gilbert 		return 0;	/* degenerate case, not an error */
3069773642d9SDouglas Gilbert 	if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
307038d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0)) {
307138d5c833SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
307238d5c833SDouglas Gilbert 		return check_condition_result;
307338d5c833SDouglas Gilbert 	}
3074773642d9SDouglas Gilbert 	if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3075773642d9SDouglas Gilbert 	     sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
307638d5c833SDouglas Gilbert 	    (cmd[1] & 0xe0) == 0)
307738d5c833SDouglas Gilbert 		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
307838d5c833SDouglas Gilbert 			    "to DIF device\n");
307938d5c833SDouglas Gilbert 
308038d5c833SDouglas Gilbert 	/* inline check_device_access_params() */
308138d5c833SDouglas Gilbert 	if (lba + num > sdebug_capacity) {
308238d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
308338d5c833SDouglas Gilbert 		return check_condition_result;
308438d5c833SDouglas Gilbert 	}
308538d5c833SDouglas Gilbert 	/* transfer length excessive (tie in to block limits VPD page) */
308638d5c833SDouglas Gilbert 	if (num > sdebug_store_sectors) {
308738d5c833SDouglas Gilbert 		/* needs work to find which cdb byte 'num' comes from */
308838d5c833SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
308938d5c833SDouglas Gilbert 		return check_condition_result;
309038d5c833SDouglas Gilbert 	}
3091d467d31fSDouglas Gilbert 	dnum = 2 * num;
3092d467d31fSDouglas Gilbert 	arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3093d467d31fSDouglas Gilbert 	if (NULL == arr) {
3094d467d31fSDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3095d467d31fSDouglas Gilbert 				INSUFF_RES_ASCQ);
3096d467d31fSDouglas Gilbert 		return check_condition_result;
3097d467d31fSDouglas Gilbert 	}
309838d5c833SDouglas Gilbert 
309938d5c833SDouglas Gilbert 	write_lock_irqsave(&atomic_rw, iflags);
310038d5c833SDouglas Gilbert 
310138d5c833SDouglas Gilbert 	/* trick do_device_access() to fetch both compare and write buffers
310238d5c833SDouglas Gilbert 	 * from data-in into arr. Safe (atomic) since write_lock held. */
310338d5c833SDouglas Gilbert 	fake_storep_hold = fake_storep;
310438d5c833SDouglas Gilbert 	fake_storep = arr;
310538d5c833SDouglas Gilbert 	ret = do_device_access(scp, 0, dnum, true);
310638d5c833SDouglas Gilbert 	fake_storep = fake_storep_hold;
310738d5c833SDouglas Gilbert 	if (ret == -1) {
3108d467d31fSDouglas Gilbert 		retval = DID_ERROR << 16;
3109d467d31fSDouglas Gilbert 		goto cleanup;
3110773642d9SDouglas Gilbert 	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
311138d5c833SDouglas Gilbert 		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
311238d5c833SDouglas Gilbert 			    "indicated=%u, IO sent=%d bytes\n", my_name,
311338d5c833SDouglas Gilbert 			    dnum * lb_size, ret);
311438d5c833SDouglas Gilbert 	if (!comp_write_worker(lba, num, arr)) {
311538d5c833SDouglas Gilbert 		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
3116d467d31fSDouglas Gilbert 		retval = check_condition_result;
3117d467d31fSDouglas Gilbert 		goto cleanup;
311838d5c833SDouglas Gilbert 	}
311938d5c833SDouglas Gilbert 	if (scsi_debug_lbp())
312038d5c833SDouglas Gilbert 		map_region(lba, num);
3121d467d31fSDouglas Gilbert cleanup:
312238d5c833SDouglas Gilbert 	write_unlock_irqrestore(&atomic_rw, iflags);
3123d467d31fSDouglas Gilbert 	kfree(arr);
3124d467d31fSDouglas Gilbert 	return retval;
312538d5c833SDouglas Gilbert }
312638d5c833SDouglas Gilbert 
312744d92694SMartin K. Petersen struct unmap_block_desc {
312844d92694SMartin K. Petersen 	__be64	lba;
312944d92694SMartin K. Petersen 	__be32	blocks;
313044d92694SMartin K. Petersen 	__be32	__reserved;
313144d92694SMartin K. Petersen };
313244d92694SMartin K. Petersen 
3133c2248fc9SDouglas Gilbert static int
3134c2248fc9SDouglas Gilbert resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
313544d92694SMartin K. Petersen {
313644d92694SMartin K. Petersen 	unsigned char *buf;
313744d92694SMartin K. Petersen 	struct unmap_block_desc *desc;
313844d92694SMartin K. Petersen 	unsigned int i, payload_len, descriptors;
313944d92694SMartin K. Petersen 	int ret;
31406c78cc06SAkinobu Mita 	unsigned long iflags;
314144d92694SMartin K. Petersen 
314244d92694SMartin K. Petersen 
3143c2248fc9SDouglas Gilbert 	if (!scsi_debug_lbp())
3144c2248fc9SDouglas Gilbert 		return 0;	/* fib and say its done */
3145c2248fc9SDouglas Gilbert 	payload_len = get_unaligned_be16(scp->cmnd + 7);
3146c2248fc9SDouglas Gilbert 	BUG_ON(scsi_bufflen(scp) != payload_len);
314744d92694SMartin K. Petersen 
314844d92694SMartin K. Petersen 	descriptors = (payload_len - 8) / 16;
3149773642d9SDouglas Gilbert 	if (descriptors > sdebug_unmap_max_desc) {
3150c2248fc9SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
315144d92694SMartin K. Petersen 		return check_condition_result;
3152c2248fc9SDouglas Gilbert 	}
315344d92694SMartin K. Petersen 
3154c2248fc9SDouglas Gilbert 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
3155c2248fc9SDouglas Gilbert 	if (!buf) {
3156c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3157c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3158c2248fc9SDouglas Gilbert 		return check_condition_result;
3159c2248fc9SDouglas Gilbert 	}
3160c2248fc9SDouglas Gilbert 
3161c2248fc9SDouglas Gilbert 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
316244d92694SMartin K. Petersen 
316344d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
316444d92694SMartin K. Petersen 	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
316544d92694SMartin K. Petersen 
316644d92694SMartin K. Petersen 	desc = (void *)&buf[8];
316744d92694SMartin K. Petersen 
31686c78cc06SAkinobu Mita 	write_lock_irqsave(&atomic_rw, iflags);
31696c78cc06SAkinobu Mita 
317044d92694SMartin K. Petersen 	for (i = 0 ; i < descriptors ; i++) {
317144d92694SMartin K. Petersen 		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
317244d92694SMartin K. Petersen 		unsigned int num = get_unaligned_be32(&desc[i].blocks);
317344d92694SMartin K. Petersen 
3174c2248fc9SDouglas Gilbert 		ret = check_device_access_params(scp, lba, num);
317544d92694SMartin K. Petersen 		if (ret)
317644d92694SMartin K. Petersen 			goto out;
317744d92694SMartin K. Petersen 
317844d92694SMartin K. Petersen 		unmap_region(lba, num);
317944d92694SMartin K. Petersen 	}
318044d92694SMartin K. Petersen 
318144d92694SMartin K. Petersen 	ret = 0;
318244d92694SMartin K. Petersen 
318344d92694SMartin K. Petersen out:
31846c78cc06SAkinobu Mita 	write_unlock_irqrestore(&atomic_rw, iflags);
318544d92694SMartin K. Petersen 	kfree(buf);
318644d92694SMartin K. Petersen 
318744d92694SMartin K. Petersen 	return ret;
318844d92694SMartin K. Petersen }
318944d92694SMartin K. Petersen 
319044d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32
319144d92694SMartin K. Petersen 
3192c2248fc9SDouglas Gilbert static int
3193c2248fc9SDouglas Gilbert resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
319444d92694SMartin K. Petersen {
3195c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3196c2248fc9SDouglas Gilbert 	u64 lba;
3197c2248fc9SDouglas Gilbert 	u32 alloc_len, mapped, num;
3198c2248fc9SDouglas Gilbert 	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
319944d92694SMartin K. Petersen 	int ret;
320044d92694SMartin K. Petersen 
3201c2248fc9SDouglas Gilbert 	lba = get_unaligned_be64(cmd + 2);
3202c2248fc9SDouglas Gilbert 	alloc_len = get_unaligned_be32(cmd + 10);
320344d92694SMartin K. Petersen 
320444d92694SMartin K. Petersen 	if (alloc_len < 24)
320544d92694SMartin K. Petersen 		return 0;
320644d92694SMartin K. Petersen 
3207c2248fc9SDouglas Gilbert 	ret = check_device_access_params(scp, lba, 1);
320844d92694SMartin K. Petersen 	if (ret)
320944d92694SMartin K. Petersen 		return ret;
321044d92694SMartin K. Petersen 
3211c2248fc9SDouglas Gilbert 	if (scsi_debug_lbp())
321244d92694SMartin K. Petersen 		mapped = map_state(lba, &num);
3213c2248fc9SDouglas Gilbert 	else {
3214c2248fc9SDouglas Gilbert 		mapped = 1;
3215c2248fc9SDouglas Gilbert 		/* following just in case virtual_gb changed */
3216c2248fc9SDouglas Gilbert 		sdebug_capacity = get_sdebug_capacity();
3217c2248fc9SDouglas Gilbert 		if (sdebug_capacity - lba <= 0xffffffff)
3218c2248fc9SDouglas Gilbert 			num = sdebug_capacity - lba;
3219c2248fc9SDouglas Gilbert 		else
3220c2248fc9SDouglas Gilbert 			num = 0xffffffff;
3221c2248fc9SDouglas Gilbert 	}
322244d92694SMartin K. Petersen 
322344d92694SMartin K. Petersen 	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
3224c2248fc9SDouglas Gilbert 	put_unaligned_be32(20, arr);		/* Parameter Data Length */
3225c2248fc9SDouglas Gilbert 	put_unaligned_be64(lba, arr + 8);	/* LBA */
3226c2248fc9SDouglas Gilbert 	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
3227c2248fc9SDouglas Gilbert 	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
322844d92694SMartin K. Petersen 
3229c2248fc9SDouglas Gilbert 	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
323044d92694SMartin K. Petersen }
323144d92694SMartin K. Petersen 
3232c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256
32331da177e4SLinus Torvalds 
32341da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp,
32351da177e4SLinus Torvalds 			    struct sdebug_dev_info * devip)
32361da177e4SLinus Torvalds {
32371da177e4SLinus Torvalds 	unsigned int alloc_len;
323822017ed2SDouglas Gilbert 	int lun_cnt, i, upper, num, n, want_wlun, shortish;
323922017ed2SDouglas Gilbert 	u64 lun;
324001123ef4SDouglas Gilbert 	unsigned char *cmd = scp->cmnd;
32411da177e4SLinus Torvalds 	int select_report = (int)cmd[2];
32421da177e4SLinus Torvalds 	struct scsi_lun *one_lun;
32431da177e4SLinus Torvalds 	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
3244c65b1445SDouglas Gilbert 	unsigned char * max_addr;
32451da177e4SLinus Torvalds 
324619c8ead7SEwan D. Milne 	clear_luns_changed_on_target(devip);
32471da177e4SLinus Torvalds 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
324822017ed2SDouglas Gilbert 	shortish = (alloc_len < 4);
324922017ed2SDouglas Gilbert 	if (shortish || (select_report > 2)) {
325022017ed2SDouglas Gilbert 		mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
32511da177e4SLinus Torvalds 		return check_condition_result;
32521da177e4SLinus Torvalds 	}
32531da177e4SLinus Torvalds 	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
32541da177e4SLinus Torvalds 	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
3255773642d9SDouglas Gilbert 	lun_cnt = sdebug_max_luns;
3256c65b1445SDouglas Gilbert 	if (1 == select_report)
3257c65b1445SDouglas Gilbert 		lun_cnt = 0;
3258773642d9SDouglas Gilbert 	else if (sdebug_no_lun_0 && (lun_cnt > 0))
3259c65b1445SDouglas Gilbert 		--lun_cnt;
326022017ed2SDouglas Gilbert 	want_wlun = (select_report > 0) ? 1 : 0;
326122017ed2SDouglas Gilbert 	num = lun_cnt + want_wlun;
3262c65b1445SDouglas Gilbert 	arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3263c65b1445SDouglas Gilbert 	arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3264c65b1445SDouglas Gilbert 	n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3265c65b1445SDouglas Gilbert 			    sizeof(struct scsi_lun)), num);
3266c65b1445SDouglas Gilbert 	if (n < num) {
326722017ed2SDouglas Gilbert 		want_wlun = 0;
3268c65b1445SDouglas Gilbert 		lun_cnt = n;
3269c65b1445SDouglas Gilbert 	}
32701da177e4SLinus Torvalds 	one_lun = (struct scsi_lun *) &arr[8];
3271c65b1445SDouglas Gilbert 	max_addr = arr + SDEBUG_RLUN_ARR_SZ;
3272773642d9SDouglas Gilbert 	for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
3273c65b1445SDouglas Gilbert              ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3274c65b1445SDouglas Gilbert 	     i++, lun++) {
3275c65b1445SDouglas Gilbert 		upper = (lun >> 8) & 0x3f;
32761da177e4SLinus Torvalds 		if (upper)
32771da177e4SLinus Torvalds 			one_lun[i].scsi_lun[0] =
32781da177e4SLinus Torvalds 			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
3279c65b1445SDouglas Gilbert 		one_lun[i].scsi_lun[1] = lun & 0xff;
32801da177e4SLinus Torvalds 	}
328122017ed2SDouglas Gilbert 	if (want_wlun) {
328234d55434STomas Winkler 		one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
328334d55434STomas Winkler 		one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
3284c65b1445SDouglas Gilbert 		i++;
3285c65b1445SDouglas Gilbert 	}
3286c65b1445SDouglas Gilbert 	alloc_len = (unsigned char *)(one_lun + i) - arr;
32871da177e4SLinus Torvalds 	return fill_from_dev_buffer(scp, arr,
32881da177e4SLinus Torvalds 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
32891da177e4SLinus Torvalds }
32901da177e4SLinus Torvalds 
3291c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3292c639d14eSFUJITA Tomonori 			    unsigned int num, struct sdebug_dev_info *devip)
3293c639d14eSFUJITA Tomonori {
3294be4e11beSAkinobu Mita 	int j;
3295c639d14eSFUJITA Tomonori 	unsigned char *kaddr, *buf;
3296c639d14eSFUJITA Tomonori 	unsigned int offset;
3297c639d14eSFUJITA Tomonori 	struct scsi_data_buffer *sdb = scsi_in(scp);
3298be4e11beSAkinobu Mita 	struct sg_mapping_iter miter;
3299c639d14eSFUJITA Tomonori 
3300c639d14eSFUJITA Tomonori 	/* better not to use temporary buffer. */
3301c639d14eSFUJITA Tomonori 	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
3302c5af0db9SAkinobu Mita 	if (!buf) {
330322017ed2SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
330422017ed2SDouglas Gilbert 				INSUFF_RES_ASCQ);
3305c5af0db9SAkinobu Mita 		return check_condition_result;
3306c5af0db9SAkinobu Mita 	}
3307c639d14eSFUJITA Tomonori 
330821a61829SFUJITA Tomonori 	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
3309c639d14eSFUJITA Tomonori 
3310c639d14eSFUJITA Tomonori 	offset = 0;
3311be4e11beSAkinobu Mita 	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3312be4e11beSAkinobu Mita 			SG_MITER_ATOMIC | SG_MITER_TO_SG);
3313c639d14eSFUJITA Tomonori 
3314be4e11beSAkinobu Mita 	while (sg_miter_next(&miter)) {
3315be4e11beSAkinobu Mita 		kaddr = miter.addr;
3316be4e11beSAkinobu Mita 		for (j = 0; j < miter.length; j++)
3317be4e11beSAkinobu Mita 			*(kaddr + j) ^= *(buf + offset + j);
3318c639d14eSFUJITA Tomonori 
3319be4e11beSAkinobu Mita 		offset += miter.length;
3320c639d14eSFUJITA Tomonori 	}
3321be4e11beSAkinobu Mita 	sg_miter_stop(&miter);
3322c639d14eSFUJITA Tomonori 	kfree(buf);
3323c639d14eSFUJITA Tomonori 
3324be4e11beSAkinobu Mita 	return 0;
3325c639d14eSFUJITA Tomonori }
3326c639d14eSFUJITA Tomonori 
3327c2248fc9SDouglas Gilbert static int
3328c2248fc9SDouglas Gilbert resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3329c2248fc9SDouglas Gilbert {
3330c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
3331c2248fc9SDouglas Gilbert 	u64 lba;
3332c2248fc9SDouglas Gilbert 	u32 num;
3333c2248fc9SDouglas Gilbert 	int errsts;
3334c2248fc9SDouglas Gilbert 
3335c2248fc9SDouglas Gilbert 	if (!scsi_bidi_cmnd(scp)) {
3336c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3337c2248fc9SDouglas Gilbert 				INSUFF_RES_ASCQ);
3338c2248fc9SDouglas Gilbert 		return check_condition_result;
3339c2248fc9SDouglas Gilbert 	}
3340c2248fc9SDouglas Gilbert 	errsts = resp_read_dt0(scp, devip);
3341c2248fc9SDouglas Gilbert 	if (errsts)
3342c2248fc9SDouglas Gilbert 		return errsts;
3343c2248fc9SDouglas Gilbert 	if (!(cmd[1] & 0x4)) {		/* DISABLE_WRITE is not set */
3344c2248fc9SDouglas Gilbert 		errsts = resp_write_dt0(scp, devip);
3345c2248fc9SDouglas Gilbert 		if (errsts)
3346c2248fc9SDouglas Gilbert 			return errsts;
3347c2248fc9SDouglas Gilbert 	}
3348c2248fc9SDouglas Gilbert 	lba = get_unaligned_be32(cmd + 2);
3349c2248fc9SDouglas Gilbert 	num = get_unaligned_be16(cmd + 7);
3350c2248fc9SDouglas Gilbert 	return resp_xdwriteread(scp, lba, num, devip);
3351c2248fc9SDouglas Gilbert }
3352c2248fc9SDouglas Gilbert 
3353cbf67842SDouglas Gilbert /* When timer or tasklet goes off this function is called. */
3354cbf67842SDouglas Gilbert static void sdebug_q_cmd_complete(unsigned long indx)
33551da177e4SLinus Torvalds {
3356cbf67842SDouglas Gilbert 	int qa_indx;
3357cbf67842SDouglas Gilbert 	int retiring = 0;
33581da177e4SLinus Torvalds 	unsigned long iflags;
3359cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3360cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3361cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
33621da177e4SLinus Torvalds 
3363cbf67842SDouglas Gilbert 	atomic_inc(&sdebug_completions);
3364cbf67842SDouglas Gilbert 	qa_indx = indx;
3365cbf67842SDouglas Gilbert 	if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
3366c1287970STomas Winkler 		pr_err("wild qa_indx=%d\n", qa_indx);
33671da177e4SLinus Torvalds 		return;
33681da177e4SLinus Torvalds 	}
33691da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
3370cbf67842SDouglas Gilbert 	sqcp = &queued_arr[qa_indx];
3371cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3372cbf67842SDouglas Gilbert 	if (NULL == scp) {
33731da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3374c1287970STomas Winkler 		pr_err("scp is NULL\n");
33751da177e4SLinus Torvalds 		return;
33761da177e4SLinus Torvalds 	}
3377cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3378cbf67842SDouglas Gilbert 	if (devip)
3379cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3380cbf67842SDouglas Gilbert 	else
3381c1287970STomas Winkler 		pr_err("devip=NULL\n");
3382cbf67842SDouglas Gilbert 	if (atomic_read(&retired_max_queue) > 0)
3383cbf67842SDouglas Gilbert 		retiring = 1;
3384cbf67842SDouglas Gilbert 
3385cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3386cbf67842SDouglas Gilbert 	if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
33871da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3388c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3389cbf67842SDouglas Gilbert 		return;
33901da177e4SLinus Torvalds 	}
33911da177e4SLinus Torvalds 
3392cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3393cbf67842SDouglas Gilbert 		int k, retval;
3394cbf67842SDouglas Gilbert 
3395cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3396cbf67842SDouglas Gilbert 		if (qa_indx >= retval) {
3397cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3398c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3399cbf67842SDouglas Gilbert 			return;
3400cbf67842SDouglas Gilbert 		}
3401cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, retval);
3402773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3403cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3404cbf67842SDouglas Gilbert 		else
3405cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3406cbf67842SDouglas Gilbert 	}
3407cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3408cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3409cbf67842SDouglas Gilbert }
3410cbf67842SDouglas Gilbert 
3411cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */
3412cbf67842SDouglas Gilbert static enum hrtimer_restart
3413cbf67842SDouglas Gilbert sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3414cbf67842SDouglas Gilbert {
3415cbf67842SDouglas Gilbert 	int qa_indx;
3416cbf67842SDouglas Gilbert 	int retiring = 0;
3417cbf67842SDouglas Gilbert 	unsigned long iflags;
3418cbf67842SDouglas Gilbert 	struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer;
3419cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3420cbf67842SDouglas Gilbert 	struct scsi_cmnd *scp;
3421cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3422cbf67842SDouglas Gilbert 
3423cbf67842SDouglas Gilbert 	atomic_inc(&sdebug_completions);
3424cbf67842SDouglas Gilbert 	qa_indx = sd_hrtp->qa_indx;
3425cbf67842SDouglas Gilbert 	if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
3426c1287970STomas Winkler 		pr_err("wild qa_indx=%d\n", qa_indx);
3427cbf67842SDouglas Gilbert 		goto the_end;
3428cbf67842SDouglas Gilbert 	}
3429cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
3430cbf67842SDouglas Gilbert 	sqcp = &queued_arr[qa_indx];
3431cbf67842SDouglas Gilbert 	scp = sqcp->a_cmnd;
3432cbf67842SDouglas Gilbert 	if (NULL == scp) {
3433cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3434c1287970STomas Winkler 		pr_err("scp is NULL\n");
3435cbf67842SDouglas Gilbert 		goto the_end;
3436cbf67842SDouglas Gilbert 	}
3437cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)scp->device->hostdata;
3438cbf67842SDouglas Gilbert 	if (devip)
3439cbf67842SDouglas Gilbert 		atomic_dec(&devip->num_in_q);
3440cbf67842SDouglas Gilbert 	else
3441c1287970STomas Winkler 		pr_err("devip=NULL\n");
3442cbf67842SDouglas Gilbert 	if (atomic_read(&retired_max_queue) > 0)
3443cbf67842SDouglas Gilbert 		retiring = 1;
3444cbf67842SDouglas Gilbert 
3445cbf67842SDouglas Gilbert 	sqcp->a_cmnd = NULL;
3446cbf67842SDouglas Gilbert 	if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3447cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3448c1287970STomas Winkler 		pr_err("Unexpected completion\n");
3449cbf67842SDouglas Gilbert 		goto the_end;
3450cbf67842SDouglas Gilbert 	}
3451cbf67842SDouglas Gilbert 
3452cbf67842SDouglas Gilbert 	if (unlikely(retiring)) {	/* user has reduced max_queue */
3453cbf67842SDouglas Gilbert 		int k, retval;
3454cbf67842SDouglas Gilbert 
3455cbf67842SDouglas Gilbert 		retval = atomic_read(&retired_max_queue);
3456cbf67842SDouglas Gilbert 		if (qa_indx >= retval) {
3457cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3458c1287970STomas Winkler 			pr_err("index %d too large\n", retval);
3459cbf67842SDouglas Gilbert 			goto the_end;
3460cbf67842SDouglas Gilbert 		}
3461cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, retval);
3462773642d9SDouglas Gilbert 		if ((k < sdebug_max_queue) || (k == retval))
3463cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
3464cbf67842SDouglas Gilbert 		else
3465cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
3466cbf67842SDouglas Gilbert 	}
3467cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3468cbf67842SDouglas Gilbert 	scp->scsi_done(scp); /* callback to mid level */
3469cbf67842SDouglas Gilbert the_end:
3470cbf67842SDouglas Gilbert 	return HRTIMER_NORESTART;
3471cbf67842SDouglas Gilbert }
34721da177e4SLinus Torvalds 
34738dea0d02SFUJITA Tomonori static struct sdebug_dev_info *
34748dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
34755cb2fc06SFUJITA Tomonori {
34765cb2fc06SFUJITA Tomonori 	struct sdebug_dev_info *devip;
34775cb2fc06SFUJITA Tomonori 
34785cb2fc06SFUJITA Tomonori 	devip = kzalloc(sizeof(*devip), flags);
34795cb2fc06SFUJITA Tomonori 	if (devip) {
34805cb2fc06SFUJITA Tomonori 		devip->sdbg_host = sdbg_host;
34815cb2fc06SFUJITA Tomonori 		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
34825cb2fc06SFUJITA Tomonori 	}
34835cb2fc06SFUJITA Tomonori 	return devip;
34845cb2fc06SFUJITA Tomonori }
34855cb2fc06SFUJITA Tomonori 
34861da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
34871da177e4SLinus Torvalds {
34881da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
34891da177e4SLinus Torvalds 	struct sdebug_dev_info * open_devip = NULL;
34901da177e4SLinus Torvalds 	struct sdebug_dev_info * devip =
34911da177e4SLinus Torvalds 			(struct sdebug_dev_info *)sdev->hostdata;
34921da177e4SLinus Torvalds 
34931da177e4SLinus Torvalds 	if (devip)
34941da177e4SLinus Torvalds 		return devip;
3495d1e4c9c5SFUJITA Tomonori 	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
34961da177e4SLinus Torvalds 	if (!sdbg_host) {
3497c1287970STomas Winkler 		pr_err("Host info NULL\n");
34981da177e4SLinus Torvalds 		return NULL;
34991da177e4SLinus Torvalds         }
35001da177e4SLinus Torvalds 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
35011da177e4SLinus Torvalds 		if ((devip->used) && (devip->channel == sdev->channel) &&
35021da177e4SLinus Torvalds                     (devip->target == sdev->id) &&
35031da177e4SLinus Torvalds                     (devip->lun == sdev->lun))
35041da177e4SLinus Torvalds                         return devip;
35051da177e4SLinus Torvalds 		else {
35061da177e4SLinus Torvalds 			if ((!devip->used) && (!open_devip))
35071da177e4SLinus Torvalds 				open_devip = devip;
35081da177e4SLinus Torvalds 		}
35091da177e4SLinus Torvalds 	}
35105cb2fc06SFUJITA Tomonori 	if (!open_devip) { /* try and make a new one */
35115cb2fc06SFUJITA Tomonori 		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
35125cb2fc06SFUJITA Tomonori 		if (!open_devip) {
3513c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
35141da177e4SLinus Torvalds 			return NULL;
35151da177e4SLinus Torvalds 		}
35161da177e4SLinus Torvalds 	}
3517a75869d1SFUJITA Tomonori 
35181da177e4SLinus Torvalds 	open_devip->channel = sdev->channel;
35191da177e4SLinus Torvalds 	open_devip->target = sdev->id;
35201da177e4SLinus Torvalds 	open_devip->lun = sdev->lun;
35211da177e4SLinus Torvalds 	open_devip->sdbg_host = sdbg_host;
3522cbf67842SDouglas Gilbert 	atomic_set(&open_devip->num_in_q, 0);
3523cbf67842SDouglas Gilbert 	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
3524c2248fc9SDouglas Gilbert 	open_devip->used = true;
35251da177e4SLinus Torvalds 	return open_devip;
35261da177e4SLinus Torvalds }
35271da177e4SLinus Torvalds 
35288dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp)
35291da177e4SLinus Torvalds {
3530773642d9SDouglas Gilbert 	if (sdebug_verbose)
3531c1287970STomas Winkler 		pr_info("slave_alloc <%u %u %u %llu>\n",
35328dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
353375ad23bcSNick Piggin 	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
35348dea0d02SFUJITA Tomonori 	return 0;
35358dea0d02SFUJITA Tomonori }
35361da177e4SLinus Torvalds 
35378dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp)
35388dea0d02SFUJITA Tomonori {
35398dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip;
3540a34c4e98SFUJITA Tomonori 
3541773642d9SDouglas Gilbert 	if (sdebug_verbose)
3542c1287970STomas Winkler 		pr_info("slave_configure <%u %u %u %llu>\n",
35438dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
35448dea0d02SFUJITA Tomonori 	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
35458dea0d02SFUJITA Tomonori 		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
35468dea0d02SFUJITA Tomonori 	devip = devInfoReg(sdp);
35478dea0d02SFUJITA Tomonori 	if (NULL == devip)
35488dea0d02SFUJITA Tomonori 		return 1;	/* no resources, will be marked offline */
3549c8b09f6fSChristoph Hellwig 	sdp->hostdata = devip;
35506bb5e6e7SAkinobu Mita 	blk_queue_max_segment_size(sdp->request_queue, -1U);
3551773642d9SDouglas Gilbert 	if (sdebug_no_uld)
355278d4e5a0SDouglas Gilbert 		sdp->no_uld_attach = 1;
35538dea0d02SFUJITA Tomonori 	return 0;
35548dea0d02SFUJITA Tomonori }
35558dea0d02SFUJITA Tomonori 
35568dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp)
35578dea0d02SFUJITA Tomonori {
35588dea0d02SFUJITA Tomonori 	struct sdebug_dev_info *devip =
35598dea0d02SFUJITA Tomonori 		(struct sdebug_dev_info *)sdp->hostdata;
35608dea0d02SFUJITA Tomonori 
3561773642d9SDouglas Gilbert 	if (sdebug_verbose)
3562c1287970STomas Winkler 		pr_info("slave_destroy <%u %u %u %llu>\n",
35638dea0d02SFUJITA Tomonori 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
35648dea0d02SFUJITA Tomonori 	if (devip) {
356525985edcSLucas De Marchi 		/* make this slot available for re-use */
3566c2248fc9SDouglas Gilbert 		devip->used = false;
35678dea0d02SFUJITA Tomonori 		sdp->hostdata = NULL;
35688dea0d02SFUJITA Tomonori 	}
35698dea0d02SFUJITA Tomonori }
35708dea0d02SFUJITA Tomonori 
3571cbf67842SDouglas Gilbert /* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */
35728dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
35738dea0d02SFUJITA Tomonori {
35748dea0d02SFUJITA Tomonori 	unsigned long iflags;
3575cbf67842SDouglas Gilbert 	int k, qmax, r_qmax;
35768dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3577cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
35788dea0d02SFUJITA Tomonori 
35798dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
3580773642d9SDouglas Gilbert 	qmax = sdebug_max_queue;
3581cbf67842SDouglas Gilbert 	r_qmax = atomic_read(&retired_max_queue);
3582cbf67842SDouglas Gilbert 	if (r_qmax > qmax)
3583cbf67842SDouglas Gilbert 		qmax = r_qmax;
3584cbf67842SDouglas Gilbert 	for (k = 0; k < qmax; ++k) {
3585cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
35868dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
3587cbf67842SDouglas Gilbert 			if (cmnd == sqcp->a_cmnd) {
3588db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3589db525fceSDouglas Gilbert 					cmnd->device->hostdata;
3590db525fceSDouglas Gilbert 				if (devip)
3591db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3592db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3593db525fceSDouglas Gilbert 				spin_unlock_irqrestore(&queued_arr_lock,
3594db525fceSDouglas Gilbert 						       iflags);
3595773642d9SDouglas Gilbert 				if (sdebug_ndelay > 0) {
3596cbf67842SDouglas Gilbert 					if (sqcp->sd_hrtp)
3597cbf67842SDouglas Gilbert 						hrtimer_cancel(
3598cbf67842SDouglas Gilbert 							&sqcp->sd_hrtp->hrt);
3599773642d9SDouglas Gilbert 				} else if (sdebug_delay > 0) {
3600cbf67842SDouglas Gilbert 					if (sqcp->cmnd_timerp)
3601cbf67842SDouglas Gilbert 						del_timer_sync(
3602cbf67842SDouglas Gilbert 							sqcp->cmnd_timerp);
3603773642d9SDouglas Gilbert 				} else if (sdebug_delay < 0) {
3604cbf67842SDouglas Gilbert 					if (sqcp->tletp)
3605cbf67842SDouglas Gilbert 						tasklet_kill(sqcp->tletp);
3606cbf67842SDouglas Gilbert 				}
3607db525fceSDouglas Gilbert 				clear_bit(k, queued_in_use_bm);
3608db525fceSDouglas Gilbert 				return 1;
36098dea0d02SFUJITA Tomonori 			}
36108dea0d02SFUJITA Tomonori 		}
3611cbf67842SDouglas Gilbert 	}
36128dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3613db525fceSDouglas Gilbert 	return 0;
36148dea0d02SFUJITA Tomonori }
36158dea0d02SFUJITA Tomonori 
3616cbf67842SDouglas Gilbert /* Deletes (stops) timers or tasklets of all queued commands */
36178dea0d02SFUJITA Tomonori static void stop_all_queued(void)
36188dea0d02SFUJITA Tomonori {
36198dea0d02SFUJITA Tomonori 	unsigned long iflags;
36208dea0d02SFUJITA Tomonori 	int k;
36218dea0d02SFUJITA Tomonori 	struct sdebug_queued_cmd *sqcp;
3622cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
36238dea0d02SFUJITA Tomonori 
36248dea0d02SFUJITA Tomonori 	spin_lock_irqsave(&queued_arr_lock, iflags);
3625cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3626cbf67842SDouglas Gilbert 		if (test_bit(k, queued_in_use_bm)) {
36278dea0d02SFUJITA Tomonori 			sqcp = &queued_arr[k];
3628cbf67842SDouglas Gilbert 			if (sqcp->a_cmnd) {
3629db525fceSDouglas Gilbert 				devip = (struct sdebug_dev_info *)
3630db525fceSDouglas Gilbert 					sqcp->a_cmnd->device->hostdata;
3631db525fceSDouglas Gilbert 				if (devip)
3632db525fceSDouglas Gilbert 					atomic_dec(&devip->num_in_q);
3633db525fceSDouglas Gilbert 				sqcp->a_cmnd = NULL;
3634db525fceSDouglas Gilbert 				spin_unlock_irqrestore(&queued_arr_lock,
3635db525fceSDouglas Gilbert 						       iflags);
3636773642d9SDouglas Gilbert 				if (sdebug_ndelay > 0) {
3637cbf67842SDouglas Gilbert 					if (sqcp->sd_hrtp)
3638cbf67842SDouglas Gilbert 						hrtimer_cancel(
3639cbf67842SDouglas Gilbert 							&sqcp->sd_hrtp->hrt);
3640773642d9SDouglas Gilbert 				} else if (sdebug_delay > 0) {
3641cbf67842SDouglas Gilbert 					if (sqcp->cmnd_timerp)
3642cbf67842SDouglas Gilbert 						del_timer_sync(
3643cbf67842SDouglas Gilbert 							sqcp->cmnd_timerp);
3644773642d9SDouglas Gilbert 				} else if (sdebug_delay < 0) {
3645cbf67842SDouglas Gilbert 					if (sqcp->tletp)
3646cbf67842SDouglas Gilbert 						tasklet_kill(sqcp->tletp);
3647cbf67842SDouglas Gilbert 				}
3648db525fceSDouglas Gilbert 				clear_bit(k, queued_in_use_bm);
3649db525fceSDouglas Gilbert 				spin_lock_irqsave(&queued_arr_lock, iflags);
36508dea0d02SFUJITA Tomonori 			}
36518dea0d02SFUJITA Tomonori 		}
3652cbf67842SDouglas Gilbert 	}
3653cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3654cbf67842SDouglas Gilbert }
3655cbf67842SDouglas Gilbert 
3656cbf67842SDouglas Gilbert /* Free queued command memory on heap */
3657cbf67842SDouglas Gilbert static void free_all_queued(void)
3658cbf67842SDouglas Gilbert {
3659cbf67842SDouglas Gilbert 	unsigned long iflags;
3660cbf67842SDouglas Gilbert 	int k;
3661cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp;
3662cbf67842SDouglas Gilbert 
3663cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
3664cbf67842SDouglas Gilbert 	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3665cbf67842SDouglas Gilbert 		sqcp = &queued_arr[k];
3666cbf67842SDouglas Gilbert 		kfree(sqcp->cmnd_timerp);
3667cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp = NULL;
3668cbf67842SDouglas Gilbert 		kfree(sqcp->tletp);
3669cbf67842SDouglas Gilbert 		sqcp->tletp = NULL;
3670cbf67842SDouglas Gilbert 		kfree(sqcp->sd_hrtp);
3671cbf67842SDouglas Gilbert 		sqcp->sd_hrtp = NULL;
3672cbf67842SDouglas Gilbert 	}
36738dea0d02SFUJITA Tomonori 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
36741da177e4SLinus Torvalds }
36751da177e4SLinus Torvalds 
36761da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
36771da177e4SLinus Torvalds {
36781da177e4SLinus Torvalds 	++num_aborts;
3679cbf67842SDouglas Gilbert 	if (SCpnt) {
3680cbf67842SDouglas Gilbert 		if (SCpnt->device &&
3681773642d9SDouglas Gilbert 		    (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3682cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, SCpnt->device, "%s\n",
3683cbf67842SDouglas Gilbert 				    __func__);
36841da177e4SLinus Torvalds 		stop_queued_cmnd(SCpnt);
3685cbf67842SDouglas Gilbert 	}
36861da177e4SLinus Torvalds 	return SUCCESS;
36871da177e4SLinus Torvalds }
36881da177e4SLinus Torvalds 
36891da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
36901da177e4SLinus Torvalds {
36911da177e4SLinus Torvalds 	struct sdebug_dev_info * devip;
36921da177e4SLinus Torvalds 
36931da177e4SLinus Torvalds 	++num_dev_resets;
3694cbf67842SDouglas Gilbert 	if (SCpnt && SCpnt->device) {
3695cbf67842SDouglas Gilbert 		struct scsi_device *sdp = SCpnt->device;
3696cbf67842SDouglas Gilbert 
3697773642d9SDouglas Gilbert 		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3698cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3699cbf67842SDouglas Gilbert 		devip = devInfoReg(sdp);
37001da177e4SLinus Torvalds 		if (devip)
3701cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_POR, devip->uas_bm);
37021da177e4SLinus Torvalds 	}
37031da177e4SLinus Torvalds 	return SUCCESS;
37041da177e4SLinus Torvalds }
37051da177e4SLinus Torvalds 
3706cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3707cbf67842SDouglas Gilbert {
3708cbf67842SDouglas Gilbert 	struct sdebug_host_info *sdbg_host;
3709cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3710cbf67842SDouglas Gilbert 	struct scsi_device *sdp;
3711cbf67842SDouglas Gilbert 	struct Scsi_Host *hp;
3712cbf67842SDouglas Gilbert 	int k = 0;
3713cbf67842SDouglas Gilbert 
3714cbf67842SDouglas Gilbert 	++num_target_resets;
3715cbf67842SDouglas Gilbert 	if (!SCpnt)
3716cbf67842SDouglas Gilbert 		goto lie;
3717cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3718cbf67842SDouglas Gilbert 	if (!sdp)
3719cbf67842SDouglas Gilbert 		goto lie;
3720773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3721cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3722cbf67842SDouglas Gilbert 	hp = sdp->host;
3723cbf67842SDouglas Gilbert 	if (!hp)
3724cbf67842SDouglas Gilbert 		goto lie;
3725cbf67842SDouglas Gilbert 	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3726cbf67842SDouglas Gilbert 	if (sdbg_host) {
3727cbf67842SDouglas Gilbert 		list_for_each_entry(devip,
3728cbf67842SDouglas Gilbert 				    &sdbg_host->dev_info_list,
3729cbf67842SDouglas Gilbert 				    dev_list)
3730cbf67842SDouglas Gilbert 			if (devip->target == sdp->id) {
3731cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3732cbf67842SDouglas Gilbert 				++k;
3733cbf67842SDouglas Gilbert 			}
3734cbf67842SDouglas Gilbert 	}
3735773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3736cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3737cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in target\n", __func__, k);
3738cbf67842SDouglas Gilbert lie:
3739cbf67842SDouglas Gilbert 	return SUCCESS;
3740cbf67842SDouglas Gilbert }
3741cbf67842SDouglas Gilbert 
37421da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
37431da177e4SLinus Torvalds {
37441da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
3745cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
37461da177e4SLinus Torvalds         struct scsi_device * sdp;
37471da177e4SLinus Torvalds         struct Scsi_Host * hp;
3748cbf67842SDouglas Gilbert 	int k = 0;
37491da177e4SLinus Torvalds 
37501da177e4SLinus Torvalds 	++num_bus_resets;
3751cbf67842SDouglas Gilbert 	if (!(SCpnt && SCpnt->device))
3752cbf67842SDouglas Gilbert 		goto lie;
3753cbf67842SDouglas Gilbert 	sdp = SCpnt->device;
3754773642d9SDouglas Gilbert 	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
3755cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3756cbf67842SDouglas Gilbert 	hp = sdp->host;
3757cbf67842SDouglas Gilbert 	if (hp) {
3758d1e4c9c5SFUJITA Tomonori 		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
37591da177e4SLinus Torvalds 		if (sdbg_host) {
3760cbf67842SDouglas Gilbert 			list_for_each_entry(devip,
37611da177e4SLinus Torvalds                                             &sdbg_host->dev_info_list,
3762cbf67842SDouglas Gilbert 					    dev_list) {
3763cbf67842SDouglas Gilbert 				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3764cbf67842SDouglas Gilbert 				++k;
37651da177e4SLinus Torvalds 			}
37661da177e4SLinus Torvalds 		}
3767cbf67842SDouglas Gilbert 	}
3768773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3769cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3770cbf67842SDouglas Gilbert 			    "%s: %d device(s) found in host\n", __func__, k);
3771cbf67842SDouglas Gilbert lie:
37721da177e4SLinus Torvalds 	return SUCCESS;
37731da177e4SLinus Torvalds }
37741da177e4SLinus Torvalds 
37751da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
37761da177e4SLinus Torvalds {
37771da177e4SLinus Torvalds 	struct sdebug_host_info * sdbg_host;
3778cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
3779cbf67842SDouglas Gilbert 	int k = 0;
37801da177e4SLinus Torvalds 
37811da177e4SLinus Torvalds 	++num_host_resets;
3782773642d9SDouglas Gilbert 	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3783cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
37841da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
37851da177e4SLinus Torvalds         list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3786cbf67842SDouglas Gilbert 		list_for_each_entry(devip, &sdbg_host->dev_info_list,
3787cbf67842SDouglas Gilbert 				    dev_list) {
3788cbf67842SDouglas Gilbert 			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3789cbf67842SDouglas Gilbert 			++k;
3790cbf67842SDouglas Gilbert 		}
37911da177e4SLinus Torvalds         }
37921da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
37931da177e4SLinus Torvalds 	stop_all_queued();
3794773642d9SDouglas Gilbert 	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
3795cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, SCpnt->device,
3796cbf67842SDouglas Gilbert 			    "%s: %d device(s) found\n", __func__, k);
37971da177e4SLinus Torvalds 	return SUCCESS;
37981da177e4SLinus Torvalds }
37991da177e4SLinus Torvalds 
3800f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp,
38015f2578e5SFUJITA Tomonori 				      unsigned long store_size)
38021da177e4SLinus Torvalds {
38031da177e4SLinus Torvalds 	struct partition * pp;
38041da177e4SLinus Torvalds 	int starts[SDEBUG_MAX_PARTS + 2];
38051da177e4SLinus Torvalds 	int sectors_per_part, num_sectors, k;
38061da177e4SLinus Torvalds 	int heads_by_sects, start_sec, end_sec;
38071da177e4SLinus Torvalds 
38081da177e4SLinus Torvalds 	/* assume partition table already zeroed */
3809773642d9SDouglas Gilbert 	if ((sdebug_num_parts < 1) || (store_size < 1048576))
38101da177e4SLinus Torvalds 		return;
3811773642d9SDouglas Gilbert 	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3812773642d9SDouglas Gilbert 		sdebug_num_parts = SDEBUG_MAX_PARTS;
3813c1287970STomas Winkler 		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
38141da177e4SLinus Torvalds 	}
3815c65b1445SDouglas Gilbert 	num_sectors = (int)sdebug_store_sectors;
38161da177e4SLinus Torvalds 	sectors_per_part = (num_sectors - sdebug_sectors_per)
3817773642d9SDouglas Gilbert 			   / sdebug_num_parts;
38181da177e4SLinus Torvalds 	heads_by_sects = sdebug_heads * sdebug_sectors_per;
38191da177e4SLinus Torvalds         starts[0] = sdebug_sectors_per;
3820773642d9SDouglas Gilbert 	for (k = 1; k < sdebug_num_parts; ++k)
38211da177e4SLinus Torvalds 		starts[k] = ((k * sectors_per_part) / heads_by_sects)
38221da177e4SLinus Torvalds 			    * heads_by_sects;
3823773642d9SDouglas Gilbert 	starts[sdebug_num_parts] = num_sectors;
3824773642d9SDouglas Gilbert 	starts[sdebug_num_parts + 1] = 0;
38251da177e4SLinus Torvalds 
38261da177e4SLinus Torvalds 	ramp[510] = 0x55;	/* magic partition markings */
38271da177e4SLinus Torvalds 	ramp[511] = 0xAA;
38281da177e4SLinus Torvalds 	pp = (struct partition *)(ramp + 0x1be);
38291da177e4SLinus Torvalds 	for (k = 0; starts[k + 1]; ++k, ++pp) {
38301da177e4SLinus Torvalds 		start_sec = starts[k];
38311da177e4SLinus Torvalds 		end_sec = starts[k + 1] - 1;
38321da177e4SLinus Torvalds 		pp->boot_ind = 0;
38331da177e4SLinus Torvalds 
38341da177e4SLinus Torvalds 		pp->cyl = start_sec / heads_by_sects;
38351da177e4SLinus Torvalds 		pp->head = (start_sec - (pp->cyl * heads_by_sects))
38361da177e4SLinus Torvalds 			   / sdebug_sectors_per;
38371da177e4SLinus Torvalds 		pp->sector = (start_sec % sdebug_sectors_per) + 1;
38381da177e4SLinus Torvalds 
38391da177e4SLinus Torvalds 		pp->end_cyl = end_sec / heads_by_sects;
38401da177e4SLinus Torvalds 		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
38411da177e4SLinus Torvalds 			       / sdebug_sectors_per;
38421da177e4SLinus Torvalds 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
38431da177e4SLinus Torvalds 
3844150c3544SAkinobu Mita 		pp->start_sect = cpu_to_le32(start_sec);
3845150c3544SAkinobu Mita 		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
38461da177e4SLinus Torvalds 		pp->sys_ind = 0x83;	/* plain Linux partition */
38471da177e4SLinus Torvalds 	}
38481da177e4SLinus Torvalds }
38491da177e4SLinus Torvalds 
3850cbf67842SDouglas Gilbert static int
3851cbf67842SDouglas Gilbert schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3852cbf67842SDouglas Gilbert 	      int scsi_result, int delta_jiff)
38531da177e4SLinus Torvalds {
3854cbf67842SDouglas Gilbert 	unsigned long iflags;
3855cd62b7daSDouglas Gilbert 	int k, num_in_q, qdepth, inject;
3856cbf67842SDouglas Gilbert 	struct sdebug_queued_cmd *sqcp = NULL;
3857299b6c07STomas Winkler 	struct scsi_device *sdp;
38581da177e4SLinus Torvalds 
3859299b6c07STomas Winkler 	/* this should never happen */
3860299b6c07STomas Winkler 	if (WARN_ON(!cmnd))
3861299b6c07STomas Winkler 		return SCSI_MLQUEUE_HOST_BUSY;
3862299b6c07STomas Winkler 
3863299b6c07STomas Winkler 	if (NULL == devip) {
3864299b6c07STomas Winkler 		pr_warn("called devip == NULL\n");
3865cbf67842SDouglas Gilbert 		/* no particularly good error to report back */
3866cbf67842SDouglas Gilbert 		return SCSI_MLQUEUE_HOST_BUSY;
38671da177e4SLinus Torvalds 	}
3868299b6c07STomas Winkler 
3869299b6c07STomas Winkler 	sdp = cmnd->device;
3870299b6c07STomas Winkler 
3871773642d9SDouglas Gilbert 	if (sdebug_verbose && scsi_result)
3872cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3873cbf67842SDouglas Gilbert 			    __func__, scsi_result);
3874cd62b7daSDouglas Gilbert 	if (delta_jiff == 0)
3875cd62b7daSDouglas Gilbert 		goto respond_in_thread;
38761da177e4SLinus Torvalds 
3877cd62b7daSDouglas Gilbert 	/* schedule the response at a later time if resources permit */
38781da177e4SLinus Torvalds 	spin_lock_irqsave(&queued_arr_lock, iflags);
3879cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
3880cbf67842SDouglas Gilbert 	qdepth = cmnd->device->queue_depth;
3881cbf67842SDouglas Gilbert 	inject = 0;
3882cd62b7daSDouglas Gilbert 	if ((qdepth > 0) && (num_in_q >= qdepth)) {
3883cd62b7daSDouglas Gilbert 		if (scsi_result) {
3884cd62b7daSDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
3885cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3886cd62b7daSDouglas Gilbert 		} else
3887cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3888773642d9SDouglas Gilbert 	} else if ((sdebug_every_nth != 0) &&
3889773642d9SDouglas Gilbert 		   (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
3890cd62b7daSDouglas Gilbert 		   (scsi_result == 0)) {
3891cbf67842SDouglas Gilbert 		if ((num_in_q == (qdepth - 1)) &&
3892cbf67842SDouglas Gilbert 		    (atomic_inc_return(&sdebug_a_tsf) >=
3893773642d9SDouglas Gilbert 		     abs(sdebug_every_nth))) {
3894cbf67842SDouglas Gilbert 			atomic_set(&sdebug_a_tsf, 0);
3895cbf67842SDouglas Gilbert 			inject = 1;
3896cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
38971da177e4SLinus Torvalds 		}
3898cbf67842SDouglas Gilbert 	}
3899cbf67842SDouglas Gilbert 
3900773642d9SDouglas Gilbert 	k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
3901773642d9SDouglas Gilbert 	if (k >= sdebug_max_queue) {
39021da177e4SLinus Torvalds 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
3903cd62b7daSDouglas Gilbert 		if (scsi_result)
3904cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3905773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
3906cd62b7daSDouglas Gilbert 			scsi_result = device_qfull_result;
3907773642d9SDouglas Gilbert 		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
3908cbf67842SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp,
3909cd62b7daSDouglas Gilbert 				    "%s: max_queue=%d exceeded, %s\n",
3910773642d9SDouglas Gilbert 				    __func__, sdebug_max_queue,
3911cd62b7daSDouglas Gilbert 				    (scsi_result ?  "status: TASK SET FULL" :
3912cbf67842SDouglas Gilbert 						    "report: host busy"));
3913cd62b7daSDouglas Gilbert 		if (scsi_result)
3914cd62b7daSDouglas Gilbert 			goto respond_in_thread;
3915cd62b7daSDouglas Gilbert 		else
3916cbf67842SDouglas Gilbert 			return SCSI_MLQUEUE_HOST_BUSY;
39171da177e4SLinus Torvalds 	}
3918cbf67842SDouglas Gilbert 	__set_bit(k, queued_in_use_bm);
3919cbf67842SDouglas Gilbert 	atomic_inc(&devip->num_in_q);
3920cbf67842SDouglas Gilbert 	sqcp = &queued_arr[k];
39211da177e4SLinus Torvalds 	sqcp->a_cmnd = cmnd;
3922cbf67842SDouglas Gilbert 	cmnd->result = scsi_result;
39231da177e4SLinus Torvalds 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
3924cbf67842SDouglas Gilbert 	if (delta_jiff > 0) {
3925cbf67842SDouglas Gilbert 		if (NULL == sqcp->cmnd_timerp) {
3926cbf67842SDouglas Gilbert 			sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list),
3927cbf67842SDouglas Gilbert 						    GFP_ATOMIC);
3928cbf67842SDouglas Gilbert 			if (NULL == sqcp->cmnd_timerp)
3929cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3930cbf67842SDouglas Gilbert 			init_timer(sqcp->cmnd_timerp);
3931cbf67842SDouglas Gilbert 		}
3932cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->function = sdebug_q_cmd_complete;
3933cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->data = k;
3934cbf67842SDouglas Gilbert 		sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff;
3935cbf67842SDouglas Gilbert 		add_timer(sqcp->cmnd_timerp);
3936773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0) {
3937773642d9SDouglas Gilbert 		ktime_t kt = ktime_set(0, sdebug_ndelay);
3938cbf67842SDouglas Gilbert 		struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp;
3939cbf67842SDouglas Gilbert 
3940cbf67842SDouglas Gilbert 		if (NULL == sd_hp) {
3941cbf67842SDouglas Gilbert 			sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC);
3942cbf67842SDouglas Gilbert 			if (NULL == sd_hp)
3943cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3944cbf67842SDouglas Gilbert 			sqcp->sd_hrtp = sd_hp;
3945cbf67842SDouglas Gilbert 			hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC,
3946cbf67842SDouglas Gilbert 				     HRTIMER_MODE_REL);
3947cbf67842SDouglas Gilbert 			sd_hp->hrt.function = sdebug_q_cmd_hrt_complete;
3948cbf67842SDouglas Gilbert 			sd_hp->qa_indx = k;
3949cbf67842SDouglas Gilbert 		}
3950cbf67842SDouglas Gilbert 		hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL);
3951cbf67842SDouglas Gilbert 	} else {	/* delay < 0 */
3952cbf67842SDouglas Gilbert 		if (NULL == sqcp->tletp) {
3953cbf67842SDouglas Gilbert 			sqcp->tletp = kmalloc(sizeof(*sqcp->tletp),
3954cbf67842SDouglas Gilbert 					      GFP_ATOMIC);
3955cbf67842SDouglas Gilbert 			if (NULL == sqcp->tletp)
3956cbf67842SDouglas Gilbert 				return SCSI_MLQUEUE_HOST_BUSY;
3957cbf67842SDouglas Gilbert 			tasklet_init(sqcp->tletp,
3958cbf67842SDouglas Gilbert 				     sdebug_q_cmd_complete, k);
3959cbf67842SDouglas Gilbert 		}
3960cbf67842SDouglas Gilbert 		if (-1 == delta_jiff)
3961cbf67842SDouglas Gilbert 			tasklet_hi_schedule(sqcp->tletp);
3962cbf67842SDouglas Gilbert 		else
3963cbf67842SDouglas Gilbert 			tasklet_schedule(sqcp->tletp);
3964cbf67842SDouglas Gilbert 	}
3965773642d9SDouglas Gilbert 	if ((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
3966cd62b7daSDouglas Gilbert 	    (scsi_result == device_qfull_result))
3967cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp,
3968cbf67842SDouglas Gilbert 			    "%s: num_in_q=%d +1, %s%s\n", __func__,
3969cbf67842SDouglas Gilbert 			    num_in_q, (inject ? "<inject> " : ""),
3970cbf67842SDouglas Gilbert 			    "status: TASK SET FULL");
39711da177e4SLinus Torvalds 	return 0;
3972cd62b7daSDouglas Gilbert 
3973cd62b7daSDouglas Gilbert respond_in_thread:	/* call back to mid-layer using invocation thread */
3974cd62b7daSDouglas Gilbert 	cmnd->result = scsi_result;
3975cd62b7daSDouglas Gilbert 	cmnd->scsi_done(cmnd);
3976cd62b7daSDouglas Gilbert 	return 0;
39771da177e4SLinus Torvalds }
3978cbf67842SDouglas Gilbert 
397923183910SDouglas Gilbert /* Note: The following macros create attribute files in the
398023183910SDouglas Gilbert    /sys/module/scsi_debug/parameters directory. Unfortunately this
398123183910SDouglas Gilbert    driver is unaware of a change and cannot trigger auxiliary actions
398223183910SDouglas Gilbert    as it can when the corresponding attribute in the
398323183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory is changed.
398423183910SDouglas Gilbert  */
3985773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
3986773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO);
3987773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
3988773642d9SDouglas Gilbert module_param_named(delay, sdebug_delay, int, S_IRUGO | S_IWUSR);
3989773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
3990773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO);
3991773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO);
3992773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
3993773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
3994773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
3995773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO);
3996773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
3997773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
3998773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
3999773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4000773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4001773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4002773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4003773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4004773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4005773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4006773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4007773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4008773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4009773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4010773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4011773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
4012773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4013773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4014773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4015773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4016773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4017773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4018773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4019773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4020773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4021773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
4022773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
402323183910SDouglas Gilbert 		   S_IRUGO | S_IWUSR);
4024773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int,
40255b94e232SMartin K. Petersen 		   S_IRUGO | S_IWUSR);
40261da177e4SLinus Torvalds 
40271da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
40281da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver");
40291da177e4SLinus Torvalds MODULE_LICENSE("GPL");
40301da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION);
40311da177e4SLinus Torvalds 
40321da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
40335b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
40340759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
4035cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
4036c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
40375b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
40385b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
4039c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
4040beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
404123183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
40425b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
4043185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
40445b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
40455b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
40465b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
4047be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
40485b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
4049c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
4050cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4051cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
4052c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
405378d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
40541da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
4055c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
405632c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
40576f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
40585b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
40591da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
4060d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
4061e46b0344SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
4062ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
4063c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
40645b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
40655b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
40666014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
40676014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
4068c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
40695b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
40705b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
40711da177e4SLinus Torvalds 
40721da177e4SLinus Torvalds static char sdebug_info[256];
40731da177e4SLinus Torvalds 
40741da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp)
40751da177e4SLinus Torvalds {
40761da177e4SLinus Torvalds 	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
40771da177e4SLinus Torvalds 		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
4078773642d9SDouglas Gilbert 		sdebug_version_date, sdebug_dev_size_mb, sdebug_opts);
40791da177e4SLinus Torvalds 	return sdebug_info;
40801da177e4SLinus Torvalds }
40811da177e4SLinus Torvalds 
4082cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
4083c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
40841da177e4SLinus Torvalds {
40851da177e4SLinus Torvalds 	char arr[16];
4086c8ed555aSAl Viro 	int opts;
40871da177e4SLinus Torvalds 	int minLen = length > 15 ? 15 : length;
40881da177e4SLinus Torvalds 
40891da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
40901da177e4SLinus Torvalds 		return -EACCES;
40911da177e4SLinus Torvalds 	memcpy(arr, buffer, minLen);
40921da177e4SLinus Torvalds 	arr[minLen] = '\0';
4093c8ed555aSAl Viro 	if (1 != sscanf(arr, "%d", &opts))
40941da177e4SLinus Torvalds 		return -EINVAL;
4095773642d9SDouglas Gilbert 	sdebug_opts = opts;
4096773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4097773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4098773642d9SDouglas Gilbert 	if (sdebug_every_nth != 0)
4099cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
41001da177e4SLinus Torvalds 	return length;
41011da177e4SLinus Torvalds }
4102c8ed555aSAl Viro 
4103cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4104cbf67842SDouglas Gilbert  * same for each scsi_debug host (if more than one). Some of the counters
4105cbf67842SDouglas Gilbert  * output are not atomics so might be inaccurate in a busy system. */
4106c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4107c8ed555aSAl Viro {
4108cbf67842SDouglas Gilbert 	int f, l;
4109cbf67842SDouglas Gilbert 	char b[32];
4110cbf67842SDouglas Gilbert 
4111773642d9SDouglas Gilbert 	if (sdebug_every_nth > 0)
4112cbf67842SDouglas Gilbert 		snprintf(b, sizeof(b), " (curr:%d)",
4113773642d9SDouglas Gilbert 			 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
4114cbf67842SDouglas Gilbert 				atomic_read(&sdebug_a_tsf) :
4115cbf67842SDouglas Gilbert 				atomic_read(&sdebug_cmnd_count)));
4116cbf67842SDouglas Gilbert 	else
4117cbf67842SDouglas Gilbert 		b[0] = '\0';
4118cbf67842SDouglas Gilbert 
4119cbf67842SDouglas Gilbert 	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
41201da177e4SLinus Torvalds 		"num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4121cbf67842SDouglas Gilbert 		"every_nth=%d%s\n"
4122cbf67842SDouglas Gilbert 		"delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
41231da177e4SLinus Torvalds 		"sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4124cbf67842SDouglas Gilbert 		"command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4125cbf67842SDouglas Gilbert 		"host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4126cbf67842SDouglas Gilbert 		"usec_in_jiffy=%lu\n",
4127773642d9SDouglas Gilbert 		SCSI_DEBUG_VERSION, sdebug_version_date,
4128773642d9SDouglas Gilbert 		sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
4129773642d9SDouglas Gilbert 		sdebug_every_nth, b, sdebug_delay, sdebug_ndelay,
4130773642d9SDouglas Gilbert 		sdebug_max_luns, atomic_read(&sdebug_completions),
4131773642d9SDouglas Gilbert 		sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
4132cbf67842SDouglas Gilbert 		sdebug_sectors_per, num_aborts, num_dev_resets,
4133cbf67842SDouglas Gilbert 		num_target_resets, num_bus_resets, num_host_resets,
4134cbf67842SDouglas Gilbert 		dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4135cbf67842SDouglas Gilbert 
4136773642d9SDouglas Gilbert 	f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4137773642d9SDouglas Gilbert 	if (f != sdebug_max_queue) {
4138773642d9SDouglas Gilbert 		l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
4139cbf67842SDouglas Gilbert 		seq_printf(m, "   %s BUSY: first,last bits set: %d,%d\n",
4140cbf67842SDouglas Gilbert 			   "queued_in_use_bm", f, l);
4141cbf67842SDouglas Gilbert 	}
4142c8ed555aSAl Viro 	return 0;
41431da177e4SLinus Torvalds }
41441da177e4SLinus Torvalds 
414582069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf)
41461da177e4SLinus Torvalds {
4147773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_delay);
41481da177e4SLinus Torvalds }
4149cbf67842SDouglas Gilbert /* Returns -EBUSY if delay is being changed and commands are queued */
415082069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf,
415182069379SAkinobu Mita 			   size_t count)
41521da177e4SLinus Torvalds {
4153cbf67842SDouglas Gilbert 	int delay, res;
41541da177e4SLinus Torvalds 
4155cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) {
4156cbf67842SDouglas Gilbert 		res = count;
4157773642d9SDouglas Gilbert 		if (sdebug_delay != delay) {
4158cbf67842SDouglas Gilbert 			unsigned long iflags;
4159cbf67842SDouglas Gilbert 			int k;
4160cbf67842SDouglas Gilbert 
4161cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4162773642d9SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4163773642d9SDouglas Gilbert 			if (k != sdebug_max_queue)
4164cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4165cbf67842SDouglas Gilbert 			else {
4166773642d9SDouglas Gilbert 				sdebug_delay = delay;
4167773642d9SDouglas Gilbert 				sdebug_ndelay = 0;
41681da177e4SLinus Torvalds 			}
4169cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4170cbf67842SDouglas Gilbert 		}
4171cbf67842SDouglas Gilbert 		return res;
41721da177e4SLinus Torvalds 	}
41731da177e4SLinus Torvalds 	return -EINVAL;
41741da177e4SLinus Torvalds }
417582069379SAkinobu Mita static DRIVER_ATTR_RW(delay);
41761da177e4SLinus Torvalds 
4177cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4178cbf67842SDouglas Gilbert {
4179773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
4180cbf67842SDouglas Gilbert }
4181cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */
4182773642d9SDouglas Gilbert /* If > 0 and accepted then sdebug_delay is set to DELAY_OVERRIDDEN */
4183cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4184cbf67842SDouglas Gilbert 			   size_t count)
4185cbf67842SDouglas Gilbert {
4186cbf67842SDouglas Gilbert 	unsigned long iflags;
4187cbf67842SDouglas Gilbert 	int ndelay, res, k;
4188cbf67842SDouglas Gilbert 
4189cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4190cbf67842SDouglas Gilbert 	    (ndelay >= 0) && (ndelay < 1000000000)) {
4191cbf67842SDouglas Gilbert 		res = count;
4192773642d9SDouglas Gilbert 		if (sdebug_ndelay != ndelay) {
4193cbf67842SDouglas Gilbert 			spin_lock_irqsave(&queued_arr_lock, iflags);
4194773642d9SDouglas Gilbert 			k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4195773642d9SDouglas Gilbert 			if (k != sdebug_max_queue)
4196cbf67842SDouglas Gilbert 				res = -EBUSY;	/* have queued commands */
4197cbf67842SDouglas Gilbert 			else {
4198773642d9SDouglas Gilbert 				sdebug_ndelay = ndelay;
4199773642d9SDouglas Gilbert 				sdebug_delay = ndelay ? DELAY_OVERRIDDEN
4200cbf67842SDouglas Gilbert 							  : DEF_DELAY;
4201cbf67842SDouglas Gilbert 			}
4202cbf67842SDouglas Gilbert 			spin_unlock_irqrestore(&queued_arr_lock, iflags);
4203cbf67842SDouglas Gilbert 		}
4204cbf67842SDouglas Gilbert 		return res;
4205cbf67842SDouglas Gilbert 	}
4206cbf67842SDouglas Gilbert 	return -EINVAL;
4207cbf67842SDouglas Gilbert }
4208cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay);
4209cbf67842SDouglas Gilbert 
421082069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf)
42111da177e4SLinus Torvalds {
4212773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
42131da177e4SLinus Torvalds }
42141da177e4SLinus Torvalds 
421582069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf,
421682069379SAkinobu Mita 			  size_t count)
42171da177e4SLinus Torvalds {
42181da177e4SLinus Torvalds         int opts;
42191da177e4SLinus Torvalds 	char work[20];
42201da177e4SLinus Torvalds 
42211da177e4SLinus Torvalds         if (1 == sscanf(buf, "%10s", work)) {
422248a96876SRasmus Villemoes 		if (0 == strncasecmp(work,"0x", 2)) {
42231da177e4SLinus Torvalds 			if (1 == sscanf(&work[2], "%x", &opts))
42241da177e4SLinus Torvalds 				goto opts_done;
42251da177e4SLinus Torvalds 		} else {
42261da177e4SLinus Torvalds 			if (1 == sscanf(work, "%d", &opts))
42271da177e4SLinus Torvalds 				goto opts_done;
42281da177e4SLinus Torvalds 		}
42291da177e4SLinus Torvalds 	}
42301da177e4SLinus Torvalds 	return -EINVAL;
42311da177e4SLinus Torvalds opts_done:
4232773642d9SDouglas Gilbert 	sdebug_opts = opts;
4233773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4234773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4235cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4236cbf67842SDouglas Gilbert 	atomic_set(&sdebug_a_tsf, 0);
42371da177e4SLinus Torvalds 	return count;
42381da177e4SLinus Torvalds }
423982069379SAkinobu Mita static DRIVER_ATTR_RW(opts);
42401da177e4SLinus Torvalds 
424182069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf)
42421da177e4SLinus Torvalds {
4243773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
42441da177e4SLinus Torvalds }
424582069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
424682069379SAkinobu Mita 			   size_t count)
42471da177e4SLinus Torvalds {
42481da177e4SLinus Torvalds         int n;
42491da177e4SLinus Torvalds 
42501da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4251773642d9SDouglas Gilbert 		sdebug_ptype = n;
42521da177e4SLinus Torvalds 		return count;
42531da177e4SLinus Torvalds 	}
42541da177e4SLinus Torvalds 	return -EINVAL;
42551da177e4SLinus Torvalds }
425682069379SAkinobu Mita static DRIVER_ATTR_RW(ptype);
42571da177e4SLinus Torvalds 
425882069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf)
42591da177e4SLinus Torvalds {
4260773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
42611da177e4SLinus Torvalds }
426282069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
426382069379SAkinobu Mita 			    size_t count)
42641da177e4SLinus Torvalds {
42651da177e4SLinus Torvalds         int n;
42661da177e4SLinus Torvalds 
42671da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4268773642d9SDouglas Gilbert 		sdebug_dsense = n;
42691da177e4SLinus Torvalds 		return count;
42701da177e4SLinus Torvalds 	}
42711da177e4SLinus Torvalds 	return -EINVAL;
42721da177e4SLinus Torvalds }
427382069379SAkinobu Mita static DRIVER_ATTR_RW(dsense);
42741da177e4SLinus Torvalds 
427582069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
427623183910SDouglas Gilbert {
4277773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
427823183910SDouglas Gilbert }
427982069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
428082069379SAkinobu Mita 			     size_t count)
428123183910SDouglas Gilbert {
428223183910SDouglas Gilbert         int n;
428323183910SDouglas Gilbert 
428423183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4285cbf67842SDouglas Gilbert 		n = (n > 0);
4286773642d9SDouglas Gilbert 		sdebug_fake_rw = (sdebug_fake_rw > 0);
4287773642d9SDouglas Gilbert 		if (sdebug_fake_rw != n) {
4288cbf67842SDouglas Gilbert 			if ((0 == n) && (NULL == fake_storep)) {
4289cbf67842SDouglas Gilbert 				unsigned long sz =
4290773642d9SDouglas Gilbert 					(unsigned long)sdebug_dev_size_mb *
4291cbf67842SDouglas Gilbert 					1048576;
4292cbf67842SDouglas Gilbert 
4293cbf67842SDouglas Gilbert 				fake_storep = vmalloc(sz);
4294cbf67842SDouglas Gilbert 				if (NULL == fake_storep) {
4295c1287970STomas Winkler 					pr_err("out of memory, 9\n");
4296cbf67842SDouglas Gilbert 					return -ENOMEM;
4297cbf67842SDouglas Gilbert 				}
4298cbf67842SDouglas Gilbert 				memset(fake_storep, 0, sz);
4299cbf67842SDouglas Gilbert 			}
4300773642d9SDouglas Gilbert 			sdebug_fake_rw = n;
4301cbf67842SDouglas Gilbert 		}
430223183910SDouglas Gilbert 		return count;
430323183910SDouglas Gilbert 	}
430423183910SDouglas Gilbert 	return -EINVAL;
430523183910SDouglas Gilbert }
430682069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw);
430723183910SDouglas Gilbert 
430882069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
4309c65b1445SDouglas Gilbert {
4310773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
4311c65b1445SDouglas Gilbert }
431282069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
431382069379SAkinobu Mita 			      size_t count)
4314c65b1445SDouglas Gilbert {
4315c65b1445SDouglas Gilbert         int n;
4316c65b1445SDouglas Gilbert 
4317c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4318773642d9SDouglas Gilbert 		sdebug_no_lun_0 = n;
4319c65b1445SDouglas Gilbert 		return count;
4320c65b1445SDouglas Gilbert 	}
4321c65b1445SDouglas Gilbert 	return -EINVAL;
4322c65b1445SDouglas Gilbert }
432382069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0);
4324c65b1445SDouglas Gilbert 
432582069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
43261da177e4SLinus Torvalds {
4327773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
43281da177e4SLinus Torvalds }
432982069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
433082069379SAkinobu Mita 			      size_t count)
43311da177e4SLinus Torvalds {
43321da177e4SLinus Torvalds         int n;
43331da177e4SLinus Torvalds 
43341da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4335773642d9SDouglas Gilbert 		sdebug_num_tgts = n;
43361da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
43371da177e4SLinus Torvalds 		return count;
43381da177e4SLinus Torvalds 	}
43391da177e4SLinus Torvalds 	return -EINVAL;
43401da177e4SLinus Torvalds }
434182069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts);
43421da177e4SLinus Torvalds 
434382069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
43441da177e4SLinus Torvalds {
4345773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
43461da177e4SLinus Torvalds }
434782069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb);
43481da177e4SLinus Torvalds 
434982069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
43501da177e4SLinus Torvalds {
4351773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
43521da177e4SLinus Torvalds }
435382069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts);
43541da177e4SLinus Torvalds 
435582069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
43561da177e4SLinus Torvalds {
4357773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
43581da177e4SLinus Torvalds }
435982069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
436082069379SAkinobu Mita 			       size_t count)
43611da177e4SLinus Torvalds {
43621da177e4SLinus Torvalds         int nth;
43631da177e4SLinus Torvalds 
43641da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4365773642d9SDouglas Gilbert 		sdebug_every_nth = nth;
4366cbf67842SDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
43671da177e4SLinus Torvalds 		return count;
43681da177e4SLinus Torvalds 	}
43691da177e4SLinus Torvalds 	return -EINVAL;
43701da177e4SLinus Torvalds }
437182069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth);
43721da177e4SLinus Torvalds 
437382069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
43741da177e4SLinus Torvalds {
4375773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
43761da177e4SLinus Torvalds }
437782069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
437882069379SAkinobu Mita 			      size_t count)
43791da177e4SLinus Torvalds {
43801da177e4SLinus Torvalds         int n;
438119c8ead7SEwan D. Milne 	bool changed;
43821da177e4SLinus Torvalds 
43831da177e4SLinus Torvalds 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4384773642d9SDouglas Gilbert 		changed = (sdebug_max_luns != n);
4385773642d9SDouglas Gilbert 		sdebug_max_luns = n;
43861da177e4SLinus Torvalds 		sdebug_max_tgts_luns();
4387773642d9SDouglas Gilbert 		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
438819c8ead7SEwan D. Milne 			struct sdebug_host_info *sdhp;
438919c8ead7SEwan D. Milne 			struct sdebug_dev_info *dp;
439019c8ead7SEwan D. Milne 
439119c8ead7SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
439219c8ead7SEwan D. Milne 			list_for_each_entry(sdhp, &sdebug_host_list,
439319c8ead7SEwan D. Milne 					    host_list) {
439419c8ead7SEwan D. Milne 				list_for_each_entry(dp, &sdhp->dev_info_list,
439519c8ead7SEwan D. Milne 						    dev_list) {
439619c8ead7SEwan D. Milne 					set_bit(SDEBUG_UA_LUNS_CHANGED,
439719c8ead7SEwan D. Milne 						dp->uas_bm);
439819c8ead7SEwan D. Milne 				}
439919c8ead7SEwan D. Milne 			}
440019c8ead7SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
440119c8ead7SEwan D. Milne 		}
44021da177e4SLinus Torvalds 		return count;
44031da177e4SLinus Torvalds 	}
44041da177e4SLinus Torvalds 	return -EINVAL;
44051da177e4SLinus Torvalds }
440682069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns);
44071da177e4SLinus Torvalds 
440882069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
440978d4e5a0SDouglas Gilbert {
4410773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
441178d4e5a0SDouglas Gilbert }
4412cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight
4413cbf67842SDouglas Gilbert  * commands beyond the new max_queue will be completed. */
441482069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
441582069379SAkinobu Mita 			       size_t count)
441678d4e5a0SDouglas Gilbert {
4417cbf67842SDouglas Gilbert 	unsigned long iflags;
4418cbf67842SDouglas Gilbert 	int n, k;
441978d4e5a0SDouglas Gilbert 
442078d4e5a0SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
442178d4e5a0SDouglas Gilbert 	    (n <= SCSI_DEBUG_CANQUEUE)) {
4422cbf67842SDouglas Gilbert 		spin_lock_irqsave(&queued_arr_lock, iflags);
4423cbf67842SDouglas Gilbert 		k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
4424773642d9SDouglas Gilbert 		sdebug_max_queue = n;
4425cbf67842SDouglas Gilbert 		if (SCSI_DEBUG_CANQUEUE == k)
4426cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4427cbf67842SDouglas Gilbert 		else if (k >= n)
4428cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, k + 1);
4429cbf67842SDouglas Gilbert 		else
4430cbf67842SDouglas Gilbert 			atomic_set(&retired_max_queue, 0);
4431cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
443278d4e5a0SDouglas Gilbert 		return count;
443378d4e5a0SDouglas Gilbert 	}
443478d4e5a0SDouglas Gilbert 	return -EINVAL;
443578d4e5a0SDouglas Gilbert }
443682069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue);
443778d4e5a0SDouglas Gilbert 
443882069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
443978d4e5a0SDouglas Gilbert {
4440773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
444178d4e5a0SDouglas Gilbert }
444282069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld);
444378d4e5a0SDouglas Gilbert 
444482069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
44451da177e4SLinus Torvalds {
4446773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
44471da177e4SLinus Torvalds }
444882069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level);
44491da177e4SLinus Torvalds 
445082069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
4451c65b1445SDouglas Gilbert {
4452773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
4453c65b1445SDouglas Gilbert }
445482069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
445582069379SAkinobu Mita 				size_t count)
4456c65b1445SDouglas Gilbert {
4457c65b1445SDouglas Gilbert         int n;
44580d01c5dfSDouglas Gilbert 	bool changed;
4459c65b1445SDouglas Gilbert 
4460c65b1445SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4461773642d9SDouglas Gilbert 		changed = (sdebug_virtual_gb != n);
4462773642d9SDouglas Gilbert 		sdebug_virtual_gb = n;
446328898873SFUJITA Tomonori 		sdebug_capacity = get_sdebug_capacity();
44640d01c5dfSDouglas Gilbert 		if (changed) {
44650d01c5dfSDouglas Gilbert 			struct sdebug_host_info *sdhp;
44660d01c5dfSDouglas Gilbert 			struct sdebug_dev_info *dp;
446728898873SFUJITA Tomonori 
44684bc6b634SEwan D. Milne 			spin_lock(&sdebug_host_list_lock);
44690d01c5dfSDouglas Gilbert 			list_for_each_entry(sdhp, &sdebug_host_list,
44700d01c5dfSDouglas Gilbert 					    host_list) {
44710d01c5dfSDouglas Gilbert 				list_for_each_entry(dp, &sdhp->dev_info_list,
44720d01c5dfSDouglas Gilbert 						    dev_list) {
44730d01c5dfSDouglas Gilbert 					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
44740d01c5dfSDouglas Gilbert 						dp->uas_bm);
44750d01c5dfSDouglas Gilbert 				}
44760d01c5dfSDouglas Gilbert 			}
44774bc6b634SEwan D. Milne 			spin_unlock(&sdebug_host_list_lock);
44780d01c5dfSDouglas Gilbert 		}
4479c65b1445SDouglas Gilbert 		return count;
4480c65b1445SDouglas Gilbert 	}
4481c65b1445SDouglas Gilbert 	return -EINVAL;
4482c65b1445SDouglas Gilbert }
448382069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb);
4484c65b1445SDouglas Gilbert 
448582069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf)
44861da177e4SLinus Torvalds {
4487773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
44881da177e4SLinus Torvalds }
44891da177e4SLinus Torvalds 
449082069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
449182069379SAkinobu Mita 			      size_t count)
44921da177e4SLinus Torvalds {
44931da177e4SLinus Torvalds 	int delta_hosts;
44941da177e4SLinus Torvalds 
4495f3df41cfSFUJITA Tomonori 	if (sscanf(buf, "%d", &delta_hosts) != 1)
44961da177e4SLinus Torvalds 		return -EINVAL;
44971da177e4SLinus Torvalds 	if (delta_hosts > 0) {
44981da177e4SLinus Torvalds 		do {
44991da177e4SLinus Torvalds 			sdebug_add_adapter();
45001da177e4SLinus Torvalds 		} while (--delta_hosts);
45011da177e4SLinus Torvalds 	} else if (delta_hosts < 0) {
45021da177e4SLinus Torvalds 		do {
45031da177e4SLinus Torvalds 			sdebug_remove_adapter();
45041da177e4SLinus Torvalds 		} while (++delta_hosts);
45051da177e4SLinus Torvalds 	}
45061da177e4SLinus Torvalds 	return count;
45071da177e4SLinus Torvalds }
450882069379SAkinobu Mita static DRIVER_ATTR_RW(add_host);
45091da177e4SLinus Torvalds 
451082069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
451123183910SDouglas Gilbert {
4512773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
451323183910SDouglas Gilbert }
451482069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
451582069379SAkinobu Mita 				    size_t count)
451623183910SDouglas Gilbert {
451723183910SDouglas Gilbert 	int n;
451823183910SDouglas Gilbert 
451923183910SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4520773642d9SDouglas Gilbert 		sdebug_vpd_use_hostno = n;
452123183910SDouglas Gilbert 		return count;
452223183910SDouglas Gilbert 	}
452323183910SDouglas Gilbert 	return -EINVAL;
452423183910SDouglas Gilbert }
452582069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno);
452623183910SDouglas Gilbert 
452782069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
4528597136abSMartin K. Petersen {
4529773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
4530597136abSMartin K. Petersen }
453182069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size);
4532597136abSMartin K. Petersen 
453382069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf)
4534c6a44287SMartin K. Petersen {
4535773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
4536c6a44287SMartin K. Petersen }
453782069379SAkinobu Mita static DRIVER_ATTR_RO(dix);
4538c6a44287SMartin K. Petersen 
453982069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf)
4540c6a44287SMartin K. Petersen {
4541773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
4542c6a44287SMartin K. Petersen }
454382069379SAkinobu Mita static DRIVER_ATTR_RO(dif);
4544c6a44287SMartin K. Petersen 
454582069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf)
4546c6a44287SMartin K. Petersen {
4547773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
4548c6a44287SMartin K. Petersen }
454982069379SAkinobu Mita static DRIVER_ATTR_RO(guard);
4550c6a44287SMartin K. Petersen 
455182069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf)
4552c6a44287SMartin K. Petersen {
4553773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
4554c6a44287SMartin K. Petersen }
455582069379SAkinobu Mita static DRIVER_ATTR_RO(ato);
4556c6a44287SMartin K. Petersen 
455782069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf)
455844d92694SMartin K. Petersen {
455944d92694SMartin K. Petersen 	ssize_t count;
456044d92694SMartin K. Petersen 
45615b94e232SMartin K. Petersen 	if (!scsi_debug_lbp())
456244d92694SMartin K. Petersen 		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
456344d92694SMartin K. Petersen 				 sdebug_store_sectors);
456444d92694SMartin K. Petersen 
4565c7badc90STejun Heo 	count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4566c7badc90STejun Heo 			  (int)map_size, map_storep);
456744d92694SMartin K. Petersen 	buf[count++] = '\n';
4568c7badc90STejun Heo 	buf[count] = '\0';
456944d92694SMartin K. Petersen 
457044d92694SMartin K. Petersen 	return count;
457144d92694SMartin K. Petersen }
457282069379SAkinobu Mita static DRIVER_ATTR_RO(map);
457344d92694SMartin K. Petersen 
457482069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf)
4575d986788bSMartin Pitt {
4576773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
4577d986788bSMartin Pitt }
457882069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf,
457982069379SAkinobu Mita 			       size_t count)
4580d986788bSMartin Pitt {
4581d986788bSMartin Pitt 	int n;
4582d986788bSMartin Pitt 
4583d986788bSMartin Pitt 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4584773642d9SDouglas Gilbert 		sdebug_removable = (n > 0);
4585d986788bSMartin Pitt 		return count;
4586d986788bSMartin Pitt 	}
4587d986788bSMartin Pitt 	return -EINVAL;
4588d986788bSMartin Pitt }
458982069379SAkinobu Mita static DRIVER_ATTR_RW(removable);
4590d986788bSMartin Pitt 
4591cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4592cbf67842SDouglas Gilbert {
4593773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
4594cbf67842SDouglas Gilbert }
4595185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
4596cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4597cbf67842SDouglas Gilbert 			       size_t count)
4598cbf67842SDouglas Gilbert {
4599185dd232SDouglas Gilbert 	int n;
4600cbf67842SDouglas Gilbert 
4601cbf67842SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4602185dd232SDouglas Gilbert 		sdebug_host_lock = (n > 0);
4603185dd232SDouglas Gilbert 		return count;
4604cbf67842SDouglas Gilbert 	}
4605cbf67842SDouglas Gilbert 	return -EINVAL;
4606cbf67842SDouglas Gilbert }
4607cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock);
4608cbf67842SDouglas Gilbert 
4609c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf)
4610c2248fc9SDouglas Gilbert {
4611773642d9SDouglas Gilbert 	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
4612c2248fc9SDouglas Gilbert }
4613c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4614c2248fc9SDouglas Gilbert 			    size_t count)
4615c2248fc9SDouglas Gilbert {
4616c2248fc9SDouglas Gilbert 	int n;
4617c2248fc9SDouglas Gilbert 
4618c2248fc9SDouglas Gilbert 	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4619773642d9SDouglas Gilbert 		sdebug_strict = (n > 0);
4620c2248fc9SDouglas Gilbert 		return count;
4621c2248fc9SDouglas Gilbert 	}
4622c2248fc9SDouglas Gilbert 	return -EINVAL;
4623c2248fc9SDouglas Gilbert }
4624c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict);
4625c2248fc9SDouglas Gilbert 
4626cbf67842SDouglas Gilbert 
462782069379SAkinobu Mita /* Note: The following array creates attribute files in the
462823183910SDouglas Gilbert    /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
462923183910SDouglas Gilbert    files (over those found in the /sys/module/scsi_debug/parameters
463023183910SDouglas Gilbert    directory) is that auxiliary actions can be triggered when an attribute
463123183910SDouglas Gilbert    is changed. For example see: sdebug_add_host_store() above.
463223183910SDouglas Gilbert  */
46336ecaff7fSRandy Dunlap 
463482069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = {
463582069379SAkinobu Mita 	&driver_attr_delay.attr,
463682069379SAkinobu Mita 	&driver_attr_opts.attr,
463782069379SAkinobu Mita 	&driver_attr_ptype.attr,
463882069379SAkinobu Mita 	&driver_attr_dsense.attr,
463982069379SAkinobu Mita 	&driver_attr_fake_rw.attr,
464082069379SAkinobu Mita 	&driver_attr_no_lun_0.attr,
464182069379SAkinobu Mita 	&driver_attr_num_tgts.attr,
464282069379SAkinobu Mita 	&driver_attr_dev_size_mb.attr,
464382069379SAkinobu Mita 	&driver_attr_num_parts.attr,
464482069379SAkinobu Mita 	&driver_attr_every_nth.attr,
464582069379SAkinobu Mita 	&driver_attr_max_luns.attr,
464682069379SAkinobu Mita 	&driver_attr_max_queue.attr,
464782069379SAkinobu Mita 	&driver_attr_no_uld.attr,
464882069379SAkinobu Mita 	&driver_attr_scsi_level.attr,
464982069379SAkinobu Mita 	&driver_attr_virtual_gb.attr,
465082069379SAkinobu Mita 	&driver_attr_add_host.attr,
465182069379SAkinobu Mita 	&driver_attr_vpd_use_hostno.attr,
465282069379SAkinobu Mita 	&driver_attr_sector_size.attr,
465382069379SAkinobu Mita 	&driver_attr_dix.attr,
465482069379SAkinobu Mita 	&driver_attr_dif.attr,
465582069379SAkinobu Mita 	&driver_attr_guard.attr,
465682069379SAkinobu Mita 	&driver_attr_ato.attr,
465782069379SAkinobu Mita 	&driver_attr_map.attr,
465882069379SAkinobu Mita 	&driver_attr_removable.attr,
4659cbf67842SDouglas Gilbert 	&driver_attr_host_lock.attr,
4660cbf67842SDouglas Gilbert 	&driver_attr_ndelay.attr,
4661c2248fc9SDouglas Gilbert 	&driver_attr_strict.attr,
466282069379SAkinobu Mita 	NULL,
466382069379SAkinobu Mita };
466482069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv);
46651da177e4SLinus Torvalds 
466611ddcecaSAkinobu Mita static struct device *pseudo_primary;
46678dea0d02SFUJITA Tomonori 
46681da177e4SLinus Torvalds static int __init scsi_debug_init(void)
46691da177e4SLinus Torvalds {
46705f2578e5SFUJITA Tomonori 	unsigned long sz;
46711da177e4SLinus Torvalds 	int host_to_add;
46721da177e4SLinus Torvalds 	int k;
46736ecaff7fSRandy Dunlap 	int ret;
46741da177e4SLinus Torvalds 
4675cbf67842SDouglas Gilbert 	atomic_set(&sdebug_cmnd_count, 0);
4676cbf67842SDouglas Gilbert 	atomic_set(&sdebug_completions, 0);
4677cbf67842SDouglas Gilbert 	atomic_set(&retired_max_queue, 0);
4678cbf67842SDouglas Gilbert 
4679773642d9SDouglas Gilbert 	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
4680c1287970STomas Winkler 		pr_warn("ndelay must be less than 1 second, ignored\n");
4681773642d9SDouglas Gilbert 		sdebug_ndelay = 0;
4682773642d9SDouglas Gilbert 	} else if (sdebug_ndelay > 0)
4683773642d9SDouglas Gilbert 		sdebug_delay = DELAY_OVERRIDDEN;
4684cbf67842SDouglas Gilbert 
4685773642d9SDouglas Gilbert 	switch (sdebug_sector_size) {
4686597136abSMartin K. Petersen 	case  512:
4687597136abSMartin K. Petersen 	case 1024:
4688597136abSMartin K. Petersen 	case 2048:
4689597136abSMartin K. Petersen 	case 4096:
4690597136abSMartin K. Petersen 		break;
4691597136abSMartin K. Petersen 	default:
4692773642d9SDouglas Gilbert 		pr_err("invalid sector_size %d\n", sdebug_sector_size);
4693597136abSMartin K. Petersen 		return -EINVAL;
4694597136abSMartin K. Petersen 	}
4695597136abSMartin K. Petersen 
4696773642d9SDouglas Gilbert 	switch (sdebug_dif) {
4697c6a44287SMartin K. Petersen 
4698c6a44287SMartin K. Petersen 	case SD_DIF_TYPE0_PROTECTION:
4699c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
4700395cef03SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
4701c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
4702c6a44287SMartin K. Petersen 		break;
4703c6a44287SMartin K. Petersen 
4704c6a44287SMartin K. Petersen 	default:
4705c1287970STomas Winkler 		pr_err("dif must be 0, 1, 2 or 3\n");
4706c6a44287SMartin K. Petersen 		return -EINVAL;
4707c6a44287SMartin K. Petersen 	}
4708c6a44287SMartin K. Petersen 
4709773642d9SDouglas Gilbert 	if (sdebug_guard > 1) {
4710c1287970STomas Winkler 		pr_err("guard must be 0 or 1\n");
4711c6a44287SMartin K. Petersen 		return -EINVAL;
4712c6a44287SMartin K. Petersen 	}
4713c6a44287SMartin K. Petersen 
4714773642d9SDouglas Gilbert 	if (sdebug_ato > 1) {
4715c1287970STomas Winkler 		pr_err("ato must be 0 or 1\n");
4716c6a44287SMartin K. Petersen 		return -EINVAL;
4717c6a44287SMartin K. Petersen 	}
4718c6a44287SMartin K. Petersen 
4719773642d9SDouglas Gilbert 	if (sdebug_physblk_exp > 15) {
4720773642d9SDouglas Gilbert 		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
4721ea61fca5SMartin K. Petersen 		return -EINVAL;
4722ea61fca5SMartin K. Petersen 	}
4723ea61fca5SMartin K. Petersen 
4724773642d9SDouglas Gilbert 	if (sdebug_lowest_aligned > 0x3fff) {
4725773642d9SDouglas Gilbert 		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
4726ea61fca5SMartin K. Petersen 		return -EINVAL;
4727ea61fca5SMartin K. Petersen 	}
4728ea61fca5SMartin K. Petersen 
4729773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb < 1)
4730773642d9SDouglas Gilbert 		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
4731773642d9SDouglas Gilbert 	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4732773642d9SDouglas Gilbert 	sdebug_store_sectors = sz / sdebug_sector_size;
473328898873SFUJITA Tomonori 	sdebug_capacity = get_sdebug_capacity();
47341da177e4SLinus Torvalds 
47351da177e4SLinus Torvalds 	/* play around with geometry, don't waste too much on track 0 */
47361da177e4SLinus Torvalds 	sdebug_heads = 8;
47371da177e4SLinus Torvalds 	sdebug_sectors_per = 32;
4738773642d9SDouglas Gilbert 	if (sdebug_dev_size_mb >= 256)
47391da177e4SLinus Torvalds 		sdebug_heads = 64;
4740773642d9SDouglas Gilbert 	else if (sdebug_dev_size_mb >= 16)
4741fa785f0aSAndy Shevchenko 		sdebug_heads = 32;
47421da177e4SLinus Torvalds 	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
47431da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
47441da177e4SLinus Torvalds 	if (sdebug_cylinders_per >= 1024) {
47451da177e4SLinus Torvalds 		/* other LLDs do this; implies >= 1GB ram disk ... */
47461da177e4SLinus Torvalds 		sdebug_heads = 255;
47471da177e4SLinus Torvalds 		sdebug_sectors_per = 63;
47481da177e4SLinus Torvalds 		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
47491da177e4SLinus Torvalds 			       (sdebug_sectors_per * sdebug_heads);
47501da177e4SLinus Torvalds 	}
47511da177e4SLinus Torvalds 
4752773642d9SDouglas Gilbert 	if (0 == sdebug_fake_rw) {
47531da177e4SLinus Torvalds 		fake_storep = vmalloc(sz);
47541da177e4SLinus Torvalds 		if (NULL == fake_storep) {
4755c1287970STomas Winkler 			pr_err("out of memory, 1\n");
47561da177e4SLinus Torvalds 			return -ENOMEM;
47571da177e4SLinus Torvalds 		}
47581da177e4SLinus Torvalds 		memset(fake_storep, 0, sz);
4759773642d9SDouglas Gilbert 		if (sdebug_num_parts > 0)
4760f58b0efbSFUJITA Tomonori 			sdebug_build_parts(fake_storep, sz);
4761cbf67842SDouglas Gilbert 	}
47621da177e4SLinus Torvalds 
4763773642d9SDouglas Gilbert 	if (sdebug_dix) {
4764c6a44287SMartin K. Petersen 		int dif_size;
4765c6a44287SMartin K. Petersen 
4766c6a44287SMartin K. Petersen 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4767c6a44287SMartin K. Petersen 		dif_storep = vmalloc(dif_size);
4768c6a44287SMartin K. Petersen 
4769c1287970STomas Winkler 		pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
4770c6a44287SMartin K. Petersen 
4771c6a44287SMartin K. Petersen 		if (dif_storep == NULL) {
4772c1287970STomas Winkler 			pr_err("out of mem. (DIX)\n");
4773c6a44287SMartin K. Petersen 			ret = -ENOMEM;
4774c6a44287SMartin K. Petersen 			goto free_vm;
4775c6a44287SMartin K. Petersen 		}
4776c6a44287SMartin K. Petersen 
4777c6a44287SMartin K. Petersen 		memset(dif_storep, 0xff, dif_size);
4778c6a44287SMartin K. Petersen 	}
4779c6a44287SMartin K. Petersen 
47805b94e232SMartin K. Petersen 	/* Logical Block Provisioning */
47815b94e232SMartin K. Petersen 	if (scsi_debug_lbp()) {
4782773642d9SDouglas Gilbert 		sdebug_unmap_max_blocks =
4783773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
47846014759cSMartin K. Petersen 
4785773642d9SDouglas Gilbert 		sdebug_unmap_max_desc =
4786773642d9SDouglas Gilbert 			clamp(sdebug_unmap_max_desc, 0U, 256U);
47876014759cSMartin K. Petersen 
4788773642d9SDouglas Gilbert 		sdebug_unmap_granularity =
4789773642d9SDouglas Gilbert 			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
47906014759cSMartin K. Petersen 
4791773642d9SDouglas Gilbert 		if (sdebug_unmap_alignment &&
4792773642d9SDouglas Gilbert 		    sdebug_unmap_granularity <=
4793773642d9SDouglas Gilbert 		    sdebug_unmap_alignment) {
4794c1287970STomas Winkler 			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
479544d92694SMartin K. Petersen 			return -EINVAL;
479644d92694SMartin K. Petersen 		}
479744d92694SMartin K. Petersen 
4798b90ebc3dSAkinobu Mita 		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4799b90ebc3dSAkinobu Mita 		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
480044d92694SMartin K. Petersen 
4801c1287970STomas Winkler 		pr_info("%lu provisioning blocks\n", map_size);
480244d92694SMartin K. Petersen 
480344d92694SMartin K. Petersen 		if (map_storep == NULL) {
4804c1287970STomas Winkler 			pr_err("out of mem. (MAP)\n");
480544d92694SMartin K. Petersen 			ret = -ENOMEM;
480644d92694SMartin K. Petersen 			goto free_vm;
480744d92694SMartin K. Petersen 		}
480844d92694SMartin K. Petersen 
4809b90ebc3dSAkinobu Mita 		bitmap_zero(map_storep, map_size);
481044d92694SMartin K. Petersen 
481144d92694SMartin K. Petersen 		/* Map first 1KB for partition table */
4812773642d9SDouglas Gilbert 		if (sdebug_num_parts)
481344d92694SMartin K. Petersen 			map_region(0, 2);
481444d92694SMartin K. Petersen 	}
481544d92694SMartin K. Petersen 
48169b906779SNicholas Bellinger 	pseudo_primary = root_device_register("pseudo_0");
48179b906779SNicholas Bellinger 	if (IS_ERR(pseudo_primary)) {
4818c1287970STomas Winkler 		pr_warn("root_device_register() error\n");
48199b906779SNicholas Bellinger 		ret = PTR_ERR(pseudo_primary);
48206ecaff7fSRandy Dunlap 		goto free_vm;
48216ecaff7fSRandy Dunlap 	}
48226ecaff7fSRandy Dunlap 	ret = bus_register(&pseudo_lld_bus);
48236ecaff7fSRandy Dunlap 	if (ret < 0) {
4824c1287970STomas Winkler 		pr_warn("bus_register error: %d\n", ret);
48256ecaff7fSRandy Dunlap 		goto dev_unreg;
48266ecaff7fSRandy Dunlap 	}
48276ecaff7fSRandy Dunlap 	ret = driver_register(&sdebug_driverfs_driver);
48286ecaff7fSRandy Dunlap 	if (ret < 0) {
4829c1287970STomas Winkler 		pr_warn("driver_register error: %d\n", ret);
48306ecaff7fSRandy Dunlap 		goto bus_unreg;
48316ecaff7fSRandy Dunlap 	}
48321da177e4SLinus Torvalds 
4833773642d9SDouglas Gilbert 	host_to_add = sdebug_add_host;
4834773642d9SDouglas Gilbert 	sdebug_add_host = 0;
48351da177e4SLinus Torvalds 
48361da177e4SLinus Torvalds         for (k = 0; k < host_to_add; k++) {
48371da177e4SLinus Torvalds                 if (sdebug_add_adapter()) {
4838c1287970STomas Winkler 			pr_err("sdebug_add_adapter failed k=%d\n", k);
48391da177e4SLinus Torvalds                         break;
48401da177e4SLinus Torvalds                 }
48411da177e4SLinus Torvalds         }
48421da177e4SLinus Torvalds 
4843773642d9SDouglas Gilbert 	if (sdebug_verbose)
4844773642d9SDouglas Gilbert 		pr_info("built %d host(s)\n", sdebug_add_host);
4845c1287970STomas Winkler 
48461da177e4SLinus Torvalds 	return 0;
48476ecaff7fSRandy Dunlap 
48486ecaff7fSRandy Dunlap bus_unreg:
48496ecaff7fSRandy Dunlap 	bus_unregister(&pseudo_lld_bus);
48506ecaff7fSRandy Dunlap dev_unreg:
48519b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
48526ecaff7fSRandy Dunlap free_vm:
485344d92694SMartin K. Petersen 	vfree(map_storep);
4854c6a44287SMartin K. Petersen 	vfree(dif_storep);
48556ecaff7fSRandy Dunlap 	vfree(fake_storep);
48566ecaff7fSRandy Dunlap 
48576ecaff7fSRandy Dunlap 	return ret;
48581da177e4SLinus Torvalds }
48591da177e4SLinus Torvalds 
48601da177e4SLinus Torvalds static void __exit scsi_debug_exit(void)
48611da177e4SLinus Torvalds {
4862773642d9SDouglas Gilbert 	int k = sdebug_add_host;
48631da177e4SLinus Torvalds 
48641da177e4SLinus Torvalds 	stop_all_queued();
4865cbf67842SDouglas Gilbert 	free_all_queued();
48661da177e4SLinus Torvalds 	for (; k; k--)
48671da177e4SLinus Torvalds 		sdebug_remove_adapter();
48681da177e4SLinus Torvalds 	driver_unregister(&sdebug_driverfs_driver);
48691da177e4SLinus Torvalds 	bus_unregister(&pseudo_lld_bus);
48709b906779SNicholas Bellinger 	root_device_unregister(pseudo_primary);
48711da177e4SLinus Torvalds 
4872c6a44287SMartin K. Petersen 	vfree(dif_storep);
48731da177e4SLinus Torvalds 	vfree(fake_storep);
48741da177e4SLinus Torvalds }
48751da177e4SLinus Torvalds 
48761da177e4SLinus Torvalds device_initcall(scsi_debug_init);
48771da177e4SLinus Torvalds module_exit(scsi_debug_exit);
48781da177e4SLinus Torvalds 
48791da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev)
48801da177e4SLinus Torvalds {
48811da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
48821da177e4SLinus Torvalds 
48831da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
48841da177e4SLinus Torvalds         kfree(sdbg_host);
48851da177e4SLinus Torvalds }
48861da177e4SLinus Torvalds 
48871da177e4SLinus Torvalds static int sdebug_add_adapter(void)
48881da177e4SLinus Torvalds {
48891da177e4SLinus Torvalds 	int k, devs_per_host;
48901da177e4SLinus Torvalds         int error = 0;
48911da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
48928b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
48931da177e4SLinus Torvalds 
489424669f75SJes Sorensen         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
48951da177e4SLinus Torvalds         if (NULL == sdbg_host) {
4896c1287970STomas Winkler 		pr_err("out of memory at line %d\n", __LINE__);
48971da177e4SLinus Torvalds                 return -ENOMEM;
48981da177e4SLinus Torvalds         }
48991da177e4SLinus Torvalds 
49001da177e4SLinus Torvalds         INIT_LIST_HEAD(&sdbg_host->dev_info_list);
49011da177e4SLinus Torvalds 
4902773642d9SDouglas Gilbert 	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
49031da177e4SLinus Torvalds         for (k = 0; k < devs_per_host; k++) {
49045cb2fc06SFUJITA Tomonori 		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
49055cb2fc06SFUJITA Tomonori 		if (!sdbg_devinfo) {
4906c1287970STomas Winkler 			pr_err("out of memory at line %d\n", __LINE__);
49071da177e4SLinus Torvalds                         error = -ENOMEM;
49081da177e4SLinus Torvalds 			goto clean;
49091da177e4SLinus Torvalds                 }
49101da177e4SLinus Torvalds         }
49111da177e4SLinus Torvalds 
49121da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
49131da177e4SLinus Torvalds         list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
49141da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
49151da177e4SLinus Torvalds 
49161da177e4SLinus Torvalds         sdbg_host->dev.bus = &pseudo_lld_bus;
49179b906779SNicholas Bellinger         sdbg_host->dev.parent = pseudo_primary;
49181da177e4SLinus Torvalds         sdbg_host->dev.release = &sdebug_release_adapter;
4919773642d9SDouglas Gilbert 	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
49201da177e4SLinus Torvalds 
49211da177e4SLinus Torvalds         error = device_register(&sdbg_host->dev);
49221da177e4SLinus Torvalds 
49231da177e4SLinus Torvalds         if (error)
49241da177e4SLinus Torvalds 		goto clean;
49251da177e4SLinus Torvalds 
4926773642d9SDouglas Gilbert 	++sdebug_add_host;
49271da177e4SLinus Torvalds         return error;
49281da177e4SLinus Torvalds 
49291da177e4SLinus Torvalds clean:
49308b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
49318b40228fSFUJITA Tomonori 				 dev_list) {
49321da177e4SLinus Torvalds 		list_del(&sdbg_devinfo->dev_list);
49331da177e4SLinus Torvalds 		kfree(sdbg_devinfo);
49341da177e4SLinus Torvalds 	}
49351da177e4SLinus Torvalds 
49361da177e4SLinus Torvalds 	kfree(sdbg_host);
49371da177e4SLinus Torvalds         return error;
49381da177e4SLinus Torvalds }
49391da177e4SLinus Torvalds 
49401da177e4SLinus Torvalds static void sdebug_remove_adapter(void)
49411da177e4SLinus Torvalds {
49421da177e4SLinus Torvalds         struct sdebug_host_info * sdbg_host = NULL;
49431da177e4SLinus Torvalds 
49441da177e4SLinus Torvalds         spin_lock(&sdebug_host_list_lock);
49451da177e4SLinus Torvalds         if (!list_empty(&sdebug_host_list)) {
49461da177e4SLinus Torvalds                 sdbg_host = list_entry(sdebug_host_list.prev,
49471da177e4SLinus Torvalds                                        struct sdebug_host_info, host_list);
49481da177e4SLinus Torvalds 		list_del(&sdbg_host->host_list);
49491da177e4SLinus Torvalds 	}
49501da177e4SLinus Torvalds         spin_unlock(&sdebug_host_list_lock);
49511da177e4SLinus Torvalds 
49521da177e4SLinus Torvalds 	if (!sdbg_host)
49531da177e4SLinus Torvalds 		return;
49541da177e4SLinus Torvalds 
49551da177e4SLinus Torvalds 	device_unregister(&sdbg_host->dev);
4956773642d9SDouglas Gilbert 	--sdebug_add_host;
49571da177e4SLinus Torvalds }
49581da177e4SLinus Torvalds 
4959cbf67842SDouglas Gilbert static int
4960db5ed4dfSChristoph Hellwig sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
4961cbf67842SDouglas Gilbert {
4962cbf67842SDouglas Gilbert 	int num_in_q = 0;
4963cbf67842SDouglas Gilbert 	unsigned long iflags;
4964cbf67842SDouglas Gilbert 	struct sdebug_dev_info *devip;
4965cbf67842SDouglas Gilbert 
4966cbf67842SDouglas Gilbert 	spin_lock_irqsave(&queued_arr_lock, iflags);
4967cbf67842SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdev->hostdata;
4968cbf67842SDouglas Gilbert 	if (NULL == devip) {
4969cbf67842SDouglas Gilbert 		spin_unlock_irqrestore(&queued_arr_lock, iflags);
4970cbf67842SDouglas Gilbert 		return	-ENODEV;
4971cbf67842SDouglas Gilbert 	}
4972cbf67842SDouglas Gilbert 	num_in_q = atomic_read(&devip->num_in_q);
4973cbf67842SDouglas Gilbert 	spin_unlock_irqrestore(&queued_arr_lock, iflags);
4974c40ecc12SChristoph Hellwig 
4975cbf67842SDouglas Gilbert 	if (qdepth < 1)
4976cbf67842SDouglas Gilbert 		qdepth = 1;
4977cbf67842SDouglas Gilbert 	/* allow to exceed max host queued_arr elements for testing */
4978cbf67842SDouglas Gilbert 	if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4979cbf67842SDouglas Gilbert 		qdepth = SCSI_DEBUG_CANQUEUE + 10;
4980db5ed4dfSChristoph Hellwig 	scsi_change_queue_depth(sdev, qdepth);
4981cbf67842SDouglas Gilbert 
4982773642d9SDouglas Gilbert 	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
4983cbf67842SDouglas Gilbert 		sdev_printk(KERN_INFO, sdev,
4984c40ecc12SChristoph Hellwig 			    "%s: qdepth=%d, num_in_q=%d\n",
4985c40ecc12SChristoph Hellwig 			    __func__, qdepth, num_in_q);
4986cbf67842SDouglas Gilbert 	}
4987cbf67842SDouglas Gilbert 	return sdev->queue_depth;
4988cbf67842SDouglas Gilbert }
4989cbf67842SDouglas Gilbert 
4990cbf67842SDouglas Gilbert static int
4991817fd66bSDouglas Gilbert check_inject(struct scsi_cmnd *scp)
4992817fd66bSDouglas Gilbert {
4993817fd66bSDouglas Gilbert 	struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4994817fd66bSDouglas Gilbert 
4995817fd66bSDouglas Gilbert 	memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4996817fd66bSDouglas Gilbert 
4997773642d9SDouglas Gilbert 	if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
4998817fd66bSDouglas Gilbert 		atomic_set(&sdebug_cmnd_count, 0);
4999773642d9SDouglas Gilbert 		if (sdebug_every_nth < -1)
5000773642d9SDouglas Gilbert 			sdebug_every_nth = -1;
5001773642d9SDouglas Gilbert 		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
5002817fd66bSDouglas Gilbert 			return 1; /* ignore command causing timeout */
5003773642d9SDouglas Gilbert 		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
5004817fd66bSDouglas Gilbert 			 scsi_medium_access_command(scp))
5005817fd66bSDouglas Gilbert 			return 1; /* time out reads and writes */
5006817fd66bSDouglas Gilbert 		if (sdebug_any_injecting_opt) {
5007773642d9SDouglas Gilbert 			if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
5008817fd66bSDouglas Gilbert 				ep->inj_recovered = true;
5009773642d9SDouglas Gilbert 			if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
5010817fd66bSDouglas Gilbert 				ep->inj_transport = true;
5011773642d9SDouglas Gilbert 			if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
5012817fd66bSDouglas Gilbert 				ep->inj_dif = true;
5013773642d9SDouglas Gilbert 			if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
5014817fd66bSDouglas Gilbert 				ep->inj_dix = true;
5015773642d9SDouglas Gilbert 			if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
5016817fd66bSDouglas Gilbert 				ep->inj_short = true;
5017817fd66bSDouglas Gilbert 		}
5018817fd66bSDouglas Gilbert 	}
5019817fd66bSDouglas Gilbert 	return 0;
5020817fd66bSDouglas Gilbert }
5021817fd66bSDouglas Gilbert 
5022c2248fc9SDouglas Gilbert static int
5023185dd232SDouglas Gilbert scsi_debug_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scp)
5024c2248fc9SDouglas Gilbert {
5025c2248fc9SDouglas Gilbert 	u8 sdeb_i;
5026c2248fc9SDouglas Gilbert 	struct scsi_device *sdp = scp->device;
5027c2248fc9SDouglas Gilbert 	const struct opcode_info_t *oip;
5028c2248fc9SDouglas Gilbert 	const struct opcode_info_t *r_oip;
5029c2248fc9SDouglas Gilbert 	struct sdebug_dev_info *devip;
5030c2248fc9SDouglas Gilbert 	u8 *cmd = scp->cmnd;
5031c2248fc9SDouglas Gilbert 	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5032c2248fc9SDouglas Gilbert 	int k, na;
5033c2248fc9SDouglas Gilbert 	int errsts = 0;
5034c2248fc9SDouglas Gilbert 	u32 flags;
5035c2248fc9SDouglas Gilbert 	u16 sa;
5036c2248fc9SDouglas Gilbert 	u8 opcode = cmd[0];
5037c2248fc9SDouglas Gilbert 	bool has_wlun_rl;
5038c2248fc9SDouglas Gilbert 
5039c2248fc9SDouglas Gilbert 	scsi_set_resid(scp, 0);
5040773642d9SDouglas Gilbert 	if (sdebug_verbose && !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts)) {
5041c2248fc9SDouglas Gilbert 		char b[120];
5042c2248fc9SDouglas Gilbert 		int n, len, sb;
5043c2248fc9SDouglas Gilbert 
5044c2248fc9SDouglas Gilbert 		len = scp->cmd_len;
5045c2248fc9SDouglas Gilbert 		sb = (int)sizeof(b);
5046c2248fc9SDouglas Gilbert 		if (len > 32)
5047c2248fc9SDouglas Gilbert 			strcpy(b, "too long, over 32 bytes");
5048c2248fc9SDouglas Gilbert 		else {
5049c2248fc9SDouglas Gilbert 			for (k = 0, n = 0; k < len && n < sb; ++k)
5050c2248fc9SDouglas Gilbert 				n += scnprintf(b + n, sb - n, "%02x ",
5051c2248fc9SDouglas Gilbert 					       (u32)cmd[k]);
5052c2248fc9SDouglas Gilbert 		}
5053c2248fc9SDouglas Gilbert 		sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
5054c2248fc9SDouglas Gilbert 	}
505534d55434STomas Winkler 	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
5056773642d9SDouglas Gilbert 	if ((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)
5057773642d9SDouglas Gilbert 		return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
5058c2248fc9SDouglas Gilbert 
5059c2248fc9SDouglas Gilbert 	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
5060c2248fc9SDouglas Gilbert 	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
5061c2248fc9SDouglas Gilbert 	devip = (struct sdebug_dev_info *)sdp->hostdata;
5062c2248fc9SDouglas Gilbert 	if (!devip) {
5063c2248fc9SDouglas Gilbert 		devip = devInfoReg(sdp);
5064c2248fc9SDouglas Gilbert 		if (NULL == devip)
5065773642d9SDouglas Gilbert 			return schedule_resp(scp, NULL, DID_NO_CONNECT << 16,
5066773642d9SDouglas Gilbert 					     0);
5067c2248fc9SDouglas Gilbert 	}
5068c2248fc9SDouglas Gilbert 	na = oip->num_attached;
5069c2248fc9SDouglas Gilbert 	r_pfp = oip->pfp;
5070c2248fc9SDouglas Gilbert 	if (na) {	/* multiple commands with this opcode */
5071c2248fc9SDouglas Gilbert 		r_oip = oip;
5072c2248fc9SDouglas Gilbert 		if (FF_SA & r_oip->flags) {
5073c2248fc9SDouglas Gilbert 			if (F_SA_LOW & oip->flags)
5074c2248fc9SDouglas Gilbert 				sa = 0x1f & cmd[1];
5075c2248fc9SDouglas Gilbert 			else
5076c2248fc9SDouglas Gilbert 				sa = get_unaligned_be16(cmd + 8);
5077c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5078c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode && sa == oip->sa)
5079c2248fc9SDouglas Gilbert 					break;
5080c2248fc9SDouglas Gilbert 			}
5081c2248fc9SDouglas Gilbert 		} else {   /* since no service action only check opcode */
5082c2248fc9SDouglas Gilbert 			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5083c2248fc9SDouglas Gilbert 				if (opcode == oip->opcode)
5084c2248fc9SDouglas Gilbert 					break;
5085c2248fc9SDouglas Gilbert 			}
5086c2248fc9SDouglas Gilbert 		}
5087c2248fc9SDouglas Gilbert 		if (k > na) {
5088c2248fc9SDouglas Gilbert 			if (F_SA_LOW & r_oip->flags)
5089c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5090c2248fc9SDouglas Gilbert 			else if (F_SA_HIGH & r_oip->flags)
5091c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5092c2248fc9SDouglas Gilbert 			else
5093c2248fc9SDouglas Gilbert 				mk_sense_invalid_opcode(scp);
5094c2248fc9SDouglas Gilbert 			goto check_cond;
5095c2248fc9SDouglas Gilbert 		}
5096c2248fc9SDouglas Gilbert 	}	/* else (when na==0) we assume the oip is a match */
5097c2248fc9SDouglas Gilbert 	flags = oip->flags;
5098c2248fc9SDouglas Gilbert 	if (F_INV_OP & flags) {
5099c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5100c2248fc9SDouglas Gilbert 		goto check_cond;
5101c2248fc9SDouglas Gilbert 	}
5102c2248fc9SDouglas Gilbert 	if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) {
5103773642d9SDouglas Gilbert 		if (sdebug_verbose)
5104773642d9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5105773642d9SDouglas Gilbert 				    my_name, opcode, " supported for wlun");
5106c2248fc9SDouglas Gilbert 		mk_sense_invalid_opcode(scp);
5107c2248fc9SDouglas Gilbert 		goto check_cond;
5108c2248fc9SDouglas Gilbert 	}
5109773642d9SDouglas Gilbert 	if (sdebug_strict) {	/* check cdb against mask */
5110c2248fc9SDouglas Gilbert 		u8 rem;
5111c2248fc9SDouglas Gilbert 		int j;
5112c2248fc9SDouglas Gilbert 
5113c2248fc9SDouglas Gilbert 		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5114c2248fc9SDouglas Gilbert 			rem = ~oip->len_mask[k] & cmd[k];
5115c2248fc9SDouglas Gilbert 			if (rem) {
5116c2248fc9SDouglas Gilbert 				for (j = 7; j >= 0; --j, rem <<= 1) {
5117c2248fc9SDouglas Gilbert 					if (0x80 & rem)
5118c2248fc9SDouglas Gilbert 						break;
5119c2248fc9SDouglas Gilbert 				}
5120c2248fc9SDouglas Gilbert 				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5121c2248fc9SDouglas Gilbert 				goto check_cond;
5122c2248fc9SDouglas Gilbert 			}
5123c2248fc9SDouglas Gilbert 		}
5124c2248fc9SDouglas Gilbert 	}
5125c2248fc9SDouglas Gilbert 	if (!(F_SKIP_UA & flags) &&
5126c2248fc9SDouglas Gilbert 	    SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) {
5127c2248fc9SDouglas Gilbert 		errsts = check_readiness(scp, UAS_ONLY, devip);
5128c2248fc9SDouglas Gilbert 		if (errsts)
5129c2248fc9SDouglas Gilbert 			goto check_cond;
5130c2248fc9SDouglas Gilbert 	}
5131c2248fc9SDouglas Gilbert 	if ((F_M_ACCESS & flags) && devip->stopped) {
5132c2248fc9SDouglas Gilbert 		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
5133773642d9SDouglas Gilbert 		if (sdebug_verbose)
5134c2248fc9SDouglas Gilbert 			sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5135c2248fc9SDouglas Gilbert 				    "%s\n", my_name, "initializing command "
5136c2248fc9SDouglas Gilbert 				    "required");
5137c2248fc9SDouglas Gilbert 		errsts = check_condition_result;
5138c2248fc9SDouglas Gilbert 		goto fini;
5139c2248fc9SDouglas Gilbert 	}
5140773642d9SDouglas Gilbert 	if (sdebug_fake_rw && (F_FAKE_RW & flags))
5141c2248fc9SDouglas Gilbert 		goto fini;
5142773642d9SDouglas Gilbert 	if (sdebug_every_nth) {
5143c2248fc9SDouglas Gilbert 		if (check_inject(scp))
5144c2248fc9SDouglas Gilbert 			return 0;	/* ignore command: make trouble */
5145c2248fc9SDouglas Gilbert 	}
5146c2248fc9SDouglas Gilbert 	if (oip->pfp)	/* if this command has a resp_* function, call it */
5147c2248fc9SDouglas Gilbert 		errsts = oip->pfp(scp, devip);
5148c2248fc9SDouglas Gilbert 	else if (r_pfp)	/* if leaf function ptr NULL, try the root's */
5149c2248fc9SDouglas Gilbert 		errsts = r_pfp(scp, devip);
5150c2248fc9SDouglas Gilbert 
5151c2248fc9SDouglas Gilbert fini:
5152c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, errsts,
5153773642d9SDouglas Gilbert 			     ((F_DELAY_OVERR & flags) ? 0 : sdebug_delay));
5154c2248fc9SDouglas Gilbert check_cond:
5155c2248fc9SDouglas Gilbert 	return schedule_resp(scp, devip, check_condition_result, 0);
5156c2248fc9SDouglas Gilbert }
5157c2248fc9SDouglas Gilbert 
51589e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = {
5159c8ed555aSAl Viro 	.show_info =		scsi_debug_show_info,
5160c8ed555aSAl Viro 	.write_info =		scsi_debug_write_info,
51619e603ca0SFUJITA Tomonori 	.proc_name =		sdebug_proc_name,
51629e603ca0SFUJITA Tomonori 	.name =			"SCSI DEBUG",
51639e603ca0SFUJITA Tomonori 	.info =			scsi_debug_info,
51649e603ca0SFUJITA Tomonori 	.slave_alloc =		scsi_debug_slave_alloc,
51659e603ca0SFUJITA Tomonori 	.slave_configure =	scsi_debug_slave_configure,
51669e603ca0SFUJITA Tomonori 	.slave_destroy =	scsi_debug_slave_destroy,
51679e603ca0SFUJITA Tomonori 	.ioctl =		scsi_debug_ioctl,
5168185dd232SDouglas Gilbert 	.queuecommand =		scsi_debug_queuecommand,
5169cbf67842SDouglas Gilbert 	.change_queue_depth =	sdebug_change_qdepth,
51709e603ca0SFUJITA Tomonori 	.eh_abort_handler =	scsi_debug_abort,
51719e603ca0SFUJITA Tomonori 	.eh_device_reset_handler = scsi_debug_device_reset,
5172cbf67842SDouglas Gilbert 	.eh_target_reset_handler = scsi_debug_target_reset,
5173cbf67842SDouglas Gilbert 	.eh_bus_reset_handler = scsi_debug_bus_reset,
51749e603ca0SFUJITA Tomonori 	.eh_host_reset_handler = scsi_debug_host_reset,
51759e603ca0SFUJITA Tomonori 	.can_queue =		SCSI_DEBUG_CANQUEUE,
51769e603ca0SFUJITA Tomonori 	.this_id =		7,
517765e8617fSMing Lin 	.sg_tablesize =		SG_MAX_SEGMENTS,
5178cbf67842SDouglas Gilbert 	.cmd_per_lun =		DEF_CMD_PER_LUN,
51796bb5e6e7SAkinobu Mita 	.max_sectors =		-1U,
51809e603ca0SFUJITA Tomonori 	.use_clustering = 	DISABLE_CLUSTERING,
51819e603ca0SFUJITA Tomonori 	.module =		THIS_MODULE,
5182c40ecc12SChristoph Hellwig 	.track_queue_depth =	1,
5183817fd66bSDouglas Gilbert 	.cmd_size =		sizeof(struct sdebug_scmd_extra_t),
51849e603ca0SFUJITA Tomonori };
51859e603ca0SFUJITA Tomonori 
51861da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev)
51871da177e4SLinus Torvalds {
51881da177e4SLinus Torvalds 	int error = 0;
51891da177e4SLinus Torvalds 	struct sdebug_host_info *sdbg_host;
51901da177e4SLinus Torvalds 	struct Scsi_Host *hpnt;
5191c6a44287SMartin K. Petersen 	int host_prot;
51921da177e4SLinus Torvalds 
51931da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
51941da177e4SLinus Torvalds 
5195773642d9SDouglas Gilbert 	sdebug_driver_template.can_queue = sdebug_max_queue;
5196773642d9SDouglas Gilbert 	if (sdebug_clustering)
51970759c666SAkinobu Mita 		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
51981da177e4SLinus Torvalds 	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
51991da177e4SLinus Torvalds 	if (NULL == hpnt) {
5200c1287970STomas Winkler 		pr_err("scsi_host_alloc failed\n");
52011da177e4SLinus Torvalds 		error = -ENODEV;
52021da177e4SLinus Torvalds 		return error;
52031da177e4SLinus Torvalds 	}
52041da177e4SLinus Torvalds 
52051da177e4SLinus Torvalds         sdbg_host->shost = hpnt;
52061da177e4SLinus Torvalds 	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
5207773642d9SDouglas Gilbert 	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5208773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts + 1;
52091da177e4SLinus Torvalds 	else
5210773642d9SDouglas Gilbert 		hpnt->max_id = sdebug_num_tgts;
5211773642d9SDouglas Gilbert 	/* = sdebug_max_luns; */
5212f2d3fd29STomas Winkler 	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
52131da177e4SLinus Torvalds 
5214c6a44287SMartin K. Petersen 	host_prot = 0;
5215c6a44287SMartin K. Petersen 
5216773642d9SDouglas Gilbert 	switch (sdebug_dif) {
5217c6a44287SMartin K. Petersen 
5218c6a44287SMartin K. Petersen 	case SD_DIF_TYPE1_PROTECTION:
5219c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE1_PROTECTION;
5220773642d9SDouglas Gilbert 		if (sdebug_dix)
5221c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE1_PROTECTION;
5222c6a44287SMartin K. Petersen 		break;
5223c6a44287SMartin K. Petersen 
5224c6a44287SMartin K. Petersen 	case SD_DIF_TYPE2_PROTECTION:
5225c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE2_PROTECTION;
5226773642d9SDouglas Gilbert 		if (sdebug_dix)
5227c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE2_PROTECTION;
5228c6a44287SMartin K. Petersen 		break;
5229c6a44287SMartin K. Petersen 
5230c6a44287SMartin K. Petersen 	case SD_DIF_TYPE3_PROTECTION:
5231c6a44287SMartin K. Petersen 		host_prot = SHOST_DIF_TYPE3_PROTECTION;
5232773642d9SDouglas Gilbert 		if (sdebug_dix)
5233c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE3_PROTECTION;
5234c6a44287SMartin K. Petersen 		break;
5235c6a44287SMartin K. Petersen 
5236c6a44287SMartin K. Petersen 	default:
5237773642d9SDouglas Gilbert 		if (sdebug_dix)
5238c6a44287SMartin K. Petersen 			host_prot |= SHOST_DIX_TYPE0_PROTECTION;
5239c6a44287SMartin K. Petersen 		break;
5240c6a44287SMartin K. Petersen 	}
5241c6a44287SMartin K. Petersen 
5242c6a44287SMartin K. Petersen 	scsi_host_set_prot(hpnt, host_prot);
5243c6a44287SMartin K. Petersen 
5244c1287970STomas Winkler 	pr_info("host protection%s%s%s%s%s%s%s\n",
5245c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5246c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5247c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5248c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5249c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5250c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5251c6a44287SMartin K. Petersen 	       (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5252c6a44287SMartin K. Petersen 
5253773642d9SDouglas Gilbert 	if (sdebug_guard == 1)
5254c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5255c6a44287SMartin K. Petersen 	else
5256c6a44287SMartin K. Petersen 		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5257c6a44287SMartin K. Petersen 
5258773642d9SDouglas Gilbert 	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5259773642d9SDouglas Gilbert 	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
52601da177e4SLinus Torvalds         error = scsi_add_host(hpnt, &sdbg_host->dev);
52611da177e4SLinus Torvalds         if (error) {
5262c1287970STomas Winkler 		pr_err("scsi_add_host failed\n");
52631da177e4SLinus Torvalds                 error = -ENODEV;
52641da177e4SLinus Torvalds 		scsi_host_put(hpnt);
52651da177e4SLinus Torvalds         } else
52661da177e4SLinus Torvalds 		scsi_scan_host(hpnt);
52671da177e4SLinus Torvalds 
52681da177e4SLinus Torvalds 	return error;
52691da177e4SLinus Torvalds }
52701da177e4SLinus Torvalds 
52711da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev)
52721da177e4SLinus Torvalds {
52731da177e4SLinus Torvalds         struct sdebug_host_info *sdbg_host;
52748b40228fSFUJITA Tomonori 	struct sdebug_dev_info *sdbg_devinfo, *tmp;
52751da177e4SLinus Torvalds 
52761da177e4SLinus Torvalds 	sdbg_host = to_sdebug_host(dev);
52771da177e4SLinus Torvalds 
52781da177e4SLinus Torvalds 	if (!sdbg_host) {
5279c1287970STomas Winkler 		pr_err("Unable to locate host info\n");
52801da177e4SLinus Torvalds 		return -ENODEV;
52811da177e4SLinus Torvalds 	}
52821da177e4SLinus Torvalds 
52831da177e4SLinus Torvalds         scsi_remove_host(sdbg_host->shost);
52841da177e4SLinus Torvalds 
52858b40228fSFUJITA Tomonori 	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
52868b40228fSFUJITA Tomonori 				 dev_list) {
52871da177e4SLinus Torvalds                 list_del(&sdbg_devinfo->dev_list);
52881da177e4SLinus Torvalds                 kfree(sdbg_devinfo);
52891da177e4SLinus Torvalds         }
52901da177e4SLinus Torvalds 
52911da177e4SLinus Torvalds         scsi_host_put(sdbg_host->shost);
52921da177e4SLinus Torvalds         return 0;
52931da177e4SLinus Torvalds }
52941da177e4SLinus Torvalds 
52958dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev,
52968dea0d02SFUJITA Tomonori 				struct device_driver *dev_driver)
52971da177e4SLinus Torvalds {
52988dea0d02SFUJITA Tomonori 	return 1;
52998dea0d02SFUJITA Tomonori }
53001da177e4SLinus Torvalds 
53018dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = {
53028dea0d02SFUJITA Tomonori 	.name = "pseudo",
53038dea0d02SFUJITA Tomonori 	.match = pseudo_lld_bus_match,
53048dea0d02SFUJITA Tomonori 	.probe = sdebug_driver_probe,
53058dea0d02SFUJITA Tomonori 	.remove = sdebug_driver_remove,
530682069379SAkinobu Mita 	.drv_groups = sdebug_drv_groups,
53078dea0d02SFUJITA Tomonori };
5308