blob: c905709707f0a2178ca82823fb2be8523e3abe96 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
Douglas Gilbert773642d2016-04-25 12:16:28 -04009 * Copyright (C) 2001 - 2016 Douglas Gilbert
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Douglas Gilbert773642d2016-04-25 12:16:28 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040016 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
19
Tomas Winklerc12879702015-07-28 16:54:20 +030020
21#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/errno.h>
Douglas Gilbertb333a812016-04-25 12:16:30 -040027#include <linux/jiffies.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/types.h>
30#include <linux/string.h>
31#include <linux/genhd.h>
32#include <linux/fs.h>
33#include <linux/init.h>
34#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/vmalloc.h>
36#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020037#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050039#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040040#include <linux/spinlock.h>
41#include <linux/interrupt.h>
42#include <linux/atomic.h>
43#include <linux/hrtimer.h>
Douglas Gilbert09ba24c2016-05-06 00:40:28 -040044#include <linux/uuid.h>
Christoph Hellwig6ebf1052016-09-11 19:35:39 +020045#include <linux/t10-pi.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050046
47#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090048
Martin K. Petersen44d92692009-10-15 14:45:27 -040049#include <asm/unaligned.h>
50
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090051#include <scsi/scsi.h>
52#include <scsi/scsi_cmnd.h>
53#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <scsi/scsi_host.h>
55#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090056#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040057#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040058#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Martin K. Petersenc6a44282009-01-04 03:08:19 -050060#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Douglas Gilbert773642d2016-04-25 12:16:28 -040063/* make sure inq_product_rev string corresponds to this version */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -040064#define SDEBUG_VERSION "1.86"
65static const char *sdebug_version_date = "20160430";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040066
67#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050069/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define NO_ADDITIONAL_SENSE 0x0
71#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050072#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040074#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050076#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040078#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040079#define UA_RESET_ASC 0x29
80#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050081#define TARGET_CHANGED_ASC 0x3f
82#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050083#define INSUFF_RES_ASC 0x55
84#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040085#define POWER_ON_RESET_ASCQ 0x0
86#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
87#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050088#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050090#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define THRESHOLD_EXCEEDED 0x5d
92#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050093#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050094#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
95#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050097/* Additional Sense Code Qualifier (ASCQ) */
98#define ACK_NAK_TO 0x3
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100/* Default values for driver parameters */
101#define DEF_NUM_HOST 1
102#define DEF_NUM_TGTS 1
103#define DEF_MAX_LUNS 1
104/* With these defaults, this driver will make 1 host with 1 target
105 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
106 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500107#define DEF_ATO 1
Douglas Gilbertc2206092016-04-25 12:16:31 -0400108#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500110#define DEF_DIF 0
111#define DEF_DIX 0
112#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500114#define DEF_FAKE_RW 0
115#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400116#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500117#define DEF_LBPU 0
118#define DEF_LBPWS 0
119#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600120#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500121#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400122#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500123#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124#define DEF_NUM_PARTS 0
125#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500126#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500127#define DEF_PHYSBLK_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400128#define DEF_PTYPE TYPE_DISK
Martin Pittd9867882012-09-06 12:04:33 +0200129#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400130#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500131#define DEF_SECTOR_SIZE 512
132#define DEF_UNMAP_ALIGNMENT 0
133#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400134#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
135#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500136#define DEF_VIRTUAL_GB 0
137#define DEF_VPD_USE_HOSTNO 1
138#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500139#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400140#define DEF_STATISTICS false
141#define DEF_SUBMIT_QUEUES 1
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400142#define DEF_UUID_CTL 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400143#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400145#define SDEBUG_LUN_0_VAL 0
146
Douglas Gilbert773642d2016-04-25 12:16:28 -0400147/* bit mask values for sdebug_opts */
148#define SDEBUG_OPT_NOISE 1
149#define SDEBUG_OPT_MEDIUM_ERR 2
150#define SDEBUG_OPT_TIMEOUT 4
151#define SDEBUG_OPT_RECOVERED_ERR 8
152#define SDEBUG_OPT_TRANSPORT_ERR 16
153#define SDEBUG_OPT_DIF_ERR 32
154#define SDEBUG_OPT_DIX_ERR 64
155#define SDEBUG_OPT_MAC_TIMEOUT 128
156#define SDEBUG_OPT_SHORT_TRANSFER 0x100
157#define SDEBUG_OPT_Q_NOISE 0x200
158#define SDEBUG_OPT_ALL_TSF 0x400
159#define SDEBUG_OPT_RARE_TSF 0x800
160#define SDEBUG_OPT_N_WCE 0x1000
161#define SDEBUG_OPT_RESET_NOISE 0x2000
162#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
163#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
164 SDEBUG_OPT_RESET_NOISE)
165#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
166 SDEBUG_OPT_TRANSPORT_ERR | \
167 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
168 SDEBUG_OPT_SHORT_TRANSFER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400170 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400172 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500173 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400174 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 *
176 * When "every_nth" < 0 then after "- every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400177 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400179 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500180 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400181 * commands if _DEBUG_OPT_TRANSPORT_ERR is set.
182 * This will continue on every subsequent command until some other action
183 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
184 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 */
186
Douglas Gilbertfd321192016-04-25 12:16:33 -0400187/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400188 * priority order. In the subset implemented here lower numbers have higher
189 * priority. The UA numbers should be a sequence starting from 0 with
190 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
191#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
192#define SDEBUG_UA_BUS_RESET 1
193#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500194#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500195#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500196#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
197#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
198#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400199
Douglas Gilbert773642d2016-04-25 12:16:28 -0400200/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 * sector on read commands: */
202#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500203#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
206 * or "peripheral device" addressing (value 0) */
207#define SAM2_LUN_ADDRESS_METHOD 0
208
Douglas Gilbertc4837392016-05-06 00:40:26 -0400209/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
210 * (for response) per submit queue at one time. Can be reduced by max_queue
211 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
212 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
213 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
214 * but cannot exceed SDEBUG_CANQUEUE .
215 */
216#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
217#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400218#define DEF_CMD_PER_LUN 255
219
Douglas Gilbertfd321192016-04-25 12:16:33 -0400220#define F_D_IN 1
221#define F_D_OUT 2
222#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
223#define F_D_UNKN 8
224#define F_RL_WLUN_OK 0x10
225#define F_SKIP_UA 0x20
226#define F_DELAY_OVERR 0x40
227#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
228#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
229#define F_INV_OP 0x200
230#define F_FAKE_RW 0x400
231#define F_M_ACCESS 0x800 /* media access */
232
233#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
234#define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
235#define FF_SA (F_SA_HIGH | F_SA_LOW)
236
237#define SDEBUG_MAX_PARTS 4
238
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400239#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400240
241
242struct sdebug_dev_info {
243 struct list_head dev_list;
244 unsigned int channel;
245 unsigned int target;
246 u64 lun;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400247 uuid_be lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400248 struct sdebug_host_info *sdbg_host;
249 unsigned long uas_bm[1];
250 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400251 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400252 bool used;
253};
254
255struct sdebug_host_info {
256 struct list_head host_list;
257 struct Scsi_Host *shost;
258 struct device dev;
259 struct list_head dev_info_list;
260};
261
262#define to_sdebug_host(d) \
263 container_of(d, struct sdebug_host_info, dev)
264
265struct sdebug_defer {
266 struct hrtimer hrt;
267 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400268 int sqa_idx; /* index of sdebug_queue array */
269 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
270 int issuing_cpu;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400271};
272
273struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400274 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
275 * instance indicates this slot is in use.
276 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400277 struct sdebug_defer *sd_dp;
278 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400279 unsigned int inj_recovered:1;
280 unsigned int inj_transport:1;
281 unsigned int inj_dif:1;
282 unsigned int inj_dix:1;
283 unsigned int inj_short:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400284};
285
Douglas Gilbertc4837392016-05-06 00:40:26 -0400286struct sdebug_queue {
287 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
288 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
289 spinlock_t qc_lock;
290 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400291};
292
Douglas Gilbertc4837392016-05-06 00:40:26 -0400293static atomic_t sdebug_cmnd_count; /* number of incoming commands */
294static atomic_t sdebug_completions; /* count of deferred completions */
295static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
296static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
297
Douglas Gilbertfd321192016-04-25 12:16:33 -0400298struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400299 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
300 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400301 u8 opcode; /* if num_attached > 0, preferred */
302 u16 sa; /* service action */
303 u32 flags; /* OR-ed set of SDEB_F_* */
304 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
305 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
306 u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */
307 /* ignore cdb bytes after position 15 */
308};
309
310/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500311enum sdeb_opcode_index {
312 SDEB_I_INVALID_OPCODE = 0,
313 SDEB_I_INQUIRY = 1,
314 SDEB_I_REPORT_LUNS = 2,
315 SDEB_I_REQUEST_SENSE = 3,
316 SDEB_I_TEST_UNIT_READY = 4,
317 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
318 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
319 SDEB_I_LOG_SENSE = 7,
320 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
321 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
322 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
323 SDEB_I_START_STOP = 11,
324 SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */
325 SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */
326 SDEB_I_MAINT_IN = 14,
327 SDEB_I_MAINT_OUT = 15,
328 SDEB_I_VERIFY = 16, /* 10 only */
329 SDEB_I_VARIABLE_LEN = 17,
330 SDEB_I_RESERVE = 18, /* 6, 10 */
331 SDEB_I_RELEASE = 19, /* 6, 10 */
332 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
333 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
334 SDEB_I_ATA_PT = 22, /* 12, 16 */
335 SDEB_I_SEND_DIAG = 23,
336 SDEB_I_UNMAP = 24,
337 SDEB_I_XDWRITEREAD = 25, /* 10 only */
338 SDEB_I_WRITE_BUFFER = 26,
339 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
340 SDEB_I_SYNC_CACHE = 28, /* 10 only */
341 SDEB_I_COMP_WRITE = 29,
342 SDEB_I_LAST_ELEMENT = 30, /* keep this last */
343};
344
Douglas Gilbertc4837392016-05-06 00:40:26 -0400345
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500346static const unsigned char opcode_ind_arr[256] = {
347/* 0x0; 0x0->0x1f: 6 byte cdbs */
348 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
349 0, 0, 0, 0,
350 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
351 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
352 SDEB_I_RELEASE,
353 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
354 SDEB_I_ALLOW_REMOVAL, 0,
355/* 0x20; 0x20->0x3f: 10 byte cdbs */
356 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
357 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
358 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
359 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
360/* 0x40; 0x40->0x5f: 10 byte cdbs */
361 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
362 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
363 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
364 SDEB_I_RELEASE,
365 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400366/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369 0, SDEB_I_VARIABLE_LEN,
370/* 0x80; 0x80->0x9f: 16 byte cdbs */
371 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
372 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
373 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
374 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
375/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
376 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
377 SDEB_I_MAINT_OUT, 0, 0, 0,
378 SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
379 0, 0, 0, 0,
380 0, 0, 0, 0, 0, 0, 0, 0,
381 0, 0, 0, 0, 0, 0, 0, 0,
382/* 0xc0; 0xc0->0xff: vendor specific */
383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
387};
388
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500389static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
390static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
391static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
392static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
393static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
394static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
395static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
396static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
397static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
398static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
399static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
400static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
401static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
402static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500403static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
404static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500405static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
406static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
407static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500408static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500409static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500410
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500411static const struct opcode_info_t msense_iarr[1] = {
412 {0, 0x1a, 0, F_D_IN, NULL, NULL,
413 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
414};
415
416static const struct opcode_info_t mselect_iarr[1] = {
417 {0, 0x15, 0, F_D_OUT, NULL, NULL,
418 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
419};
420
421static const struct opcode_info_t read_iarr[3] = {
422 {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
423 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
424 0, 0, 0, 0} },
425 {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
426 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
427 {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
428 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
429 0xc7, 0, 0, 0, 0} },
430};
431
432static const struct opcode_info_t write_iarr[3] = {
433 {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */
434 {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
435 0, 0, 0, 0} },
436 {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */
437 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
438 {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */
439 {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
440 0xc7, 0, 0, 0, 0} },
441};
442
443static const struct opcode_info_t sa_in_iarr[1] = {
444 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
445 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
446 0xff, 0xff, 0xff, 0, 0xc7} },
447};
448
449static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
450 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
451 NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
452 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
453};
454
455static const struct opcode_info_t maint_in_iarr[2] = {
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500456 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500457 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
458 0xc7, 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500459 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500460 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
461 0, 0} },
462};
463
464static const struct opcode_info_t write_same_iarr[1] = {
465 {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
466 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
467 0xff, 0xff, 0xff, 0x1f, 0xc7} },
468};
469
470static const struct opcode_info_t reserve_iarr[1] = {
471 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
472 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
473};
474
475static const struct opcode_info_t release_iarr[1] = {
476 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
477 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
478};
479
480
481/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
482 * plus the terminating elements for logic that scans this table such as
483 * REPORT SUPPORTED OPERATION CODES. */
484static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
485/* 0 */
486 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
487 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
488 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
489 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
490 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
491 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
492 0, 0} },
493 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
494 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
495 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
496 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
497 {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
498 {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
499 0} },
500 {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
501 {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
502 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
503 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
504 0, 0, 0} },
505 {0, 0x25, 0, F_D_IN, resp_readcap, NULL,
506 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
507 0, 0} },
508 {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
509 {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
510 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */
511/* 10 */
512 {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
513 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
514 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */
515 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
516 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
517 {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
518 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
519 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */
520 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
521 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
522 {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
523 {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
524 0} },
525 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
526 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500527 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
528 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
529 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500530 {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
531 vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
532 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
533 {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
534 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
535 0} },
536 {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
537 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
538 0} },
539/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500540 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
541 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500542 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
543 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
544 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
545 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
546 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
547 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
548 {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
549 {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
550 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
551 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
552 0, 0, 0, 0, 0, 0} },
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500553 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
554 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
555 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500556 {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
557 write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
558 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
559 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
560 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
561 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500562 {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500563 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
564 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
565
566/* 30 */
567 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
568 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
569};
570
Douglas Gilbert773642d2016-04-25 12:16:28 -0400571static int sdebug_add_host = DEF_NUM_HOST;
572static int sdebug_ato = DEF_ATO;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400573static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400574static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
575static int sdebug_dif = DEF_DIF;
576static int sdebug_dix = DEF_DIX;
577static int sdebug_dsense = DEF_D_SENSE;
578static int sdebug_every_nth = DEF_EVERY_NTH;
579static int sdebug_fake_rw = DEF_FAKE_RW;
580static unsigned int sdebug_guard = DEF_GUARD;
581static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
582static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400583static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400584static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400585static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400586static int sdebug_no_lun_0 = DEF_NO_LUN_0;
587static int sdebug_no_uld;
588static int sdebug_num_parts = DEF_NUM_PARTS;
589static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
590static int sdebug_opt_blks = DEF_OPT_BLKS;
591static int sdebug_opts = DEF_OPTS;
592static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400593static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400594static int sdebug_scsi_level = DEF_SCSI_LEVEL;
595static int sdebug_sector_size = DEF_SECTOR_SIZE;
596static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
597static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
598static unsigned int sdebug_lbpu = DEF_LBPU;
599static unsigned int sdebug_lbpws = DEF_LBPWS;
600static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
601static unsigned int sdebug_lbprz = DEF_LBPRZ;
602static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
603static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
604static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
605static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
606static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400607static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400608static bool sdebug_removable = DEF_REMOVABLE;
609static bool sdebug_clustering;
610static bool sdebug_host_lock = DEF_HOST_LOCK;
611static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500612static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400613static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400614static bool have_dif_prot;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400615static bool sdebug_statistics = DEF_STATISTICS;
616static bool sdebug_mq_active;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400618static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619static sector_t sdebug_capacity; /* in sectors */
620
621/* old BIOS stuff, kernel may get rid of them but some mode sense pages
622 may still need them */
623static int sdebug_heads; /* heads per disk */
624static int sdebug_cylinders_per; /* cylinders per surface */
625static int sdebug_sectors_per; /* sectors per cylinder */
626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627static LIST_HEAD(sdebug_host_list);
628static DEFINE_SPINLOCK(sdebug_host_list_lock);
629
Douglas Gilbertfd321192016-04-25 12:16:33 -0400630static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200631static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400632static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Martin K. Petersen44d92692009-10-15 14:45:27 -0400634static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400635static int num_aborts;
636static int num_dev_resets;
637static int num_target_resets;
638static int num_bus_resets;
639static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500640static int dix_writes;
641static int dix_reads;
642static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Douglas Gilbertc4837392016-05-06 00:40:26 -0400644static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
645static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647static DEFINE_RWLOCK(atomic_rw);
648
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400649static char sdebug_proc_name[] = MY_NAME;
650static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652static struct bus_type pseudo_lld_bus;
653
654static struct device_driver sdebug_driverfs_driver = {
655 .name = sdebug_proc_name,
656 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657};
658
659static const int check_condition_result =
660 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
661
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500662static const int illegal_condition_result =
663 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
664
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400665static const int device_qfull_result =
666 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
667
Douglas Gilbertfd321192016-04-25 12:16:33 -0400668
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400669/* Only do the extra work involved in logical block provisioning if one or
670 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
671 * real reads and writes (i.e. not skipping them for speed).
672 */
673static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400674{
675 return 0 == sdebug_fake_rw &&
676 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
677}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400678
Akinobu Mita14faa942013-09-18 21:27:24 +0900679static void *fake_store(unsigned long long lba)
680{
681 lba = do_div(lba, sdebug_store_sectors);
682
Douglas Gilbert773642d2016-04-25 12:16:28 -0400683 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900684}
685
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200686static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900687{
Arnd Bergmann49413112015-11-20 17:38:28 +0100688 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900689
690 return dif_storep + sector;
691}
692
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900693static void sdebug_max_tgts_luns(void)
694{
695 struct sdebug_host_info *sdbg_host;
696 struct Scsi_Host *hpnt;
697
698 spin_lock(&sdebug_host_list_lock);
699 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
700 hpnt = sdbg_host->shost;
701 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400702 (sdebug_num_tgts > hpnt->this_id))
703 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900704 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400705 hpnt->max_id = sdebug_num_tgts;
706 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300707 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900708 }
709 spin_unlock(&sdebug_host_list_lock);
710}
711
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500712enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
713
714/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400715static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
716 enum sdeb_cmd_data c_d,
717 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500718{
719 unsigned char *sbuff;
720 u8 sks[4];
721 int sl, asc;
722
723 sbuff = scp->sense_buffer;
724 if (!sbuff) {
725 sdev_printk(KERN_ERR, scp->device,
726 "%s: sense_buffer is NULL\n", __func__);
727 return;
728 }
729 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
730 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400731 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500732 memset(sks, 0, sizeof(sks));
733 sks[0] = 0x80;
734 if (c_d)
735 sks[0] |= 0x40;
736 if (in_bit >= 0) {
737 sks[0] |= 0x8;
738 sks[0] |= 0x7 & in_bit;
739 }
740 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400741 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500742 sl = sbuff[7] + 8;
743 sbuff[7] = sl;
744 sbuff[sl] = 0x2;
745 sbuff[sl + 1] = 0x6;
746 memcpy(sbuff + sl + 4, sks, 3);
747 } else
748 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400749 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500750 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
751 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
752 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
753}
754
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400755static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900756{
757 unsigned char *sbuff;
758
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400759 sbuff = scp->sense_buffer;
760 if (!sbuff) {
761 sdev_printk(KERN_ERR, scp->device,
762 "%s: sense_buffer is NULL\n", __func__);
763 return;
764 }
765 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900766
Douglas Gilbert773642d2016-04-25 12:16:28 -0400767 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900768
Douglas Gilbert773642d2016-04-25 12:16:28 -0400769 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400770 sdev_printk(KERN_INFO, scp->device,
771 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
772 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900773}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Douglas Gilbertfd321192016-04-25 12:16:33 -0400775static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500776{
777 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
778}
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
781{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400782 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400783 if (0x1261 == cmd)
784 sdev_printk(KERN_INFO, dev,
785 "%s: BLKFLSBUF [0x1261]\n", __func__);
786 else if (0x5331 == cmd)
787 sdev_printk(KERN_INFO, dev,
788 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
789 __func__);
790 else
791 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
792 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
794 return -EINVAL;
795 /* return -ENOTTY; // correct return but upsets fdisk */
796}
797
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500798static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
799{
800 struct sdebug_host_info *sdhp;
801 struct sdebug_dev_info *dp;
802
803 spin_lock(&sdebug_host_list_lock);
804 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
805 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
806 if ((devip->sdbg_host == dp->sdbg_host) &&
807 (devip->target == dp->target))
808 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
809 }
810 }
811 spin_unlock(&sdebug_host_list_lock);
812}
813
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400814static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400816 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400817
818 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
819 if (k != SDEBUG_NUM_UAS) {
820 const char *cp = NULL;
821
822 switch (k) {
823 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400824 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
825 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400826 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400827 cp = "power on reset";
828 break;
829 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400830 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
831 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400832 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400833 cp = "bus reset";
834 break;
835 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400836 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
837 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400838 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400839 cp = "mode parameters changed";
840 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500841 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400842 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
843 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400844 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500845 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500846 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500847 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400848 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400849 TARGET_CHANGED_ASC,
850 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400851 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500852 cp = "microcode has been changed";
853 break;
854 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400855 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500856 TARGET_CHANGED_ASC,
857 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400858 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500859 cp = "microcode has been changed without reset";
860 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500861 case SDEBUG_UA_LUNS_CHANGED:
862 /*
863 * SPC-3 behavior is to report a UNIT ATTENTION with
864 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
865 * on the target, until a REPORT LUNS command is
866 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400867 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500868 * values as struct scsi_device->scsi_level.
869 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400870 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500871 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400872 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500873 TARGET_CHANGED_ASC,
874 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400875 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500876 cp = "reported luns data has changed";
877 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400878 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400879 pr_warn("unexpected unit attention code=%d\n", k);
880 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400881 cp = "unknown";
882 break;
883 }
884 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400885 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400886 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400887 "%s reports: Unit attention: %s\n",
888 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return check_condition_result;
890 }
891 return 0;
892}
893
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400894/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900895static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 int arr_len)
897{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900898 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900899 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900901 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900903 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400904 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900905
906 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
907 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700908 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 return 0;
911}
912
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400913/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
914 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
915 * calls, not required to write in ascending offset order. Assumes resid
916 * set to scsi_bufflen() prior to any calls.
917 */
918static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
919 int arr_len, unsigned int off_dst)
920{
921 int act_len, n;
922 struct scsi_data_buffer *sdb = scsi_in(scp);
923 off_t skip = off_dst;
924
925 if (sdb->length <= off_dst)
926 return 0;
927 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
928 return DID_ERROR << 16;
929
930 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
931 arr, arr_len, skip);
932 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
933 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
934 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
935 sdb->resid = min(sdb->resid, n);
936 return 0;
937}
938
939/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
940 * 'arr' or -1 if error.
941 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900942static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
943 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900945 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900947 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900949
950 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951}
952
953
954static const char * inq_vendor_id = "Linux ";
955static const char * inq_product_id = "scsi_debug ";
Douglas Gilbert773642d2016-04-25 12:16:28 -0400956static const char *inq_product_rev = "0186"; /* version less '.' */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -0400957/* Use some locally assigned NAAs for SAS addresses. */
958static const u64 naa3_comp_a = 0x3222222000000000ULL;
959static const u64 naa3_comp_b = 0x3333333000000000ULL;
960static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400962/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400963static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
964 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400965 const char *dev_id_str, int dev_id_str_len,
966 const uuid_be *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400968 int num, port_a;
969 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400971 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 /* T10 vendor identifier field format (faked) */
973 arr[0] = 0x2; /* ASCII */
974 arr[1] = 0x1;
975 arr[2] = 0x0;
976 memcpy(&arr[4], inq_vendor_id, 8);
977 memcpy(&arr[12], inq_product_id, 16);
978 memcpy(&arr[28], dev_id_str, dev_id_str_len);
979 num = 8 + 16 + dev_id_str_len;
980 arr[3] = num;
981 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400982 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400983 if (sdebug_uuid_ctl) {
984 /* Locally assigned UUID */
985 arr[num++] = 0x1; /* binary (not necessarily sas) */
986 arr[num++] = 0xa; /* PIV=0, lu, naa */
987 arr[num++] = 0x0;
988 arr[num++] = 0x12;
989 arr[num++] = 0x10; /* uuid type=1, locally assigned */
990 arr[num++] = 0x0;
991 memcpy(arr + num, lu_name, 16);
992 num += 16;
993 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -0400994 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400995 arr[num++] = 0x1; /* binary (not necessarily sas) */
996 arr[num++] = 0x3; /* PIV=0, lu, naa */
997 arr[num++] = 0x0;
998 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -0400999 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001000 num += 8;
1001 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001002 /* Target relative port number */
1003 arr[num++] = 0x61; /* proto=sas, binary */
1004 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1005 arr[num++] = 0x0; /* reserved */
1006 arr[num++] = 0x4; /* length */
1007 arr[num++] = 0x0; /* reserved */
1008 arr[num++] = 0x0; /* reserved */
1009 arr[num++] = 0x0;
1010 arr[num++] = 0x1; /* relative port A */
1011 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001012 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001013 arr[num++] = 0x61; /* proto=sas, binary */
1014 arr[num++] = 0x93; /* piv=1, target port, naa */
1015 arr[num++] = 0x0;
1016 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001017 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001018 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001019 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001020 arr[num++] = 0x61; /* proto=sas, binary */
1021 arr[num++] = 0x95; /* piv=1, target port group id */
1022 arr[num++] = 0x0;
1023 arr[num++] = 0x4;
1024 arr[num++] = 0;
1025 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001026 put_unaligned_be16(port_group_id, arr + num);
1027 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001028 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001029 arr[num++] = 0x61; /* proto=sas, binary */
1030 arr[num++] = 0xa3; /* piv=1, target device, naa */
1031 arr[num++] = 0x0;
1032 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001033 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001034 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001035 /* SCSI name string: Target device identifier */
1036 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1037 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1038 arr[num++] = 0x0;
1039 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001040 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001041 num += 12;
1042 snprintf(b, sizeof(b), "%08X", target_dev_id);
1043 memcpy(arr + num, b, 8);
1044 num += 8;
1045 memset(arr + num, 0, 4);
1046 num += 4;
1047 return num;
1048}
1049
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001050static unsigned char vpd84_data[] = {
1051/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1052 0x22,0x22,0x22,0x0,0xbb,0x1,
1053 0x22,0x22,0x22,0x0,0xbb,0x2,
1054};
1055
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001056/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001057static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001058{
1059 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1060 return sizeof(vpd84_data);
1061}
1062
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001063/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001064static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001065{
1066 int num = 0;
1067 const char * na1 = "https://www.kernel.org/config";
1068 const char * na2 = "http://www.kernel.org/log";
1069 int plen, olen;
1070
1071 arr[num++] = 0x1; /* lu, storage config */
1072 arr[num++] = 0x0; /* reserved */
1073 arr[num++] = 0x0;
1074 olen = strlen(na1);
1075 plen = olen + 1;
1076 if (plen % 4)
1077 plen = ((plen / 4) + 1) * 4;
1078 arr[num++] = plen; /* length, null termianted, padded */
1079 memcpy(arr + num, na1, olen);
1080 memset(arr + num + olen, 0, plen - olen);
1081 num += plen;
1082
1083 arr[num++] = 0x4; /* lu, logging */
1084 arr[num++] = 0x0; /* reserved */
1085 arr[num++] = 0x0;
1086 olen = strlen(na2);
1087 plen = olen + 1;
1088 if (plen % 4)
1089 plen = ((plen / 4) + 1) * 4;
1090 arr[num++] = plen; /* length, null terminated, padded */
1091 memcpy(arr + num, na2, olen);
1092 memset(arr + num + olen, 0, plen - olen);
1093 num += plen;
1094
1095 return num;
1096}
1097
1098/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001099static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001100{
1101 int num = 0;
1102 int port_a, port_b;
1103
1104 port_a = target_dev_id + 1;
1105 port_b = port_a + 1;
1106 arr[num++] = 0x0; /* reserved */
1107 arr[num++] = 0x0; /* reserved */
1108 arr[num++] = 0x0;
1109 arr[num++] = 0x1; /* relative port 1 (primary) */
1110 memset(arr + num, 0, 6);
1111 num += 6;
1112 arr[num++] = 0x0;
1113 arr[num++] = 12; /* length tp descriptor */
1114 /* naa-5 target port identifier (A) */
1115 arr[num++] = 0x61; /* proto=sas, binary */
1116 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1117 arr[num++] = 0x0; /* reserved */
1118 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001119 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001120 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001121 arr[num++] = 0x0; /* reserved */
1122 arr[num++] = 0x0; /* reserved */
1123 arr[num++] = 0x0;
1124 arr[num++] = 0x2; /* relative port 2 (secondary) */
1125 memset(arr + num, 0, 6);
1126 num += 6;
1127 arr[num++] = 0x0;
1128 arr[num++] = 12; /* length tp descriptor */
1129 /* naa-5 target port identifier (B) */
1130 arr[num++] = 0x61; /* proto=sas, binary */
1131 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1132 arr[num++] = 0x0; /* reserved */
1133 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001134 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001135 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001136
1137 return num;
1138}
1139
1140
1141static unsigned char vpd89_data[] = {
1142/* from 4th byte */ 0,0,0,0,
1143'l','i','n','u','x',' ',' ',' ',
1144'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1145'1','2','3','4',
11460x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
11470xec,0,0,0,
11480x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
11490,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
11500x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
11510x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
11520x53,0x41,
11530x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11540x20,0x20,
11550x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11560x10,0x80,
11570,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
11580x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
11590x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
11600,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
11610x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
11620x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
11630,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
11640,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11670x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
11680,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
11690xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
11700,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
11710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11720,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11730,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11740,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11760,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11770,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11790,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11820,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1183};
1184
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001185/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001186static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001187{
1188 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1189 return sizeof(vpd89_data);
1190}
1191
1192
1193static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001194 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1195 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1196 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1197 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001198};
1199
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001200/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001201static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001202{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001203 unsigned int gran;
1204
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001205 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001206
1207 /* Optimal transfer length granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001208 gran = 1 << sdebug_physblk_exp;
1209 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001210
1211 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001212 if (sdebug_store_sectors > 0x400)
1213 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001214
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001215 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001216 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001217
Douglas Gilbert773642d2016-04-25 12:16:28 -04001218 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001219 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001220 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001221
1222 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001223 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001224 }
1225
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001226 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001227 if (sdebug_unmap_alignment) {
1228 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001229 arr[28] |= 0x80; /* UGAVALID */
1230 }
1231
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001232 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001233 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001234
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001235 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001236 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001237
1238 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001239
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001240 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241}
1242
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001243/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001244static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001245{
1246 memset(arr, 0, 0x3c);
1247 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001248 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1249 arr[2] = 0;
1250 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001251
1252 return 0x3c;
1253}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001255/* Logical block provisioning VPD page (SBC-4) */
1256static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001257{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001258 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001259 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001260 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001261 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001262 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001263 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001264 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001265 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001266 if (sdebug_lbprz && scsi_debug_lbp())
1267 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1268 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1269 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1270 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001271 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001272}
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001275#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001277static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
1279 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001280 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001281 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001282 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001283 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
Douglas Gilbert773642d2016-04-25 12:16:28 -04001285 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001286 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1287 if (! arr)
1288 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001289 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001290 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001291 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001292 pq_pdt = TYPE_WLUN; /* present, wlun */
1293 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1294 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001295 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001296 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 arr[0] = pq_pdt;
1298 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001299 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001300 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 return check_condition_result;
1302 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001303 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001304 char lu_id_str[6];
1305 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001307 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1308 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001309 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001310 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001311 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001312 (devip->target * 1000) + devip->lun);
1313 target_dev_id = ((host_no + 1) * 2000) +
1314 (devip->target * 1000) - 3;
1315 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001317 arr[1] = cmd[2]; /*sanity */
1318 n = 4;
1319 arr[n++] = 0x0; /* this page */
1320 arr[n++] = 0x80; /* unit serial number */
1321 arr[n++] = 0x83; /* device identification */
1322 arr[n++] = 0x84; /* software interface ident. */
1323 arr[n++] = 0x85; /* management network addresses */
1324 arr[n++] = 0x86; /* extended inquiry */
1325 arr[n++] = 0x87; /* mode page policy */
1326 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001327 if (is_disk) { /* SBC only */
1328 arr[n++] = 0x89; /* ATA information */
1329 arr[n++] = 0xb0; /* Block limits */
1330 arr[n++] = 0xb1; /* Block characteristics */
1331 arr[n++] = 0xb2; /* Logical Block Prov */
1332 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001333 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001335 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001337 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001339 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001340 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1341 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001342 lu_id_str, len,
1343 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001344 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1345 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001346 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001347 } else if (0x85 == cmd[2]) { /* Management network addresses */
1348 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001349 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001350 } else if (0x86 == cmd[2]) { /* extended inquiry */
1351 arr[1] = cmd[2]; /*sanity */
1352 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001353 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001354 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001355 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001356 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1357 else
1358 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001359 arr[5] = 0x7; /* head of q, ordered + simple q's */
1360 } else if (0x87 == cmd[2]) { /* mode page policy */
1361 arr[1] = cmd[2]; /*sanity */
1362 arr[3] = 0x8; /* number of following entries */
1363 arr[4] = 0x2; /* disconnect-reconnect mp */
1364 arr[6] = 0x80; /* mlus, shared */
1365 arr[8] = 0x18; /* protocol specific lu */
1366 arr[10] = 0x82; /* mlus, per initiator port */
1367 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1368 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001369 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1370 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001371 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001372 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001373 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001374 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001375 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001376 arr[3] = inquiry_vpd_b0(&arr[4]);
1377 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001378 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001379 arr[3] = inquiry_vpd_b1(&arr[4]);
1380 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001381 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001382 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001384 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001385 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 return check_condition_result;
1387 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001388 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001389 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001390 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001391 kfree(arr);
1392 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 }
1394 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001395 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1396 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 arr[3] = 2; /* response_data_format==2 */
1398 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001399 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001400 if (sdebug_vpd_use_hostno == 0)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001401 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001402 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001404 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 memcpy(&arr[8], inq_vendor_id, 8);
1406 memcpy(&arr[16], inq_product_id, 16);
1407 memcpy(&arr[32], inq_product_rev, 4);
1408 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001409 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1410 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001411 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001412 if (is_disk) { /* SBC-4 no version claimed */
1413 put_unaligned_be16(0x600, arr + n);
1414 n += 2;
1415 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1416 put_unaligned_be16(0x525, arr + n);
1417 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001419 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001420 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001422 kfree(arr);
1423 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424}
1425
Douglas Gilbertfd321192016-04-25 12:16:33 -04001426static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1427 0, 0, 0x0, 0x0};
1428
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429static int resp_requests(struct scsi_cmnd * scp,
1430 struct sdebug_dev_info * devip)
1431{
1432 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001433 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001434 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001435 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 int len = 18;
1437
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001438 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001439 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001440 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001441 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001442 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001443 arr[0] = 0x72;
1444 arr[1] = 0x0; /* NO_SENSE in sense_key */
1445 arr[2] = THRESHOLD_EXCEEDED;
1446 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001447 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001448 } else {
1449 arr[0] = 0x70;
1450 arr[2] = 0x0; /* NO_SENSE in sense_key */
1451 arr[7] = 0xa; /* 18 byte sense buffer */
1452 arr[12] = THRESHOLD_EXCEEDED;
1453 arr[13] = 0xff; /* TEST set and MRIE==6 */
1454 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001455 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001456 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001457 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001458 ; /* have sense and formats match */
1459 else if (arr[0] <= 0x70) {
1460 if (dsense) {
1461 memset(arr, 0, 8);
1462 arr[0] = 0x72;
1463 len = 8;
1464 } else {
1465 memset(arr, 0, 18);
1466 arr[0] = 0x70;
1467 arr[7] = 0xa;
1468 }
1469 } else if (dsense) {
1470 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001471 arr[0] = 0x72;
1472 arr[1] = sbuff[2]; /* sense key */
1473 arr[2] = sbuff[12]; /* asc */
1474 arr[3] = sbuff[13]; /* ascq */
1475 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001476 } else {
1477 memset(arr, 0, 18);
1478 arr[0] = 0x70;
1479 arr[2] = sbuff[1];
1480 arr[7] = 0xa;
1481 arr[12] = sbuff[1];
1482 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001483 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001484
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001485 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001486 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 return fill_from_dev_buffer(scp, arr, len);
1488}
1489
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001490static int resp_start_stop(struct scsi_cmnd * scp,
1491 struct sdebug_dev_info * devip)
1492{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001493 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001494 int power_cond, stop;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001495
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496 power_cond = (cmd[4] & 0xf0) >> 4;
1497 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001498 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001499 return check_condition_result;
1500 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001501 stop = !(cmd[4] & 1);
1502 atomic_xchg(&devip->stopped, stop);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001503 return 0;
1504}
1505
FUJITA Tomonori28898872008-03-30 00:59:55 +09001506static sector_t get_sdebug_capacity(void)
1507{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001508 static const unsigned int gibibyte = 1073741824;
1509
1510 if (sdebug_virtual_gb > 0)
1511 return (sector_t)sdebug_virtual_gb *
1512 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001513 else
1514 return sdebug_store_sectors;
1515}
1516
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517#define SDEBUG_READCAP_ARR_SZ 8
1518static int resp_readcap(struct scsi_cmnd * scp,
1519 struct sdebug_dev_info * devip)
1520{
1521 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001522 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001524 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001525 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001527 if (sdebug_capacity < 0xffffffff) {
1528 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001529 put_unaligned_be32(capac, arr + 0);
1530 } else
1531 put_unaligned_be32(0xffffffff, arr + 0);
1532 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1534}
1535
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001536#define SDEBUG_READCAP16_ARR_SZ 32
1537static int resp_readcap16(struct scsi_cmnd * scp,
1538 struct sdebug_dev_info * devip)
1539{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001540 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001541 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001542 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001543
Douglas Gilbert773642d2016-04-25 12:16:28 -04001544 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001545 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001546 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001547 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001548 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1549 put_unaligned_be32(sdebug_sector_size, arr + 8);
1550 arr[13] = sdebug_physblk_exp & 0xf;
1551 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001552
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001553 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001554 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001555 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1556 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1557 * in the wider field maps to 0 in this field.
1558 */
1559 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1560 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001561 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001562
Douglas Gilbert773642d2016-04-25 12:16:28 -04001563 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001564
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001565 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001566 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001567 arr[12] |= 1; /* PROT_EN */
1568 }
1569
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001570 return fill_from_dev_buffer(scp, arr,
1571 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1572}
1573
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001574#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1575
1576static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1577 struct sdebug_dev_info * devip)
1578{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001579 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001580 unsigned char * arr;
1581 int host_no = devip->sdbg_host->shost->host_no;
1582 int n, ret, alen, rlen;
1583 int port_group_a, port_group_b, port_a, port_b;
1584
Douglas Gilbert773642d2016-04-25 12:16:28 -04001585 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001586 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1587 if (! arr)
1588 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001589 /*
1590 * EVPD page 0x88 states we have two ports, one
1591 * real and a fake port with no device connected.
1592 * So we create two port groups with one port each
1593 * and set the group with port B to unavailable.
1594 */
1595 port_a = 0x1; /* relative port A */
1596 port_b = 0x2; /* relative port B */
1597 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001598 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001599 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001600 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001601
1602 /*
1603 * The asymmetric access state is cycled according to the host_id.
1604 */
1605 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001606 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001607 arr[n++] = host_no % 3; /* Asymm access state */
1608 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001609 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001610 arr[n++] = 0x0; /* Active/Optimized path */
1611 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001612 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001613 put_unaligned_be16(port_group_a, arr + n);
1614 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001615 arr[n++] = 0; /* Reserved */
1616 arr[n++] = 0; /* Status code */
1617 arr[n++] = 0; /* Vendor unique */
1618 arr[n++] = 0x1; /* One port per group */
1619 arr[n++] = 0; /* Reserved */
1620 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001621 put_unaligned_be16(port_a, arr + n);
1622 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001623 arr[n++] = 3; /* Port unavailable */
1624 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001625 put_unaligned_be16(port_group_b, arr + n);
1626 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001627 arr[n++] = 0; /* Reserved */
1628 arr[n++] = 0; /* Status code */
1629 arr[n++] = 0; /* Vendor unique */
1630 arr[n++] = 0x1; /* One port per group */
1631 arr[n++] = 0; /* Reserved */
1632 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001633 put_unaligned_be16(port_b, arr + n);
1634 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001635
1636 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001637 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001638
1639 /*
1640 * Return the smallest value of either
1641 * - The allocated length
1642 * - The constructed command length
1643 * - The maximum array size
1644 */
1645 rlen = min(alen,n);
1646 ret = fill_from_dev_buffer(scp, arr,
1647 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1648 kfree(arr);
1649 return ret;
1650}
1651
Douglas Gilbertfd321192016-04-25 12:16:33 -04001652static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1653 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001654{
1655 bool rctd;
1656 u8 reporting_opts, req_opcode, sdeb_i, supp;
1657 u16 req_sa, u;
1658 u32 alloc_len, a_len;
1659 int k, offset, len, errsts, count, bump, na;
1660 const struct opcode_info_t *oip;
1661 const struct opcode_info_t *r_oip;
1662 u8 *arr;
1663 u8 *cmd = scp->cmnd;
1664
1665 rctd = !!(cmd[2] & 0x80);
1666 reporting_opts = cmd[2] & 0x7;
1667 req_opcode = cmd[3];
1668 req_sa = get_unaligned_be16(cmd + 4);
1669 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001670 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001671 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1672 return check_condition_result;
1673 }
1674 if (alloc_len > 8192)
1675 a_len = 8192;
1676 else
1677 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001678 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001679 if (NULL == arr) {
1680 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1681 INSUFF_RES_ASCQ);
1682 return check_condition_result;
1683 }
1684 switch (reporting_opts) {
1685 case 0: /* all commands */
1686 /* count number of commands */
1687 for (count = 0, oip = opcode_info_arr;
1688 oip->num_attached != 0xff; ++oip) {
1689 if (F_INV_OP & oip->flags)
1690 continue;
1691 count += (oip->num_attached + 1);
1692 }
1693 bump = rctd ? 20 : 8;
1694 put_unaligned_be32(count * bump, arr);
1695 for (offset = 4, oip = opcode_info_arr;
1696 oip->num_attached != 0xff && offset < a_len; ++oip) {
1697 if (F_INV_OP & oip->flags)
1698 continue;
1699 na = oip->num_attached;
1700 arr[offset] = oip->opcode;
1701 put_unaligned_be16(oip->sa, arr + offset + 2);
1702 if (rctd)
1703 arr[offset + 5] |= 0x2;
1704 if (FF_SA & oip->flags)
1705 arr[offset + 5] |= 0x1;
1706 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1707 if (rctd)
1708 put_unaligned_be16(0xa, arr + offset + 8);
1709 r_oip = oip;
1710 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1711 if (F_INV_OP & oip->flags)
1712 continue;
1713 offset += bump;
1714 arr[offset] = oip->opcode;
1715 put_unaligned_be16(oip->sa, arr + offset + 2);
1716 if (rctd)
1717 arr[offset + 5] |= 0x2;
1718 if (FF_SA & oip->flags)
1719 arr[offset + 5] |= 0x1;
1720 put_unaligned_be16(oip->len_mask[0],
1721 arr + offset + 6);
1722 if (rctd)
1723 put_unaligned_be16(0xa,
1724 arr + offset + 8);
1725 }
1726 oip = r_oip;
1727 offset += bump;
1728 }
1729 break;
1730 case 1: /* one command: opcode only */
1731 case 2: /* one command: opcode plus service action */
1732 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1733 sdeb_i = opcode_ind_arr[req_opcode];
1734 oip = &opcode_info_arr[sdeb_i];
1735 if (F_INV_OP & oip->flags) {
1736 supp = 1;
1737 offset = 4;
1738 } else {
1739 if (1 == reporting_opts) {
1740 if (FF_SA & oip->flags) {
1741 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1742 2, 2);
1743 kfree(arr);
1744 return check_condition_result;
1745 }
1746 req_sa = 0;
1747 } else if (2 == reporting_opts &&
1748 0 == (FF_SA & oip->flags)) {
1749 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1750 kfree(arr); /* point at requested sa */
1751 return check_condition_result;
1752 }
1753 if (0 == (FF_SA & oip->flags) &&
1754 req_opcode == oip->opcode)
1755 supp = 3;
1756 else if (0 == (FF_SA & oip->flags)) {
1757 na = oip->num_attached;
1758 for (k = 0, oip = oip->arrp; k < na;
1759 ++k, ++oip) {
1760 if (req_opcode == oip->opcode)
1761 break;
1762 }
1763 supp = (k >= na) ? 1 : 3;
1764 } else if (req_sa != oip->sa) {
1765 na = oip->num_attached;
1766 for (k = 0, oip = oip->arrp; k < na;
1767 ++k, ++oip) {
1768 if (req_sa == oip->sa)
1769 break;
1770 }
1771 supp = (k >= na) ? 1 : 3;
1772 } else
1773 supp = 3;
1774 if (3 == supp) {
1775 u = oip->len_mask[0];
1776 put_unaligned_be16(u, arr + 2);
1777 arr[4] = oip->opcode;
1778 for (k = 1; k < u; ++k)
1779 arr[4 + k] = (k < 16) ?
1780 oip->len_mask[k] : 0xff;
1781 offset = 4 + u;
1782 } else
1783 offset = 4;
1784 }
1785 arr[1] = (rctd ? 0x80 : 0) | supp;
1786 if (rctd) {
1787 put_unaligned_be16(0xa, arr + offset);
1788 offset += 12;
1789 }
1790 break;
1791 default:
1792 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1793 kfree(arr);
1794 return check_condition_result;
1795 }
1796 offset = (offset < a_len) ? offset : a_len;
1797 len = (offset < alloc_len) ? offset : alloc_len;
1798 errsts = fill_from_dev_buffer(scp, arr, len);
1799 kfree(arr);
1800 return errsts;
1801}
1802
Douglas Gilbertfd321192016-04-25 12:16:33 -04001803static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1804 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001805{
1806 bool repd;
1807 u32 alloc_len, len;
1808 u8 arr[16];
1809 u8 *cmd = scp->cmnd;
1810
1811 memset(arr, 0, sizeof(arr));
1812 repd = !!(cmd[2] & 0x80);
1813 alloc_len = get_unaligned_be32(cmd + 6);
1814 if (alloc_len < 4) {
1815 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1816 return check_condition_result;
1817 }
1818 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1819 arr[1] = 0x1; /* ITNRS */
1820 if (repd) {
1821 arr[3] = 0xc;
1822 len = 16;
1823 } else
1824 len = 4;
1825
1826 len = (len < alloc_len) ? len : alloc_len;
1827 return fill_from_dev_buffer(scp, arr, len);
1828}
1829
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830/* <<Following mode page info copied from ST318451LW>> */
1831
1832static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1833{ /* Read-Write Error Recovery page for mode_sense */
1834 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1835 5, 0, 0xff, 0xff};
1836
1837 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1838 if (1 == pcontrol)
1839 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1840 return sizeof(err_recov_pg);
1841}
1842
1843static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1844{ /* Disconnect-Reconnect page for mode_sense */
1845 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1846 0, 0, 0, 0, 0, 0, 0, 0};
1847
1848 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1849 if (1 == pcontrol)
1850 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1851 return sizeof(disconnect_pg);
1852}
1853
1854static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1855{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001856 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1857 0, 0, 0, 0, 0, 0, 0, 0,
1858 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859
Martin K. Petersen597136a2008-06-05 00:12:59 -04001860 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001861 put_unaligned_be16(sdebug_sectors_per, p + 10);
1862 put_unaligned_be16(sdebug_sector_size, p + 12);
1863 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001864 p[20] |= 0x20; /* should agree with INQUIRY */
1865 if (1 == pcontrol)
1866 memset(p + 2, 0, sizeof(format_pg) - 2);
1867 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868}
1869
Douglas Gilbertfd321192016-04-25 12:16:33 -04001870static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1871 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1872 0, 0, 0, 0};
1873
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1875{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001876 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1877 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1878 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1880
Douglas Gilbert773642d2016-04-25 12:16:28 -04001881 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001882 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 memcpy(p, caching_pg, sizeof(caching_pg));
1884 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001885 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1886 else if (2 == pcontrol)
1887 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 return sizeof(caching_pg);
1889}
1890
Douglas Gilbertfd321192016-04-25 12:16:33 -04001891static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1892 0, 0, 0x2, 0x4b};
1893
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1895{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001896 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1897 0, 0, 0, 0};
1898 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 0, 0, 0x2, 0x4b};
1900
Douglas Gilbert773642d2016-04-25 12:16:28 -04001901 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001903 else
1904 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001905
Douglas Gilbert773642d2016-04-25 12:16:28 -04001906 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001907 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1908
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1910 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001911 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1912 else if (2 == pcontrol)
1913 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 return sizeof(ctrl_m_pg);
1915}
1916
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001917
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1919{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001920 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1921 0, 0, 0x0, 0x0};
1922 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1923 0, 0, 0x0, 0x0};
1924
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1926 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001927 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1928 else if (2 == pcontrol)
1929 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 return sizeof(iec_m_pg);
1931}
1932
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001933static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1934{ /* SAS SSP mode page - short format for mode_sense */
1935 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1936 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1937
1938 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1939 if (1 == pcontrol)
1940 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1941 return sizeof(sas_sf_m_pg);
1942}
1943
1944
1945static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1946 int target_dev_id)
1947{ /* SAS phy control and discover mode page for mode_sense */
1948 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1949 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001950 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1951 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001952 0x2, 0, 0, 0, 0, 0, 0, 0,
1953 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1954 0, 0, 0, 0, 0, 0, 0, 0,
1955 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001956 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1957 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001958 0x3, 0, 0, 0, 0, 0, 0, 0,
1959 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1960 0, 0, 0, 0, 0, 0, 0, 0,
1961 };
1962 int port_a, port_b;
1963
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001964 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
1965 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
1966 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
1967 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001968 port_a = target_dev_id + 1;
1969 port_b = port_a + 1;
1970 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001971 put_unaligned_be32(port_a, p + 20);
1972 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001973 if (1 == pcontrol)
1974 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1975 return sizeof(sas_pcd_m_pg);
1976}
1977
1978static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1979{ /* SAS SSP shared protocol specific port mode subpage */
1980 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1981 0, 0, 0, 0, 0, 0, 0, 0,
1982 };
1983
1984 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1985 if (1 == pcontrol)
1986 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1987 return sizeof(sas_sha_m_pg);
1988}
1989
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990#define SDEBUG_MAX_MSENSE_SZ 256
1991
Douglas Gilbertfd321192016-04-25 12:16:33 -04001992static int resp_mode_sense(struct scsi_cmnd *scp,
1993 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994{
Douglas Gilbert23183912006-09-16 20:30:47 -04001995 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001997 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001998 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 unsigned char * ap;
2000 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002001 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002002 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002004 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 pcontrol = (cmd[2] & 0xc0) >> 6;
2006 pcode = cmd[2] & 0x3f;
2007 subpcode = cmd[3];
2008 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002009 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2010 is_disk = (sdebug_ptype == TYPE_DISK);
2011 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002012 bd_len = llbaa ? 16 : 8;
2013 else
2014 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002015 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2017 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002018 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 return check_condition_result;
2020 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002021 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2022 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002023 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002024 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002025 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002026 else
2027 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 if (msense_6) {
2029 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002030 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 offset = 4;
2032 } else {
2033 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002034 if (16 == bd_len)
2035 arr[4] = 0x1; /* set LONGLBA bit */
2036 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 offset = 8;
2038 }
2039 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002040 if ((bd_len > 0) && (!sdebug_capacity))
2041 sdebug_capacity = get_sdebug_capacity();
2042
Douglas Gilbert23183912006-09-16 20:30:47 -04002043 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002044 if (sdebug_capacity > 0xfffffffe)
2045 put_unaligned_be32(0xffffffff, ap + 0);
2046 else
2047 put_unaligned_be32(sdebug_capacity, ap + 0);
2048 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002049 offset += bd_len;
2050 ap = arr + offset;
2051 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002052 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2053 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002054 offset += bd_len;
2055 ap = arr + offset;
2056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002058 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2059 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002060 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 return check_condition_result;
2062 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002063 bad_pcode = false;
2064
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 switch (pcode) {
2066 case 0x1: /* Read-Write error recovery page, direct access */
2067 len = resp_err_recov_pg(ap, pcontrol, target);
2068 offset += len;
2069 break;
2070 case 0x2: /* Disconnect-Reconnect page, all devices */
2071 len = resp_disconnect_pg(ap, pcontrol, target);
2072 offset += len;
2073 break;
2074 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002075 if (is_disk) {
2076 len = resp_format_pg(ap, pcontrol, target);
2077 offset += len;
2078 } else
2079 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 break;
2081 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002082 if (is_disk) {
2083 len = resp_caching_pg(ap, pcontrol, target);
2084 offset += len;
2085 } else
2086 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 break;
2088 case 0xa: /* Control Mode page, all devices */
2089 len = resp_ctrl_m_pg(ap, pcontrol, target);
2090 offset += len;
2091 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002092 case 0x19: /* if spc==1 then sas phy, control+discover */
2093 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002094 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002095 return check_condition_result;
2096 }
2097 len = 0;
2098 if ((0x0 == subpcode) || (0xff == subpcode))
2099 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2100 if ((0x1 == subpcode) || (0xff == subpcode))
2101 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2102 target_dev_id);
2103 if ((0x2 == subpcode) || (0xff == subpcode))
2104 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2105 offset += len;
2106 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 case 0x1c: /* Informational Exceptions Mode page, all devices */
2108 len = resp_iec_m_pg(ap, pcontrol, target);
2109 offset += len;
2110 break;
2111 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002112 if ((0 == subpcode) || (0xff == subpcode)) {
2113 len = resp_err_recov_pg(ap, pcontrol, target);
2114 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002115 if (is_disk) {
2116 len += resp_format_pg(ap + len, pcontrol,
2117 target);
2118 len += resp_caching_pg(ap + len, pcontrol,
2119 target);
2120 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002121 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2122 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2123 if (0xff == subpcode) {
2124 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2125 target, target_dev_id);
2126 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2127 }
2128 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002129 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002130 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002131 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002132 return check_condition_result;
2133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 break;
2135 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002136 bad_pcode = true;
2137 break;
2138 }
2139 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002140 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 return check_condition_result;
2142 }
2143 if (msense_6)
2144 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002145 else
2146 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2148}
2149
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002150#define SDEBUG_MAX_MSELECT_SZ 512
2151
Douglas Gilbertfd321192016-04-25 12:16:33 -04002152static int resp_mode_select(struct scsi_cmnd *scp,
2153 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002154{
2155 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002156 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002157 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002158 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002159 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002160
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002161 memset(arr, 0, sizeof(arr));
2162 pf = cmd[1] & 0x10;
2163 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002164 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002165 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002166 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002167 return check_condition_result;
2168 }
2169 res = fetch_to_dev_buffer(scp, arr, param_len);
2170 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002171 return DID_ERROR << 16;
2172 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002173 sdev_printk(KERN_INFO, scp->device,
2174 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2175 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002176 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2177 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002178 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002179 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002180 return check_condition_result;
2181 }
2182 off = bd_len + (mselect6 ? 4 : 8);
2183 mpage = arr[off] & 0x3f;
2184 ps = !!(arr[off] & 0x80);
2185 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002186 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002187 return check_condition_result;
2188 }
2189 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002190 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002191 (arr[off + 1] + 2);
2192 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002193 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002194 PARAMETER_LIST_LENGTH_ERR, 0);
2195 return check_condition_result;
2196 }
2197 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002198 case 0x8: /* Caching Mode page */
2199 if (caching_pg[1] == arr[off + 1]) {
2200 memcpy(caching_pg + 2, arr + off + 2,
2201 sizeof(caching_pg) - 2);
2202 goto set_mode_changed_ua;
2203 }
2204 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002205 case 0xa: /* Control Mode page */
2206 if (ctrl_m_pg[1] == arr[off + 1]) {
2207 memcpy(ctrl_m_pg + 2, arr + off + 2,
2208 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002209 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002210 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002211 }
2212 break;
2213 case 0x1c: /* Informational Exceptions Mode page */
2214 if (iec_m_pg[1] == arr[off + 1]) {
2215 memcpy(iec_m_pg + 2, arr + off + 2,
2216 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002217 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002218 }
2219 break;
2220 default:
2221 break;
2222 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002223 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002224 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002225set_mode_changed_ua:
2226 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2227 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002228}
2229
2230static int resp_temp_l_pg(unsigned char * arr)
2231{
2232 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2233 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2234 };
2235
2236 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2237 return sizeof(temp_l_pg);
2238}
2239
2240static int resp_ie_l_pg(unsigned char * arr)
2241{
2242 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2243 };
2244
2245 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2246 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2247 arr[4] = THRESHOLD_EXCEEDED;
2248 arr[5] = 0xff;
2249 }
2250 return sizeof(ie_l_pg);
2251}
2252
2253#define SDEBUG_MAX_LSENSE_SZ 512
2254
2255static int resp_log_sense(struct scsi_cmnd * scp,
2256 struct sdebug_dev_info * devip)
2257{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002258 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002259 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002260 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002261
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002262 memset(arr, 0, sizeof(arr));
2263 ppc = cmd[1] & 0x2;
2264 sp = cmd[1] & 0x1;
2265 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002266 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002267 return check_condition_result;
2268 }
2269 pcontrol = (cmd[2] & 0xc0) >> 6;
2270 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002271 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002272 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002273 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002274 if (0 == subpcode) {
2275 switch (pcode) {
2276 case 0x0: /* Supported log pages log page */
2277 n = 4;
2278 arr[n++] = 0x0; /* this page */
2279 arr[n++] = 0xd; /* Temperature */
2280 arr[n++] = 0x2f; /* Informational exceptions */
2281 arr[3] = n - 4;
2282 break;
2283 case 0xd: /* Temperature log page */
2284 arr[3] = resp_temp_l_pg(arr + 4);
2285 break;
2286 case 0x2f: /* Informational exceptions log page */
2287 arr[3] = resp_ie_l_pg(arr + 4);
2288 break;
2289 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002290 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002291 return check_condition_result;
2292 }
2293 } else if (0xff == subpcode) {
2294 arr[0] |= 0x40;
2295 arr[1] = subpcode;
2296 switch (pcode) {
2297 case 0x0: /* Supported log pages and subpages log page */
2298 n = 4;
2299 arr[n++] = 0x0;
2300 arr[n++] = 0x0; /* 0,0 page */
2301 arr[n++] = 0x0;
2302 arr[n++] = 0xff; /* this page */
2303 arr[n++] = 0xd;
2304 arr[n++] = 0x0; /* Temperature */
2305 arr[n++] = 0x2f;
2306 arr[n++] = 0x0; /* Informational exceptions */
2307 arr[3] = n - 4;
2308 break;
2309 case 0xd: /* Temperature subpages */
2310 n = 4;
2311 arr[n++] = 0xd;
2312 arr[n++] = 0x0; /* Temperature */
2313 arr[3] = n - 4;
2314 break;
2315 case 0x2f: /* Informational exceptions subpages */
2316 n = 4;
2317 arr[n++] = 0x2f;
2318 arr[n++] = 0x0; /* Informational exceptions */
2319 arr[3] = n - 4;
2320 break;
2321 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002322 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002323 return check_condition_result;
2324 }
2325 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002326 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002327 return check_condition_result;
2328 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002329 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002330 return fill_from_dev_buffer(scp, arr,
2331 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2332}
2333
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002334static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002335 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002337 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002338 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 return check_condition_result;
2340 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002341 /* transfer length excessive (tie in to block limits VPD page) */
2342 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002343 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002344 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002345 return check_condition_result;
2346 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002347 return 0;
2348}
2349
Akinobu Mitaa4517512013-07-08 16:01:57 -07002350/* Returns number of bytes copied or -1 if error. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002351static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2352 bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002353{
2354 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002355 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002356 struct scsi_data_buffer *sdb;
2357 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002358
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002359 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002360 sdb = scsi_out(scmd);
2361 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002362 } else {
2363 sdb = scsi_in(scmd);
2364 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002365 }
2366
2367 if (!sdb->length)
2368 return 0;
2369 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2370 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002371
2372 block = do_div(lba, sdebug_store_sectors);
2373 if (block + num > sdebug_store_sectors)
2374 rest = block + num - sdebug_store_sectors;
2375
Dave Gordon386ecb12015-06-30 14:58:57 -07002376 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002377 fake_storep + (block * sdebug_sector_size),
2378 (num - rest) * sdebug_sector_size, 0, do_write);
2379 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002380 return ret;
2381
2382 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002383 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002384 fake_storep, rest * sdebug_sector_size,
2385 (num - rest) * sdebug_sector_size, do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002386 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002387
2388 return ret;
2389}
2390
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002391/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2392 * arr into fake_store(lba,num) and return true. If comparison fails then
2393 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002394static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002395{
2396 bool res;
2397 u64 block, rest = 0;
2398 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002399 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002400
2401 block = do_div(lba, store_blks);
2402 if (block + num > store_blks)
2403 rest = block + num - store_blks;
2404
2405 res = !memcmp(fake_storep + (block * lb_size), arr,
2406 (num - rest) * lb_size);
2407 if (!res)
2408 return res;
2409 if (rest)
2410 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2411 rest * lb_size);
2412 if (!res)
2413 return res;
2414 arr += num * lb_size;
2415 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2416 if (rest)
2417 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2418 rest * lb_size);
2419 return res;
2420}
2421
Akinobu Mita51d648a2013-09-18 21:27:28 +09002422static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002423{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002424 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002425
Douglas Gilbert773642d2016-04-25 12:16:28 -04002426 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002427 csum = (__force __be16)ip_compute_csum(buf, len);
2428 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002429 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002430
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002431 return csum;
2432}
2433
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002434static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002435 sector_t sector, u32 ei_lba)
2436{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002437 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002438
2439 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002440 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002441 (unsigned long)sector,
2442 be16_to_cpu(sdt->guard_tag),
2443 be16_to_cpu(csum));
2444 return 0x01;
2445 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002446 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002447 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002448 pr_err("REF check failed on sector %lu\n",
2449 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002450 return 0x03;
2451 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002452 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002453 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002454 pr_err("REF check failed on sector %lu\n",
2455 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002456 return 0x03;
2457 }
2458 return 0;
2459}
2460
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002461static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002462 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002463{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002464 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002465 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002466 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002467 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002468
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002469 /* Bytes of protection data to copy into sgl */
2470 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002471
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002472 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2473 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2474 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2475
2476 while (sg_miter_next(&miter) && resid > 0) {
2477 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002478 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002479 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002480
2481 if (dif_store_end < start + len)
2482 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002483
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002484 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002485
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002486 if (read)
2487 memcpy(paddr, start, len - rest);
2488 else
2489 memcpy(start, paddr, len - rest);
2490
2491 if (rest) {
2492 if (read)
2493 memcpy(paddr + len - rest, dif_storep, rest);
2494 else
2495 memcpy(dif_storep, paddr + len - rest, rest);
2496 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002497
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002498 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002499 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002500 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002501 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002502}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002503
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002504static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2505 unsigned int sectors, u32 ei_lba)
2506{
2507 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002508 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002509 sector_t sector;
2510
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002511 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002512 int ret;
2513
2514 sector = start_sec + i;
2515 sdt = dif_store(sector);
2516
Akinobu Mita51d648a2013-09-18 21:27:28 +09002517 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002518 continue;
2519
2520 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2521 if (ret) {
2522 dif_errors++;
2523 return ret;
2524 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002525 }
2526
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002527 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002528 dix_reads++;
2529
2530 return 0;
2531}
2532
Douglas Gilbertfd321192016-04-25 12:16:33 -04002533static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002534{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002535 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002536 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002537 u64 lba;
2538 u32 num;
2539 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002540 unsigned long iflags;
2541 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002542 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002543
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002544 switch (cmd[0]) {
2545 case READ_16:
2546 ei_lba = 0;
2547 lba = get_unaligned_be64(cmd + 2);
2548 num = get_unaligned_be32(cmd + 10);
2549 check_prot = true;
2550 break;
2551 case READ_10:
2552 ei_lba = 0;
2553 lba = get_unaligned_be32(cmd + 2);
2554 num = get_unaligned_be16(cmd + 7);
2555 check_prot = true;
2556 break;
2557 case READ_6:
2558 ei_lba = 0;
2559 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2560 (u32)(cmd[1] & 0x1f) << 16;
2561 num = (0 == cmd[4]) ? 256 : cmd[4];
2562 check_prot = true;
2563 break;
2564 case READ_12:
2565 ei_lba = 0;
2566 lba = get_unaligned_be32(cmd + 2);
2567 num = get_unaligned_be32(cmd + 6);
2568 check_prot = true;
2569 break;
2570 case XDWRITEREAD_10:
2571 ei_lba = 0;
2572 lba = get_unaligned_be32(cmd + 2);
2573 num = get_unaligned_be16(cmd + 7);
2574 check_prot = false;
2575 break;
2576 default: /* assume READ(32) */
2577 lba = get_unaligned_be64(cmd + 12);
2578 ei_lba = get_unaligned_be32(cmd + 20);
2579 num = get_unaligned_be32(cmd + 28);
2580 check_prot = false;
2581 break;
2582 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002583 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002584 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002585 (cmd[1] & 0xe0)) {
2586 mk_sense_invalid_opcode(scp);
2587 return check_condition_result;
2588 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002589 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2590 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002591 (cmd[1] & 0xe0) == 0)
2592 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2593 "to DIF device\n");
2594 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002595 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002596 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002597
Douglas Gilbertc4837392016-05-06 00:40:26 -04002598 if (sqcp) {
2599 if (sqcp->inj_short)
2600 num /= 2;
2601 }
2602 } else
2603 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002604
2605 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002606 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002607 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2608 return check_condition_result;
2609 }
2610 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002611 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002612 /* needs work to find which cdb byte 'num' comes from */
2613 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2614 return check_condition_result;
2615 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002616
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002617 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2618 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2619 ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002620 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002621 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002622 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002623 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2624 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002625 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2626 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002627 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002628 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002629 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 return check_condition_result;
2631 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002632
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002633 read_lock_irqsave(&atomic_rw, iflags);
2634
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002635 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002636 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002637 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002638
2639 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002640 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002641 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002642 return illegal_condition_result;
2643 }
2644 }
2645
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002646 ret = do_device_access(scp, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002648 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002649 return DID_ERROR << 16;
2650
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002651 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002652
Douglas Gilbertc4837392016-05-06 00:40:26 -04002653 if (unlikely(sqcp)) {
2654 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002655 mk_sense_buffer(scp, RECOVERED_ERROR,
2656 THRESHOLD_EXCEEDED, 0);
2657 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002658 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002659 mk_sense_buffer(scp, ABORTED_COMMAND,
2660 TRANSPORT_PROBLEM, ACK_NAK_TO);
2661 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002662 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002663 /* Logical block guard check failed */
2664 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2665 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002666 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002667 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2668 return illegal_condition_result;
2669 }
2670 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002671 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672}
2673
Tomas Winkler58a86352015-07-28 16:54:23 +03002674static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002675{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002676 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002677
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002678 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002679 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002680 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002681
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002682 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002683 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002684
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002685 if (c >= 0x20 && c < 0x7e)
2686 n += scnprintf(b + n, sizeof(b) - n,
2687 " %c ", buf[i+j]);
2688 else
2689 n += scnprintf(b + n, sizeof(b) - n,
2690 "%02x ", buf[i+j]);
2691 }
2692 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002693 }
2694}
2695
2696static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002697 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002698{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002699 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002700 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002701 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002702 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002703 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002704 int dpage_offset;
2705 struct sg_mapping_iter diter;
2706 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002707
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002708 BUG_ON(scsi_sg_count(SCpnt) == 0);
2709 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2710
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002711 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2712 scsi_prot_sg_count(SCpnt),
2713 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2714 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2715 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002716
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002717 /* For each protection page */
2718 while (sg_miter_next(&piter)) {
2719 dpage_offset = 0;
2720 if (WARN_ON(!sg_miter_next(&diter))) {
2721 ret = 0x01;
2722 goto out;
2723 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002724
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002725 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002726 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002727 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002728 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002729 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002730 if (dpage_offset >= diter.length) {
2731 if (WARN_ON(!sg_miter_next(&diter))) {
2732 ret = 0x01;
2733 goto out;
2734 }
2735 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002736 }
2737
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002738 sdt = piter.addr + ppage_offset;
2739 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002740
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002741 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002742 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002743 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002744 goto out;
2745 }
2746
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002747 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002748 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002749 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002750 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002751 diter.consumed = dpage_offset;
2752 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002753 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002754 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002755
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002756 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002757 dix_writes++;
2758
2759 return 0;
2760
2761out:
2762 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002763 sg_miter_stop(&diter);
2764 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002765 return ret;
2766}
2767
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002768static unsigned long lba_to_map_index(sector_t lba)
2769{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002770 if (sdebug_unmap_alignment)
2771 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2772 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002773 return lba;
2774}
2775
2776static sector_t map_index_to_lba(unsigned long index)
2777{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002778 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002779
Douglas Gilbert773642d2016-04-25 12:16:28 -04002780 if (sdebug_unmap_alignment)
2781 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002782 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002783}
2784
Martin K. Petersen44d92692009-10-15 14:45:27 -04002785static unsigned int map_state(sector_t lba, unsigned int *num)
2786{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002787 sector_t end;
2788 unsigned int mapped;
2789 unsigned long index;
2790 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002791
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002792 index = lba_to_map_index(lba);
2793 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002794
2795 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002796 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002797 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002798 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002799
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002800 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002801 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002802 return mapped;
2803}
2804
2805static void map_region(sector_t lba, unsigned int len)
2806{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002807 sector_t end = lba + len;
2808
Martin K. Petersen44d92692009-10-15 14:45:27 -04002809 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002810 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002811
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002812 if (index < map_size)
2813 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002814
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002815 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002816 }
2817}
2818
2819static void unmap_region(sector_t lba, unsigned int len)
2820{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002821 sector_t end = lba + len;
2822
Martin K. Petersen44d92692009-10-15 14:45:27 -04002823 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002824 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002825
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002826 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002827 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002828 index < map_size) {
2829 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002830 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002831 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002832 lba * sdebug_sector_size,
2833 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002834 sdebug_sector_size *
2835 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002836 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002837 if (dif_storep) {
2838 memset(dif_storep + lba, 0xff,
2839 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002840 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002841 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002842 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002843 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002844 }
2845}
2846
Douglas Gilbertfd321192016-04-25 12:16:33 -04002847static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002849 u8 *cmd = scp->cmnd;
2850 u64 lba;
2851 u32 num;
2852 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002854 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002855 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002857 switch (cmd[0]) {
2858 case WRITE_16:
2859 ei_lba = 0;
2860 lba = get_unaligned_be64(cmd + 2);
2861 num = get_unaligned_be32(cmd + 10);
2862 check_prot = true;
2863 break;
2864 case WRITE_10:
2865 ei_lba = 0;
2866 lba = get_unaligned_be32(cmd + 2);
2867 num = get_unaligned_be16(cmd + 7);
2868 check_prot = true;
2869 break;
2870 case WRITE_6:
2871 ei_lba = 0;
2872 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2873 (u32)(cmd[1] & 0x1f) << 16;
2874 num = (0 == cmd[4]) ? 256 : cmd[4];
2875 check_prot = true;
2876 break;
2877 case WRITE_12:
2878 ei_lba = 0;
2879 lba = get_unaligned_be32(cmd + 2);
2880 num = get_unaligned_be32(cmd + 6);
2881 check_prot = true;
2882 break;
2883 case 0x53: /* XDWRITEREAD(10) */
2884 ei_lba = 0;
2885 lba = get_unaligned_be32(cmd + 2);
2886 num = get_unaligned_be16(cmd + 7);
2887 check_prot = false;
2888 break;
2889 default: /* assume WRITE(32) */
2890 lba = get_unaligned_be64(cmd + 12);
2891 ei_lba = get_unaligned_be32(cmd + 20);
2892 num = get_unaligned_be32(cmd + 28);
2893 check_prot = false;
2894 break;
2895 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002896 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002897 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002898 (cmd[1] & 0xe0)) {
2899 mk_sense_invalid_opcode(scp);
2900 return check_condition_result;
2901 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002902 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2903 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002904 (cmd[1] & 0xe0) == 0)
2905 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2906 "to DIF device\n");
2907 }
2908
2909 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002910 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002911 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2912 return check_condition_result;
2913 }
2914 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002915 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002916 /* needs work to find which cdb byte 'num' comes from */
2917 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2918 return check_condition_result;
2919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002921 write_lock_irqsave(&atomic_rw, iflags);
2922
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002923 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002924 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002925 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002926
2927 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002928 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002929 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002930 return illegal_condition_result;
2931 }
2932 }
2933
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002934 ret = do_device_access(scp, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002935 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04002936 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002938 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04002939 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002940 else if (unlikely(sdebug_verbose &&
2941 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002942 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002943 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002944 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002945
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002946 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002947 struct sdebug_queued_cmd *sqcp =
2948 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002949
Douglas Gilbertc4837392016-05-06 00:40:26 -04002950 if (sqcp) {
2951 if (sqcp->inj_recovered) {
2952 mk_sense_buffer(scp, RECOVERED_ERROR,
2953 THRESHOLD_EXCEEDED, 0);
2954 return check_condition_result;
2955 } else if (sqcp->inj_dif) {
2956 /* Logical block guard check failed */
2957 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2958 return illegal_condition_result;
2959 } else if (sqcp->inj_dix) {
2960 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2961 return illegal_condition_result;
2962 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002963 }
2964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 return 0;
2966}
2967
Douglas Gilbertfd321192016-04-25 12:16:33 -04002968static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2969 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002970{
2971 unsigned long iflags;
2972 unsigned long long i;
2973 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002974 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002975
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002976 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002977 if (ret)
2978 return ret;
2979
2980 write_lock_irqsave(&atomic_rw, iflags);
2981
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002982 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002983 unmap_region(lba, num);
2984 goto out;
2985 }
2986
Douglas Gilbert773642d2016-04-25 12:16:28 -04002987 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002988 /* if ndob then zero 1 logical block, else fetch 1 logical block */
2989 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002990 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002991 ret = 0;
2992 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04002993 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2994 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002995
2996 if (-1 == ret) {
2997 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002998 return DID_ERROR << 16;
2999 } else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003000 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003001 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
3002 my_name, "write same",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003003 num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003004
3005 /* Copy first sector to remaining blocks */
3006 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003007 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3008 fake_storep + lba_off,
3009 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003010
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003011 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003012 map_region(lba, num);
3013out:
3014 write_unlock_irqrestore(&atomic_rw, iflags);
3015
3016 return 0;
3017}
3018
Douglas Gilbertfd321192016-04-25 12:16:33 -04003019static int resp_write_same_10(struct scsi_cmnd *scp,
3020 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003021{
3022 u8 *cmd = scp->cmnd;
3023 u32 lba;
3024 u16 num;
3025 u32 ei_lba = 0;
3026 bool unmap = false;
3027
3028 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003029 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003030 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3031 return check_condition_result;
3032 } else
3033 unmap = true;
3034 }
3035 lba = get_unaligned_be32(cmd + 2);
3036 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003037 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003038 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3039 return check_condition_result;
3040 }
3041 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3042}
3043
Douglas Gilbertfd321192016-04-25 12:16:33 -04003044static int resp_write_same_16(struct scsi_cmnd *scp,
3045 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003046{
3047 u8 *cmd = scp->cmnd;
3048 u64 lba;
3049 u32 num;
3050 u32 ei_lba = 0;
3051 bool unmap = false;
3052 bool ndob = false;
3053
3054 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003055 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003056 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3057 return check_condition_result;
3058 } else
3059 unmap = true;
3060 }
3061 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3062 ndob = true;
3063 lba = get_unaligned_be64(cmd + 2);
3064 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003065 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003066 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3067 return check_condition_result;
3068 }
3069 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3070}
3071
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003072/* Note the mode field is in the same position as the (lower) service action
3073 * field. For the Report supported operation codes command, SPC-4 suggests
3074 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003075static int resp_write_buffer(struct scsi_cmnd *scp,
3076 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003077{
3078 u8 *cmd = scp->cmnd;
3079 struct scsi_device *sdp = scp->device;
3080 struct sdebug_dev_info *dp;
3081 u8 mode;
3082
3083 mode = cmd[1] & 0x1f;
3084 switch (mode) {
3085 case 0x4: /* download microcode (MC) and activate (ACT) */
3086 /* set UAs on this device only */
3087 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3088 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3089 break;
3090 case 0x5: /* download MC, save and ACT */
3091 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3092 break;
3093 case 0x6: /* download MC with offsets and ACT */
3094 /* set UAs on most devices (LUs) in this target */
3095 list_for_each_entry(dp,
3096 &devip->sdbg_host->dev_info_list,
3097 dev_list)
3098 if (dp->target == sdp->id) {
3099 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3100 if (devip != dp)
3101 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3102 dp->uas_bm);
3103 }
3104 break;
3105 case 0x7: /* download MC with offsets, save, and ACT */
3106 /* set UA on all devices (LUs) in this target */
3107 list_for_each_entry(dp,
3108 &devip->sdbg_host->dev_info_list,
3109 dev_list)
3110 if (dp->target == sdp->id)
3111 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3112 dp->uas_bm);
3113 break;
3114 default:
3115 /* do nothing for this command for other mode values */
3116 break;
3117 }
3118 return 0;
3119}
3120
Douglas Gilbertfd321192016-04-25 12:16:33 -04003121static int resp_comp_write(struct scsi_cmnd *scp,
3122 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003123{
3124 u8 *cmd = scp->cmnd;
3125 u8 *arr;
3126 u8 *fake_storep_hold;
3127 u64 lba;
3128 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003129 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003130 u8 num;
3131 unsigned long iflags;
3132 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003133 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003134
Douglas Gilbertd467d312014-11-26 12:33:48 -05003135 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003136 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3137 if (0 == num)
3138 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003139 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003140 (cmd[1] & 0xe0)) {
3141 mk_sense_invalid_opcode(scp);
3142 return check_condition_result;
3143 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003144 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3145 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003146 (cmd[1] & 0xe0) == 0)
3147 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3148 "to DIF device\n");
3149
3150 /* inline check_device_access_params() */
3151 if (lba + num > sdebug_capacity) {
3152 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3153 return check_condition_result;
3154 }
3155 /* transfer length excessive (tie in to block limits VPD page) */
3156 if (num > sdebug_store_sectors) {
3157 /* needs work to find which cdb byte 'num' comes from */
3158 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3159 return check_condition_result;
3160 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003161 dnum = 2 * num;
3162 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3163 if (NULL == arr) {
3164 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3165 INSUFF_RES_ASCQ);
3166 return check_condition_result;
3167 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003168
3169 write_lock_irqsave(&atomic_rw, iflags);
3170
3171 /* trick do_device_access() to fetch both compare and write buffers
3172 * from data-in into arr. Safe (atomic) since write_lock held. */
3173 fake_storep_hold = fake_storep;
3174 fake_storep = arr;
3175 ret = do_device_access(scp, 0, dnum, true);
3176 fake_storep = fake_storep_hold;
3177 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003178 retval = DID_ERROR << 16;
3179 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003180 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003181 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3182 "indicated=%u, IO sent=%d bytes\n", my_name,
3183 dnum * lb_size, ret);
3184 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003185 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003186 retval = check_condition_result;
3187 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003188 }
3189 if (scsi_debug_lbp())
3190 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003191cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003192 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003193 kfree(arr);
3194 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003195}
3196
Martin K. Petersen44d92692009-10-15 14:45:27 -04003197struct unmap_block_desc {
3198 __be64 lba;
3199 __be32 blocks;
3200 __be32 __reserved;
3201};
3202
Douglas Gilbertfd321192016-04-25 12:16:33 -04003203static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003204{
3205 unsigned char *buf;
3206 struct unmap_block_desc *desc;
3207 unsigned int i, payload_len, descriptors;
3208 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003209 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003210
Martin K. Petersen44d92692009-10-15 14:45:27 -04003211
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003212 if (!scsi_debug_lbp())
3213 return 0; /* fib and say its done */
3214 payload_len = get_unaligned_be16(scp->cmnd + 7);
3215 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003216
3217 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003218 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003219 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003220 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003221 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003222
Douglas Gilbertb333a812016-04-25 12:16:30 -04003223 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003224 if (!buf) {
3225 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3226 INSUFF_RES_ASCQ);
3227 return check_condition_result;
3228 }
3229
3230 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003231
3232 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3233 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3234
3235 desc = (void *)&buf[8];
3236
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003237 write_lock_irqsave(&atomic_rw, iflags);
3238
Martin K. Petersen44d92692009-10-15 14:45:27 -04003239 for (i = 0 ; i < descriptors ; i++) {
3240 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3241 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3242
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003243 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003244 if (ret)
3245 goto out;
3246
3247 unmap_region(lba, num);
3248 }
3249
3250 ret = 0;
3251
3252out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003253 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003254 kfree(buf);
3255
3256 return ret;
3257}
3258
3259#define SDEBUG_GET_LBA_STATUS_LEN 32
3260
Douglas Gilbertfd321192016-04-25 12:16:33 -04003261static int resp_get_lba_status(struct scsi_cmnd *scp,
3262 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003263{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003264 u8 *cmd = scp->cmnd;
3265 u64 lba;
3266 u32 alloc_len, mapped, num;
3267 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003268 int ret;
3269
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003270 lba = get_unaligned_be64(cmd + 2);
3271 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003272
3273 if (alloc_len < 24)
3274 return 0;
3275
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003276 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003277 if (ret)
3278 return ret;
3279
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003280 if (scsi_debug_lbp())
3281 mapped = map_state(lba, &num);
3282 else {
3283 mapped = 1;
3284 /* following just in case virtual_gb changed */
3285 sdebug_capacity = get_sdebug_capacity();
3286 if (sdebug_capacity - lba <= 0xffffffff)
3287 num = sdebug_capacity - lba;
3288 else
3289 num = 0xffffffff;
3290 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003291
3292 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003293 put_unaligned_be32(20, arr); /* Parameter Data Length */
3294 put_unaligned_be64(lba, arr + 8); /* LBA */
3295 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3296 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003297
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003298 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003299}
3300
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003301#define RL_BUCKET_ELEMS 8
3302
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003303/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3304 * (W-LUN), the normal Linux scanning logic does not associate it with a
3305 * device (e.g. /dev/sg7). The following magic will make that association:
3306 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3307 * where <n> is a host number. If there are multiple targets in a host then
3308 * the above will associate a W-LUN to each target. To only get a W-LUN
3309 * for target 2, then use "echo '- 2 49409' > scan" .
3310 */
3311static int resp_report_luns(struct scsi_cmnd *scp,
3312 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003314 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003315 unsigned int alloc_len;
3316 unsigned char select_report;
3317 u64 lun;
3318 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003319 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003320 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3321 unsigned int wlun_cnt; /* report luns W-LUN count */
3322 unsigned int tlun_cnt; /* total LUN count */
3323 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003324 int k, j, n, res;
3325 unsigned int off_rsp = 0;
3326 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003328 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003329
3330 select_report = cmd[2];
3331 alloc_len = get_unaligned_be32(cmd + 6);
3332
3333 if (alloc_len < 4) {
3334 pr_err("alloc len too small %d\n", alloc_len);
3335 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 return check_condition_result;
3337 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003338
3339 switch (select_report) {
3340 case 0: /* all LUNs apart from W-LUNs */
3341 lun_cnt = sdebug_max_luns;
3342 wlun_cnt = 0;
3343 break;
3344 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003345 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003346 wlun_cnt = 1;
3347 break;
3348 case 2: /* all LUNs */
3349 lun_cnt = sdebug_max_luns;
3350 wlun_cnt = 1;
3351 break;
3352 case 0x10: /* only administrative LUs */
3353 case 0x11: /* see SPC-5 */
3354 case 0x12: /* only subsiduary LUs owned by referenced LU */
3355 default:
3356 pr_debug("select report invalid %d\n", select_report);
3357 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3358 return check_condition_result;
3359 }
3360
3361 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003362 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003363
3364 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003365 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3366 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003367 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3368 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3369
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003370 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003371 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003372 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3373 memset(arr, 0, sizeof(arr));
3374 lun_p = (struct scsi_lun *)&arr[0];
3375 if (k == 0) {
3376 put_unaligned_be32(rlen, &arr[0]);
3377 ++lun_p;
3378 j = 1;
3379 }
3380 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3381 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3382 break;
3383 int_to_scsilun(lun++, lun_p);
3384 }
3385 if (j < RL_BUCKET_ELEMS)
3386 break;
3387 n = j * sz_lun;
3388 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3389 if (res)
3390 return res;
3391 off_rsp += n;
3392 }
3393 if (wlun_cnt) {
3394 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3395 ++j;
3396 }
3397 if (j > 0)
3398 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003399 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400}
3401
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003402static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3403 unsigned int num, struct sdebug_dev_info *devip)
3404{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003405 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003406 unsigned char *kaddr, *buf;
3407 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003408 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003409 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003410
3411 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003412 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003413 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003414 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3415 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003416 return check_condition_result;
3417 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003418
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003419 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003420
3421 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003422 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3423 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003424
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003425 while (sg_miter_next(&miter)) {
3426 kaddr = miter.addr;
3427 for (j = 0; j < miter.length; j++)
3428 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003429
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003430 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003431 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003432 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003433 kfree(buf);
3434
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003435 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003436}
3437
Douglas Gilbertfd321192016-04-25 12:16:33 -04003438static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3439 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003440{
3441 u8 *cmd = scp->cmnd;
3442 u64 lba;
3443 u32 num;
3444 int errsts;
3445
3446 if (!scsi_bidi_cmnd(scp)) {
3447 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3448 INSUFF_RES_ASCQ);
3449 return check_condition_result;
3450 }
3451 errsts = resp_read_dt0(scp, devip);
3452 if (errsts)
3453 return errsts;
3454 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3455 errsts = resp_write_dt0(scp, devip);
3456 if (errsts)
3457 return errsts;
3458 }
3459 lba = get_unaligned_be32(cmd + 2);
3460 num = get_unaligned_be16(cmd + 7);
3461 return resp_xdwriteread(scp, lba, num, devip);
3462}
3463
Douglas Gilbertc4837392016-05-06 00:40:26 -04003464static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3465{
3466 struct sdebug_queue *sqp = sdebug_q_arr;
3467
3468 if (sdebug_mq_active) {
3469 u32 tag = blk_mq_unique_tag(cmnd->request);
3470 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3471
3472 if (unlikely(hwq >= submit_queues)) {
3473 pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3474 hwq %= submit_queues;
3475 }
3476 pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3477 return sqp + hwq;
3478 } else
3479 return sqp;
3480}
3481
3482/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003483static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003485 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003486 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003488 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003489 struct sdebug_queued_cmd *sqcp;
3490 struct scsi_cmnd *scp;
3491 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492
Douglas Gilbertc4837392016-05-06 00:40:26 -04003493 qc_idx = sd_dp->qc_idx;
3494 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3495 if (sdebug_statistics) {
3496 atomic_inc(&sdebug_completions);
3497 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3498 atomic_inc(&sdebug_miss_cpus);
3499 }
3500 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3501 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 return;
3503 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003504 spin_lock_irqsave(&sqp->qc_lock, iflags);
3505 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003506 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003507 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003508 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3509 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3510 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 return;
3512 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003513 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003514 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003515 atomic_dec(&devip->num_in_q);
3516 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003517 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003518 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003519 retiring = 1;
3520
3521 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003522 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3523 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003524 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003525 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003527
3528 if (unlikely(retiring)) { /* user has reduced max_queue */
3529 int k, retval;
3530
3531 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003532 if (qc_idx >= retval) {
3533 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003534 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003535 return;
3536 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003537 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003538 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003539 atomic_set(&retired_max_queue, 0);
3540 else
3541 atomic_set(&retired_max_queue, k + 1);
3542 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003543 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003544 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545}
3546
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003547/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003548static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003549{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003550 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3551 hrt);
3552 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003553 return HRTIMER_NORESTART;
3554}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555
Douglas Gilberta10bc122016-04-25 12:16:32 -04003556/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003557static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003558{
3559 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3560 ew.work);
3561 sdebug_q_cmd_complete(sd_dp);
3562}
3563
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003564static bool got_shared_uuid;
3565static uuid_be shared_uuid;
3566
Douglas Gilbertfd321192016-04-25 12:16:33 -04003567static struct sdebug_dev_info *sdebug_device_create(
3568 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003569{
3570 struct sdebug_dev_info *devip;
3571
3572 devip = kzalloc(sizeof(*devip), flags);
3573 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003574 if (sdebug_uuid_ctl == 1)
3575 uuid_be_gen(&devip->lu_name);
3576 else if (sdebug_uuid_ctl == 2) {
3577 if (got_shared_uuid)
3578 devip->lu_name = shared_uuid;
3579 else {
3580 uuid_be_gen(&shared_uuid);
3581 got_shared_uuid = true;
3582 devip->lu_name = shared_uuid;
3583 }
3584 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003585 devip->sdbg_host = sdbg_host;
3586 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3587 }
3588 return devip;
3589}
3590
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003591static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003593 struct sdebug_host_info *sdbg_host;
3594 struct sdebug_dev_info *open_devip = NULL;
3595 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003597 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3598 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003599 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 return NULL;
3601 }
3602 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3603 if ((devip->used) && (devip->channel == sdev->channel) &&
3604 (devip->target == sdev->id) &&
3605 (devip->lun == sdev->lun))
3606 return devip;
3607 else {
3608 if ((!devip->used) && (!open_devip))
3609 open_devip = devip;
3610 }
3611 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003612 if (!open_devip) { /* try and make a new one */
3613 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3614 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003615 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 return NULL;
3617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003619
3620 open_devip->channel = sdev->channel;
3621 open_devip->target = sdev->id;
3622 open_devip->lun = sdev->lun;
3623 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003624 atomic_set(&open_devip->num_in_q, 0);
3625 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003626 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003627 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628}
3629
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003630static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003632 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003633 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003634 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003635 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003636 return 0;
3637}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003639static int scsi_debug_slave_configure(struct scsi_device *sdp)
3640{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003641 struct sdebug_dev_info *devip =
3642 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003643
Douglas Gilbert773642d2016-04-25 12:16:28 -04003644 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003645 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003646 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003647 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3648 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3649 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003650 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003651 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003652 return 1; /* no resources, will be marked offline */
3653 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003654 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003655 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003656 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003657 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003658 return 0;
3659}
3660
3661static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3662{
3663 struct sdebug_dev_info *devip =
3664 (struct sdebug_dev_info *)sdp->hostdata;
3665
Douglas Gilbert773642d2016-04-25 12:16:28 -04003666 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003667 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003668 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3669 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003670 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003671 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003672 sdp->hostdata = NULL;
3673 }
3674}
3675
Douglas Gilbertc4837392016-05-06 00:40:26 -04003676static void stop_qc_helper(struct sdebug_defer *sd_dp)
3677{
3678 if (!sd_dp)
3679 return;
3680 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3681 hrtimer_cancel(&sd_dp->hrt);
3682 else if (sdebug_jdelay < 0)
3683 cancel_work_sync(&sd_dp->ew.work);
3684}
3685
Douglas Gilberta10bc122016-04-25 12:16:32 -04003686/* If @cmnd found deletes its timer or work queue and returns true; else
3687 returns false */
3688static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003689{
3690 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003691 int j, k, qmax, r_qmax;
3692 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003693 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003694 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003695 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003696
Douglas Gilbertc4837392016-05-06 00:40:26 -04003697 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3698 spin_lock_irqsave(&sqp->qc_lock, iflags);
3699 qmax = sdebug_max_queue;
3700 r_qmax = atomic_read(&retired_max_queue);
3701 if (r_qmax > qmax)
3702 qmax = r_qmax;
3703 for (k = 0; k < qmax; ++k) {
3704 if (test_bit(k, sqp->in_use_bm)) {
3705 sqcp = &sqp->qc_arr[k];
3706 if (cmnd != sqcp->a_cmnd)
3707 continue;
3708 /* found */
3709 devip = (struct sdebug_dev_info *)
3710 cmnd->device->hostdata;
3711 if (devip)
3712 atomic_dec(&devip->num_in_q);
3713 sqcp->a_cmnd = NULL;
3714 sd_dp = sqcp->sd_dp;
3715 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3716 stop_qc_helper(sd_dp);
3717 clear_bit(k, sqp->in_use_bm);
3718 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003719 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003720 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003721 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003722 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003723 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003724}
3725
Douglas Gilberta10bc122016-04-25 12:16:32 -04003726/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003727static void stop_all_queued(void)
3728{
3729 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003730 int j, k;
3731 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003732 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003733 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003734 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003735
Douglas Gilbertc4837392016-05-06 00:40:26 -04003736 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3737 spin_lock_irqsave(&sqp->qc_lock, iflags);
3738 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3739 if (test_bit(k, sqp->in_use_bm)) {
3740 sqcp = &sqp->qc_arr[k];
3741 if (sqcp->a_cmnd == NULL)
3742 continue;
3743 devip = (struct sdebug_dev_info *)
3744 sqcp->a_cmnd->device->hostdata;
3745 if (devip)
3746 atomic_dec(&devip->num_in_q);
3747 sqcp->a_cmnd = NULL;
3748 sd_dp = sqcp->sd_dp;
3749 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3750 stop_qc_helper(sd_dp);
3751 clear_bit(k, sqp->in_use_bm);
3752 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003753 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003754 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003755 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757}
3758
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003759/* Free queued command memory on heap */
3760static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003762 int j, k;
3763 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003764 struct sdebug_queued_cmd *sqcp;
3765
Douglas Gilbertc4837392016-05-06 00:40:26 -04003766 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3767 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3768 sqcp = &sqp->qc_arr[k];
3769 kfree(sqcp->sd_dp);
3770 sqcp->sd_dp = NULL;
3771 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773}
3774
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003775static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003777 bool ok;
3778
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003779 ++num_aborts;
3780 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003781 ok = stop_queued_cmnd(SCpnt);
3782 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3783 sdev_printk(KERN_INFO, SCpnt->device,
3784 "%s: command%s found\n", __func__,
3785 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003787 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788}
3789
3790static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3791{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003793 if (SCpnt && SCpnt->device) {
3794 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003795 struct sdebug_dev_info *devip =
3796 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003797
Douglas Gilbert773642d2016-04-25 12:16:28 -04003798 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003799 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003801 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802 }
3803 return SUCCESS;
3804}
3805
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003806static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3807{
3808 struct sdebug_host_info *sdbg_host;
3809 struct sdebug_dev_info *devip;
3810 struct scsi_device *sdp;
3811 struct Scsi_Host *hp;
3812 int k = 0;
3813
3814 ++num_target_resets;
3815 if (!SCpnt)
3816 goto lie;
3817 sdp = SCpnt->device;
3818 if (!sdp)
3819 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003820 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003821 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3822 hp = sdp->host;
3823 if (!hp)
3824 goto lie;
3825 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3826 if (sdbg_host) {
3827 list_for_each_entry(devip,
3828 &sdbg_host->dev_info_list,
3829 dev_list)
3830 if (devip->target == sdp->id) {
3831 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3832 ++k;
3833 }
3834 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003835 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003836 sdev_printk(KERN_INFO, sdp,
3837 "%s: %d device(s) found in target\n", __func__, k);
3838lie:
3839 return SUCCESS;
3840}
3841
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3843{
3844 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003845 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 struct scsi_device * sdp;
3847 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003848 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003851 if (!(SCpnt && SCpnt->device))
3852 goto lie;
3853 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003854 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003855 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3856 hp = sdp->host;
3857 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003858 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003860 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003862 dev_list) {
3863 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3864 ++k;
3865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 }
3867 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003868 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003869 sdev_printk(KERN_INFO, sdp,
3870 "%s: %d device(s) found in host\n", __func__, k);
3871lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 return SUCCESS;
3873}
3874
3875static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3876{
3877 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003878 struct sdebug_dev_info *devip;
3879 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003882 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003883 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 spin_lock(&sdebug_host_list_lock);
3885 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003886 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3887 dev_list) {
3888 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3889 ++k;
3890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 }
3892 spin_unlock(&sdebug_host_list_lock);
3893 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003894 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003895 sdev_printk(KERN_INFO, SCpnt->device,
3896 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 return SUCCESS;
3898}
3899
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003900static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003901 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902{
3903 struct partition * pp;
3904 int starts[SDEBUG_MAX_PARTS + 2];
3905 int sectors_per_part, num_sectors, k;
3906 int heads_by_sects, start_sec, end_sec;
3907
3908 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003909 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003911 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3912 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003913 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003915 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003917 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3919 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003920 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3922 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003923 starts[sdebug_num_parts] = num_sectors;
3924 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
3926 ramp[510] = 0x55; /* magic partition markings */
3927 ramp[511] = 0xAA;
3928 pp = (struct partition *)(ramp + 0x1be);
3929 for (k = 0; starts[k + 1]; ++k, ++pp) {
3930 start_sec = starts[k];
3931 end_sec = starts[k + 1] - 1;
3932 pp->boot_ind = 0;
3933
3934 pp->cyl = start_sec / heads_by_sects;
3935 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3936 / sdebug_sectors_per;
3937 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3938
3939 pp->end_cyl = end_sec / heads_by_sects;
3940 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3941 / sdebug_sectors_per;
3942 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3943
Akinobu Mita150c3542013-08-26 22:08:40 +09003944 pp->start_sect = cpu_to_le32(start_sec);
3945 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 pp->sys_ind = 0x83; /* plain Linux partition */
3947 }
3948}
3949
Douglas Gilbertc4837392016-05-06 00:40:26 -04003950static void block_unblock_all_queues(bool block)
3951{
3952 int j;
3953 struct sdebug_queue *sqp;
3954
3955 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
3956 atomic_set(&sqp->blocked, (int)block);
3957}
3958
3959/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
3960 * commands will be processed normally before triggers occur.
3961 */
3962static void tweak_cmnd_count(void)
3963{
3964 int count, modulo;
3965
3966 modulo = abs(sdebug_every_nth);
3967 if (modulo < 2)
3968 return;
3969 block_unblock_all_queues(true);
3970 count = atomic_read(&sdebug_cmnd_count);
3971 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
3972 block_unblock_all_queues(false);
3973}
3974
3975static void clear_queue_stats(void)
3976{
3977 atomic_set(&sdebug_cmnd_count, 0);
3978 atomic_set(&sdebug_completions, 0);
3979 atomic_set(&sdebug_miss_cpus, 0);
3980 atomic_set(&sdebug_a_tsf, 0);
3981}
3982
3983static void setup_inject(struct sdebug_queue *sqp,
3984 struct sdebug_queued_cmd *sqcp)
3985{
3986 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
3987 return;
3988 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
3989 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
3990 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
3991 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
3992 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
3993}
3994
3995/* Complete the processing of the thread that queued a SCSI command to this
3996 * driver. It either completes the command by calling cmnd_done() or
3997 * schedules a hr timer or work queue then returns 0. Returns
3998 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
3999 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004000static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4001 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004003 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004004 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004005 struct sdebug_queue *sqp;
4006 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004007 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004008 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004010 if (unlikely(devip == NULL)) {
4011 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004012 scsi_result = DID_NO_CONNECT << 16;
4013 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004015 sdp = cmnd->device;
4016
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004017 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004018 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4019 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004020 if (delta_jiff == 0)
4021 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004023 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004024 sqp = get_queue(cmnd);
4025 spin_lock_irqsave(&sqp->qc_lock, iflags);
4026 if (unlikely(atomic_read(&sqp->blocked))) {
4027 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4028 return SCSI_MLQUEUE_HOST_BUSY;
4029 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004030 num_in_q = atomic_read(&devip->num_in_q);
4031 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004032 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004033 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004034 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004035 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004036 goto respond_in_thread;
4037 } else
4038 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004039 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004040 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4041 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004042 if ((num_in_q == (qdepth - 1)) &&
4043 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004044 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004045 atomic_set(&sdebug_a_tsf, 0);
4046 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004047 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004049 }
4050
Douglas Gilbertc4837392016-05-06 00:40:26 -04004051 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004052 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004053 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004054 if (scsi_result)
4055 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004056 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004057 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004058 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004059 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004060 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004061 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004062 (scsi_result ? "status: TASK SET FULL" :
4063 "report: host busy"));
4064 if (scsi_result)
4065 goto respond_in_thread;
4066 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004067 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004069 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004070 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004071 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004072 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004073 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004074 cmnd->result = scsi_result;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004075 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004076 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4077 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4078 setup_inject(sqp, sqcp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004079 if (delta_jiff > 0 || sdebug_ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004080 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004081
Douglas Gilbertb333a812016-04-25 12:16:30 -04004082 if (delta_jiff > 0) {
4083 struct timespec ts;
4084
4085 jiffies_to_timespec(delta_jiff, &ts);
4086 kt = ktime_set(ts.tv_sec, ts.tv_nsec);
4087 } else
4088 kt = ktime_set(0, sdebug_ndelay);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004089 if (NULL == sd_dp) {
4090 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4091 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004092 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004093 sqcp->sd_dp = sd_dp;
4094 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004095 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004096 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004097 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4098 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004099 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004100 if (sdebug_statistics)
4101 sd_dp->issuing_cpu = raw_smp_processor_id();
4102 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4103 } else { /* jdelay < 0, use work queue */
Douglas Gilberta10bc122016-04-25 12:16:32 -04004104 if (NULL == sd_dp) {
4105 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4106 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004107 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004108 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004109 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4110 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004111 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004112 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004113 if (sdebug_statistics)
4114 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilberta10bc122016-04-25 12:16:32 -04004115 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004116 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004117 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4118 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004119 sdev_printk(KERN_INFO, sdp,
4120 "%s: num_in_q=%d +1, %s%s\n", __func__,
4121 num_in_q, (inject ? "<inject> " : ""),
4122 "status: TASK SET FULL");
4123 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004124
4125respond_in_thread: /* call back to mid-layer using invocation thread */
4126 cmnd->result = scsi_result;
4127 cmnd->scsi_done(cmnd);
4128 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004130
Douglas Gilbert23183912006-09-16 20:30:47 -04004131/* Note: The following macros create attribute files in the
4132 /sys/module/scsi_debug/parameters directory. Unfortunately this
4133 driver is unaware of a change and cannot trigger auxiliary actions
4134 as it can when the corresponding attribute in the
4135 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4136 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004137module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4138module_param_named(ato, sdebug_ato, int, S_IRUGO);
4139module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004140module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004141module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4142module_param_named(dif, sdebug_dif, int, S_IRUGO);
4143module_param_named(dix, sdebug_dix, int, S_IRUGO);
4144module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4145module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4146module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4147module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4148module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4149module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4150module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4151module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4152module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4153module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4154module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4155module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4156module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4157module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4158module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4159module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4160module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4161module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4162module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4163module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
4164module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4165module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4166module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4167module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004168module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004169module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004170module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004171module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4172module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4173module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4174module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4175module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004176module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004177module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004178 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004179module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004180 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181
4182MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4183MODULE_DESCRIPTION("SCSI debug adapter driver");
4184MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004185MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
4187MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004188MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004189MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004190MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004191MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004192MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4193MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004194MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004195MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004196MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004197MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004198MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004199MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4200MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4201MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004202MODULE_PARM_DESC(lbprz,
4203 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004204MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004205MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004206MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4207MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004208MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004209MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004211MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004212MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004213MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004214MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004216MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004217MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004218MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004219MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004220MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004221MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004222MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4223MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004224MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4225MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004226MODULE_PARM_DESC(uuid_ctl,
4227 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004228MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004229MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4230MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004232#define SDEBUG_INFO_LEN 256
4233static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234
4235static const char * scsi_debug_info(struct Scsi_Host * shp)
4236{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004237 int k;
4238
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004239 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4240 my_name, SDEBUG_VERSION, sdebug_version_date);
4241 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004242 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004243 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4244 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4245 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4246 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 return sdebug_info;
4248}
4249
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004250/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004251static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4252 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253{
Al Viroc8ed5552013-03-31 01:46:06 -04004254 char arr[16];
4255 int opts;
4256 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257
Al Viroc8ed5552013-03-31 01:46:06 -04004258 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4259 return -EACCES;
4260 memcpy(arr, buffer, minLen);
4261 arr[minLen] = '\0';
4262 if (1 != sscanf(arr, "%d", &opts))
4263 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004264 sdebug_opts = opts;
4265 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4266 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4267 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004268 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004269 return length;
4270}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004272/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4273 * same for each scsi_debug host (if more than one). Some of the counters
4274 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004275static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4276{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004277 int f, j, l;
4278 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004279
Douglas Gilbertc4837392016-05-06 00:40:26 -04004280 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4281 SDEBUG_VERSION, sdebug_version_date);
4282 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4283 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4284 sdebug_opts, sdebug_every_nth);
4285 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4286 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4287 sdebug_sector_size, "bytes");
4288 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4289 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4290 num_aborts);
4291 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4292 num_dev_resets, num_target_resets, num_bus_resets,
4293 num_host_resets);
4294 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4295 dix_reads, dix_writes, dif_errors);
4296 seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4297 TICK_NSEC / 1000, "statistics", sdebug_statistics,
4298 sdebug_mq_active);
4299 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4300 atomic_read(&sdebug_cmnd_count),
4301 atomic_read(&sdebug_completions),
4302 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4303 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004304
Douglas Gilbertc4837392016-05-06 00:40:26 -04004305 seq_printf(m, "submit_queues=%d\n", submit_queues);
4306 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4307 seq_printf(m, " queue %d:\n", j);
4308 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4309 if (f != sdebug_max_queue) {
4310 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4311 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4312 "first,last bits", f, l);
4313 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004314 }
Al Viroc8ed5552013-03-31 01:46:06 -04004315 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316}
4317
Akinobu Mita82069372013-10-14 22:48:04 +09004318static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004320 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004322/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4323 * of delay is jiffies.
4324 */
Akinobu Mita82069372013-10-14 22:48:04 +09004325static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4326 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004328 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004330 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004331 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004332 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004333 int j, k;
4334 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004335
Douglas Gilbertc4837392016-05-06 00:40:26 -04004336 block_unblock_all_queues(true);
4337 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4338 ++j, ++sqp) {
4339 k = find_first_bit(sqp->in_use_bm,
4340 sdebug_max_queue);
4341 if (k != sdebug_max_queue) {
4342 res = -EBUSY; /* queued commands */
4343 break;
4344 }
4345 }
4346 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004347 /* make sure sdebug_defer instances get
4348 * re-allocated for new delay variant */
4349 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004350 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004351 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004352 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004353 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004355 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 }
4357 return -EINVAL;
4358}
Akinobu Mita82069372013-10-14 22:48:04 +09004359static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004361static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4362{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004363 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004364}
4365/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004366/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004367static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004368 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004369{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004370 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004371
4372 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004373 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004374 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004375 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004376 int j, k;
4377 struct sdebug_queue *sqp;
4378
4379 block_unblock_all_queues(true);
4380 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4381 ++j, ++sqp) {
4382 k = find_first_bit(sqp->in_use_bm,
4383 sdebug_max_queue);
4384 if (k != sdebug_max_queue) {
4385 res = -EBUSY; /* queued commands */
4386 break;
4387 }
4388 }
4389 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004390 /* make sure sdebug_defer instances get
4391 * re-allocated for new delay variant */
4392 free_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004393 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004394 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4395 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004396 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004397 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004398 }
4399 return res;
4400 }
4401 return -EINVAL;
4402}
4403static DRIVER_ATTR_RW(ndelay);
4404
Akinobu Mita82069372013-10-14 22:48:04 +09004405static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004407 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408}
4409
Akinobu Mita82069372013-10-14 22:48:04 +09004410static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4411 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412{
4413 int opts;
4414 char work[20];
4415
4416 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07004417 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 if (1 == sscanf(&work[2], "%x", &opts))
4419 goto opts_done;
4420 } else {
4421 if (1 == sscanf(work, "%d", &opts))
4422 goto opts_done;
4423 }
4424 }
4425 return -EINVAL;
4426opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004427 sdebug_opts = opts;
4428 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4429 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004430 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 return count;
4432}
Akinobu Mita82069372013-10-14 22:48:04 +09004433static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
Akinobu Mita82069372013-10-14 22:48:04 +09004435static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004437 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438}
Akinobu Mita82069372013-10-14 22:48:04 +09004439static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4440 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441{
4442 int n;
4443
4444 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004445 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 return count;
4447 }
4448 return -EINVAL;
4449}
Akinobu Mita82069372013-10-14 22:48:04 +09004450static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451
Akinobu Mita82069372013-10-14 22:48:04 +09004452static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004454 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455}
Akinobu Mita82069372013-10-14 22:48:04 +09004456static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4457 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458{
4459 int n;
4460
4461 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004462 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 return count;
4464 }
4465 return -EINVAL;
4466}
Akinobu Mita82069372013-10-14 22:48:04 +09004467static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468
Akinobu Mita82069372013-10-14 22:48:04 +09004469static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004470{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004471 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004472}
Akinobu Mita82069372013-10-14 22:48:04 +09004473static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4474 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004475{
4476 int n;
4477
4478 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004479 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004480 sdebug_fake_rw = (sdebug_fake_rw > 0);
4481 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004482 if ((0 == n) && (NULL == fake_storep)) {
4483 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004484 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004485 1048576;
4486
4487 fake_storep = vmalloc(sz);
4488 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004489 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004490 return -ENOMEM;
4491 }
4492 memset(fake_storep, 0, sz);
4493 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004494 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004495 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004496 return count;
4497 }
4498 return -EINVAL;
4499}
Akinobu Mita82069372013-10-14 22:48:04 +09004500static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004501
Akinobu Mita82069372013-10-14 22:48:04 +09004502static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004503{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004504 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004505}
Akinobu Mita82069372013-10-14 22:48:04 +09004506static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4507 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004508{
4509 int n;
4510
4511 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004512 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004513 return count;
4514 }
4515 return -EINVAL;
4516}
Akinobu Mita82069372013-10-14 22:48:04 +09004517static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004518
Akinobu Mita82069372013-10-14 22:48:04 +09004519static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004521 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522}
Akinobu Mita82069372013-10-14 22:48:04 +09004523static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4524 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525{
4526 int n;
4527
4528 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004529 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 sdebug_max_tgts_luns();
4531 return count;
4532 }
4533 return -EINVAL;
4534}
Akinobu Mita82069372013-10-14 22:48:04 +09004535static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
Akinobu Mita82069372013-10-14 22:48:04 +09004537static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004539 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540}
Akinobu Mita82069372013-10-14 22:48:04 +09004541static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542
Akinobu Mita82069372013-10-14 22:48:04 +09004543static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004545 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546}
Akinobu Mita82069372013-10-14 22:48:04 +09004547static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548
Akinobu Mita82069372013-10-14 22:48:04 +09004549static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004551 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552}
Akinobu Mita82069372013-10-14 22:48:04 +09004553static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4554 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555{
4556 int nth;
4557
4558 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004559 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004560 if (nth && !sdebug_statistics) {
4561 pr_info("every_nth needs statistics=1, set it\n");
4562 sdebug_statistics = true;
4563 }
4564 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 return count;
4566 }
4567 return -EINVAL;
4568}
Akinobu Mita82069372013-10-14 22:48:04 +09004569static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570
Akinobu Mita82069372013-10-14 22:48:04 +09004571static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004573 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574}
Akinobu Mita82069372013-10-14 22:48:04 +09004575static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4576 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577{
4578 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004579 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580
4581 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004582 if (n > 256) {
4583 pr_warn("max_luns can be no more than 256\n");
4584 return -EINVAL;
4585 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004586 changed = (sdebug_max_luns != n);
4587 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004589 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004590 struct sdebug_host_info *sdhp;
4591 struct sdebug_dev_info *dp;
4592
4593 spin_lock(&sdebug_host_list_lock);
4594 list_for_each_entry(sdhp, &sdebug_host_list,
4595 host_list) {
4596 list_for_each_entry(dp, &sdhp->dev_info_list,
4597 dev_list) {
4598 set_bit(SDEBUG_UA_LUNS_CHANGED,
4599 dp->uas_bm);
4600 }
4601 }
4602 spin_unlock(&sdebug_host_list_lock);
4603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 return count;
4605 }
4606 return -EINVAL;
4607}
Akinobu Mita82069372013-10-14 22:48:04 +09004608static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609
Akinobu Mita82069372013-10-14 22:48:04 +09004610static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004611{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004612 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004613}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004614/* N.B. max_queue can be changed while there are queued commands. In flight
4615 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004616static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4617 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004618{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004619 int j, n, k, a;
4620 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004621
4622 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004623 (n <= SDEBUG_CANQUEUE)) {
4624 block_unblock_all_queues(true);
4625 k = 0;
4626 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4627 ++j, ++sqp) {
4628 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4629 if (a > k)
4630 k = a;
4631 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004632 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004633 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004634 atomic_set(&retired_max_queue, 0);
4635 else if (k >= n)
4636 atomic_set(&retired_max_queue, k + 1);
4637 else
4638 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004639 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004640 return count;
4641 }
4642 return -EINVAL;
4643}
Akinobu Mita82069372013-10-14 22:48:04 +09004644static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004645
Akinobu Mita82069372013-10-14 22:48:04 +09004646static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004647{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004648 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004649}
Akinobu Mita82069372013-10-14 22:48:04 +09004650static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004651
Akinobu Mita82069372013-10-14 22:48:04 +09004652static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004654 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655}
Akinobu Mita82069372013-10-14 22:48:04 +09004656static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657
Akinobu Mita82069372013-10-14 22:48:04 +09004658static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004659{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004660 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004661}
Akinobu Mita82069372013-10-14 22:48:04 +09004662static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4663 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004664{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004665 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004666 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004667
4668 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004669 changed = (sdebug_virtual_gb != n);
4670 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004671 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004672 if (changed) {
4673 struct sdebug_host_info *sdhp;
4674 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004675
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004676 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004677 list_for_each_entry(sdhp, &sdebug_host_list,
4678 host_list) {
4679 list_for_each_entry(dp, &sdhp->dev_info_list,
4680 dev_list) {
4681 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4682 dp->uas_bm);
4683 }
4684 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004685 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004686 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004687 return count;
4688 }
4689 return -EINVAL;
4690}
Akinobu Mita82069372013-10-14 22:48:04 +09004691static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004692
Akinobu Mita82069372013-10-14 22:48:04 +09004693static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004695 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696}
4697
Douglas Gilbertfd321192016-04-25 12:16:33 -04004698static int sdebug_add_adapter(void);
4699static void sdebug_remove_adapter(void);
4700
Akinobu Mita82069372013-10-14 22:48:04 +09004701static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4702 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004704 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004706 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 if (delta_hosts > 0) {
4709 do {
4710 sdebug_add_adapter();
4711 } while (--delta_hosts);
4712 } else if (delta_hosts < 0) {
4713 do {
4714 sdebug_remove_adapter();
4715 } while (++delta_hosts);
4716 }
4717 return count;
4718}
Akinobu Mita82069372013-10-14 22:48:04 +09004719static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720
Akinobu Mita82069372013-10-14 22:48:04 +09004721static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004722{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004723 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004724}
Akinobu Mita82069372013-10-14 22:48:04 +09004725static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4726 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004727{
4728 int n;
4729
4730 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004731 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004732 return count;
4733 }
4734 return -EINVAL;
4735}
Akinobu Mita82069372013-10-14 22:48:04 +09004736static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004737
Douglas Gilbertc4837392016-05-06 00:40:26 -04004738static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4739{
4740 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4741}
4742static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4743 size_t count)
4744{
4745 int n;
4746
4747 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4748 if (n > 0)
4749 sdebug_statistics = true;
4750 else {
4751 clear_queue_stats();
4752 sdebug_statistics = false;
4753 }
4754 return count;
4755 }
4756 return -EINVAL;
4757}
4758static DRIVER_ATTR_RW(statistics);
4759
Akinobu Mita82069372013-10-14 22:48:04 +09004760static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04004761{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004762 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004763}
Akinobu Mita82069372013-10-14 22:48:04 +09004764static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004765
Douglas Gilbertc4837392016-05-06 00:40:26 -04004766static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4767{
4768 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4769}
4770static DRIVER_ATTR_RO(submit_queues);
4771
Akinobu Mita82069372013-10-14 22:48:04 +09004772static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004773{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004774 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004775}
Akinobu Mita82069372013-10-14 22:48:04 +09004776static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004777
Akinobu Mita82069372013-10-14 22:48:04 +09004778static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004779{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004780 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004781}
Akinobu Mita82069372013-10-14 22:48:04 +09004782static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004783
Akinobu Mita82069372013-10-14 22:48:04 +09004784static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004785{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004786 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004787}
Akinobu Mita82069372013-10-14 22:48:04 +09004788static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004789
Akinobu Mita82069372013-10-14 22:48:04 +09004790static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004791{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004792 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004793}
Akinobu Mita82069372013-10-14 22:48:04 +09004794static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004795
Akinobu Mita82069372013-10-14 22:48:04 +09004796static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004797{
4798 ssize_t count;
4799
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004800 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004801 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4802 sdebug_store_sectors);
4803
Tejun Heoc7badc92015-02-13 14:37:51 -08004804 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4805 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004806 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004807 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004808
4809 return count;
4810}
Akinobu Mita82069372013-10-14 22:48:04 +09004811static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004812
Akinobu Mita82069372013-10-14 22:48:04 +09004813static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004814{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004815 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004816}
Akinobu Mita82069372013-10-14 22:48:04 +09004817static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4818 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004819{
4820 int n;
4821
4822 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004823 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004824 return count;
4825 }
4826 return -EINVAL;
4827}
Akinobu Mita82069372013-10-14 22:48:04 +09004828static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004829
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004830static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4831{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004832 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004833}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004834/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004835static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4836 size_t count)
4837{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004838 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004839
4840 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004841 sdebug_host_lock = (n > 0);
4842 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004843 }
4844 return -EINVAL;
4845}
4846static DRIVER_ATTR_RW(host_lock);
4847
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004848static ssize_t strict_show(struct device_driver *ddp, char *buf)
4849{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004850 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004851}
4852static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4853 size_t count)
4854{
4855 int n;
4856
4857 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004858 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004859 return count;
4860 }
4861 return -EINVAL;
4862}
4863static DRIVER_ATTR_RW(strict);
4864
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004865static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
4866{
4867 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
4868}
4869static DRIVER_ATTR_RO(uuid_ctl);
4870
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004871
Akinobu Mita82069372013-10-14 22:48:04 +09004872/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004873 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4874 files (over those found in the /sys/module/scsi_debug/parameters
4875 directory) is that auxiliary actions can be triggered when an attribute
4876 is changed. For example see: sdebug_add_host_store() above.
4877 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004878
Akinobu Mita82069372013-10-14 22:48:04 +09004879static struct attribute *sdebug_drv_attrs[] = {
4880 &driver_attr_delay.attr,
4881 &driver_attr_opts.attr,
4882 &driver_attr_ptype.attr,
4883 &driver_attr_dsense.attr,
4884 &driver_attr_fake_rw.attr,
4885 &driver_attr_no_lun_0.attr,
4886 &driver_attr_num_tgts.attr,
4887 &driver_attr_dev_size_mb.attr,
4888 &driver_attr_num_parts.attr,
4889 &driver_attr_every_nth.attr,
4890 &driver_attr_max_luns.attr,
4891 &driver_attr_max_queue.attr,
4892 &driver_attr_no_uld.attr,
4893 &driver_attr_scsi_level.attr,
4894 &driver_attr_virtual_gb.attr,
4895 &driver_attr_add_host.attr,
4896 &driver_attr_vpd_use_hostno.attr,
4897 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004898 &driver_attr_statistics.attr,
4899 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004900 &driver_attr_dix.attr,
4901 &driver_attr_dif.attr,
4902 &driver_attr_guard.attr,
4903 &driver_attr_ato.attr,
4904 &driver_attr_map.attr,
4905 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004906 &driver_attr_host_lock.attr,
4907 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004908 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004909 &driver_attr_uuid_ctl.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004910 NULL,
4911};
4912ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004914static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004915
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916static int __init scsi_debug_init(void)
4917{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004918 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 int host_to_add;
4920 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004921 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004923 atomic_set(&retired_max_queue, 0);
4924
Douglas Gilbert773642d2016-04-25 12:16:28 -04004925 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004926 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04004927 sdebug_ndelay = 0;
4928 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04004929 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004930
Douglas Gilbert773642d2016-04-25 12:16:28 -04004931 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04004932 case 512:
4933 case 1024:
4934 case 2048:
4935 case 4096:
4936 break;
4937 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004938 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004939 return -EINVAL;
4940 }
4941
Douglas Gilbert773642d2016-04-25 12:16:28 -04004942 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02004943 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004944 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02004945 case T10_PI_TYPE1_PROTECTION:
4946 case T10_PI_TYPE2_PROTECTION:
4947 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004948 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004949 break;
4950
4951 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03004952 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004953 return -EINVAL;
4954 }
4955
Douglas Gilbert773642d2016-04-25 12:16:28 -04004956 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004957 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004958 return -EINVAL;
4959 }
4960
Douglas Gilbert773642d2016-04-25 12:16:28 -04004961 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004962 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004963 return -EINVAL;
4964 }
4965
Douglas Gilbert773642d2016-04-25 12:16:28 -04004966 if (sdebug_physblk_exp > 15) {
4967 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004968 return -EINVAL;
4969 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004970 if (sdebug_max_luns > 256) {
4971 pr_warn("max_luns can be no more than 256, use default\n");
4972 sdebug_max_luns = DEF_MAX_LUNS;
4973 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004974
Douglas Gilbert773642d2016-04-25 12:16:28 -04004975 if (sdebug_lowest_aligned > 0x3fff) {
4976 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004977 return -EINVAL;
4978 }
4979
Douglas Gilbertc4837392016-05-06 00:40:26 -04004980 if (submit_queues < 1) {
4981 pr_err("submit_queues must be 1 or more\n");
4982 return -EINVAL;
4983 }
4984 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
4985 GFP_KERNEL);
4986 if (sdebug_q_arr == NULL)
4987 return -ENOMEM;
4988 for (k = 0; k < submit_queues; ++k)
4989 spin_lock_init(&sdebug_q_arr[k].qc_lock);
4990
Douglas Gilbert773642d2016-04-25 12:16:28 -04004991 if (sdebug_dev_size_mb < 1)
4992 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
4993 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4994 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004995 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996
4997 /* play around with geometry, don't waste too much on track 0 */
4998 sdebug_heads = 8;
4999 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005000 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005002 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005003 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5005 (sdebug_sectors_per * sdebug_heads);
5006 if (sdebug_cylinders_per >= 1024) {
5007 /* other LLDs do this; implies >= 1GB ram disk ... */
5008 sdebug_heads = 255;
5009 sdebug_sectors_per = 63;
5010 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5011 (sdebug_sectors_per * sdebug_heads);
5012 }
5013
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005014 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005015 fake_storep = vmalloc(sz);
5016 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005017 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005018 ret = -ENOMEM;
5019 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005020 }
5021 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005022 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005023 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025
Douglas Gilbert773642d2016-04-25 12:16:28 -04005026 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005027 int dif_size;
5028
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005029 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005030 dif_storep = vmalloc(dif_size);
5031
Tomas Winklerc12879702015-07-28 16:54:20 +03005032 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005033
5034 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005035 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005036 ret = -ENOMEM;
5037 goto free_vm;
5038 }
5039
5040 memset(dif_storep, 0xff, dif_size);
5041 }
5042
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005043 /* Logical Block Provisioning */
5044 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005045 sdebug_unmap_max_blocks =
5046 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005047
Douglas Gilbert773642d2016-04-25 12:16:28 -04005048 sdebug_unmap_max_desc =
5049 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005050
Douglas Gilbert773642d2016-04-25 12:16:28 -04005051 sdebug_unmap_granularity =
5052 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005053
Douglas Gilbert773642d2016-04-25 12:16:28 -04005054 if (sdebug_unmap_alignment &&
5055 sdebug_unmap_granularity <=
5056 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005057 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005058 ret = -EINVAL;
5059 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005060 }
5061
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005062 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5063 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005064
Tomas Winklerc12879702015-07-28 16:54:20 +03005065 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005066
5067 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005068 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005069 ret = -ENOMEM;
5070 goto free_vm;
5071 }
5072
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005073 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005074
5075 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005076 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005077 map_region(0, 2);
5078 }
5079
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005080 pseudo_primary = root_device_register("pseudo_0");
5081 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005082 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005083 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005084 goto free_vm;
5085 }
5086 ret = bus_register(&pseudo_lld_bus);
5087 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005088 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005089 goto dev_unreg;
5090 }
5091 ret = driver_register(&sdebug_driverfs_driver);
5092 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005093 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005094 goto bus_unreg;
5095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096
Douglas Gilbert773642d2016-04-25 12:16:28 -04005097 host_to_add = sdebug_add_host;
5098 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099
5100 for (k = 0; k < host_to_add; k++) {
5101 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005102 pr_err("sdebug_add_adapter failed k=%d\n", k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 break;
5104 }
5105 }
5106
Douglas Gilbert773642d2016-04-25 12:16:28 -04005107 if (sdebug_verbose)
5108 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005109
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005111
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005112bus_unreg:
5113 bus_unregister(&pseudo_lld_bus);
5114dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005115 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005116free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005117 vfree(map_storep);
5118 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005119 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005120free_q_arr:
5121 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005122 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123}
5124
5125static void __exit scsi_debug_exit(void)
5126{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005127 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128
5129 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005130 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 for (; k; k--)
5132 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 driver_unregister(&sdebug_driverfs_driver);
5134 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005135 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136
Tomas Winklerde232af2015-07-28 16:54:22 +03005137 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005139 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140}
5141
5142device_initcall(scsi_debug_init);
5143module_exit(scsi_debug_exit);
5144
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145static void sdebug_release_adapter(struct device * dev)
5146{
5147 struct sdebug_host_info *sdbg_host;
5148
5149 sdbg_host = to_sdebug_host(dev);
5150 kfree(sdbg_host);
5151}
5152
5153static int sdebug_add_adapter(void)
5154{
5155 int k, devs_per_host;
5156 int error = 0;
5157 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005158 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005160 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 if (NULL == sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005162 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 return -ENOMEM;
5164 }
5165
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
5167
Douglas Gilbert773642d2016-04-25 12:16:28 -04005168 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005170 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5171 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005172 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173 error = -ENOMEM;
5174 goto clean;
5175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 }
5177
5178 spin_lock(&sdebug_host_list_lock);
5179 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5180 spin_unlock(&sdebug_host_list_lock);
5181
5182 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005183 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005185 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186
5187 error = device_register(&sdbg_host->dev);
5188
5189 if (error)
5190 goto clean;
5191
Douglas Gilbert773642d2016-04-25 12:16:28 -04005192 ++sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 return error;
5194
5195clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005196 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5197 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 list_del(&sdbg_devinfo->dev_list);
5199 kfree(sdbg_devinfo);
5200 }
5201
5202 kfree(sdbg_host);
5203 return error;
5204}
5205
5206static void sdebug_remove_adapter(void)
5207{
5208 struct sdebug_host_info * sdbg_host = NULL;
5209
5210 spin_lock(&sdebug_host_list_lock);
5211 if (!list_empty(&sdebug_host_list)) {
5212 sdbg_host = list_entry(sdebug_host_list.prev,
5213 struct sdebug_host_info, host_list);
5214 list_del(&sdbg_host->host_list);
5215 }
5216 spin_unlock(&sdebug_host_list_lock);
5217
5218 if (!sdbg_host)
5219 return;
5220
Douglas Gilbert773642d2016-04-25 12:16:28 -04005221 device_unregister(&sdbg_host->dev);
5222 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223}
5224
Douglas Gilbertfd321192016-04-25 12:16:33 -04005225static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005226{
5227 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005228 struct sdebug_dev_info *devip;
5229
Douglas Gilbertc4837392016-05-06 00:40:26 -04005230 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005231 devip = (struct sdebug_dev_info *)sdev->hostdata;
5232 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005233 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005234 return -ENODEV;
5235 }
5236 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005237
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005238 if (qdepth < 1)
5239 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005240 /* allow to exceed max host qc_arr elements for testing */
5241 if (qdepth > SDEBUG_CANQUEUE + 10)
5242 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005243 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005244
Douglas Gilbert773642d2016-04-25 12:16:28 -04005245 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005246 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005247 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005248 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005249 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005250 return sdev->queue_depth;
5251}
5252
Douglas Gilbertc4837392016-05-06 00:40:26 -04005253static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005254{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005255 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005256 if (sdebug_every_nth < -1)
5257 sdebug_every_nth = -1;
5258 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005259 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005260 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005261 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005262 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005263 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005264 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005265}
5266
Douglas Gilbertfd321192016-04-25 12:16:33 -04005267static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5268 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005269{
5270 u8 sdeb_i;
5271 struct scsi_device *sdp = scp->device;
5272 const struct opcode_info_t *oip;
5273 const struct opcode_info_t *r_oip;
5274 struct sdebug_dev_info *devip;
5275 u8 *cmd = scp->cmnd;
5276 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5277 int k, na;
5278 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005279 u32 flags;
5280 u16 sa;
5281 u8 opcode = cmd[0];
5282 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005283
5284 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005285 if (sdebug_statistics)
5286 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005287 if (unlikely(sdebug_verbose &&
5288 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005289 char b[120];
5290 int n, len, sb;
5291
5292 len = scp->cmd_len;
5293 sb = (int)sizeof(b);
5294 if (len > 32)
5295 strcpy(b, "too long, over 32 bytes");
5296 else {
5297 for (k = 0, n = 0; k < len && n < sb; ++k)
5298 n += scnprintf(b + n, sb - n, "%02x ",
5299 (u32)cmd[k]);
5300 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005301 if (sdebug_mq_active)
5302 sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5303 my_name, blk_mq_unique_tag(scp->request),
5304 b);
5305 else
5306 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5307 b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005308 }
Tomas Winkler34d55432015-07-28 16:54:21 +03005309 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005310 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5311 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005312
5313 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5314 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5315 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005316 if (unlikely(!devip)) {
5317 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005318 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005319 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005320 }
5321 na = oip->num_attached;
5322 r_pfp = oip->pfp;
5323 if (na) { /* multiple commands with this opcode */
5324 r_oip = oip;
5325 if (FF_SA & r_oip->flags) {
5326 if (F_SA_LOW & oip->flags)
5327 sa = 0x1f & cmd[1];
5328 else
5329 sa = get_unaligned_be16(cmd + 8);
5330 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5331 if (opcode == oip->opcode && sa == oip->sa)
5332 break;
5333 }
5334 } else { /* since no service action only check opcode */
5335 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5336 if (opcode == oip->opcode)
5337 break;
5338 }
5339 }
5340 if (k > na) {
5341 if (F_SA_LOW & r_oip->flags)
5342 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5343 else if (F_SA_HIGH & r_oip->flags)
5344 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5345 else
5346 mk_sense_invalid_opcode(scp);
5347 goto check_cond;
5348 }
5349 } /* else (when na==0) we assume the oip is a match */
5350 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005351 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005352 mk_sense_invalid_opcode(scp);
5353 goto check_cond;
5354 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005355 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005356 if (sdebug_verbose)
5357 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5358 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005359 mk_sense_invalid_opcode(scp);
5360 goto check_cond;
5361 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005362 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005363 u8 rem;
5364 int j;
5365
5366 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5367 rem = ~oip->len_mask[k] & cmd[k];
5368 if (rem) {
5369 for (j = 7; j >= 0; --j, rem <<= 1) {
5370 if (0x80 & rem)
5371 break;
5372 }
5373 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5374 goto check_cond;
5375 }
5376 }
5377 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005378 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005379 find_first_bit(devip->uas_bm,
5380 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005381 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005382 if (errsts)
5383 goto check_cond;
5384 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005385 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005386 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005387 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005388 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5389 "%s\n", my_name, "initializing command "
5390 "required");
5391 errsts = check_condition_result;
5392 goto fini;
5393 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005394 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005395 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005396 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005397 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005398 return 0; /* ignore command: make trouble */
5399 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005400 if (likely(oip->pfp))
5401 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005402 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5403 errsts = r_pfp(scp, devip);
5404
5405fini:
5406 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005407 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005408check_cond:
5409 return schedule_resp(scp, devip, check_condition_result, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005410err_out:
5411 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005412}
5413
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005414static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005415 .show_info = scsi_debug_show_info,
5416 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005417 .proc_name = sdebug_proc_name,
5418 .name = "SCSI DEBUG",
5419 .info = scsi_debug_info,
5420 .slave_alloc = scsi_debug_slave_alloc,
5421 .slave_configure = scsi_debug_slave_configure,
5422 .slave_destroy = scsi_debug_slave_destroy,
5423 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005424 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005425 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005426 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005427 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005428 .eh_target_reset_handler = scsi_debug_target_reset,
5429 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005430 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005431 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005432 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005433 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005434 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005435 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005436 .use_clustering = DISABLE_CLUSTERING,
5437 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005438 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005439};
5440
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441static int sdebug_driver_probe(struct device * dev)
5442{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005443 int error = 0;
5444 struct sdebug_host_info *sdbg_host;
5445 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005446 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447
5448 sdbg_host = to_sdebug_host(dev);
5449
Douglas Gilbert773642d2016-04-25 12:16:28 -04005450 sdebug_driver_template.can_queue = sdebug_max_queue;
5451 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005452 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005453 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5454 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005455 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005456 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005458 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005459 if (submit_queues > nr_cpu_ids) {
5460 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%d\n",
5461 my_name, submit_queues, nr_cpu_ids);
5462 submit_queues = nr_cpu_ids;
5463 }
5464 /* Decide whether to tell scsi subsystem that we want mq */
5465 /* Following should give the same answer for each host */
5466 sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5467 if (sdebug_mq_active)
5468 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469
5470 sdbg_host->shost = hpnt;
5471 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005472 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5473 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005475 hpnt->max_id = sdebug_num_tgts;
5476 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005477 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005479 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005480
Douglas Gilbert773642d2016-04-25 12:16:28 -04005481 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005482
Christoph Hellwig8475c812016-09-11 19:35:41 +02005483 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005484 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005485 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005486 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005487 break;
5488
Christoph Hellwig8475c812016-09-11 19:35:41 +02005489 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005490 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005491 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005492 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005493 break;
5494
Christoph Hellwig8475c812016-09-11 19:35:41 +02005495 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005496 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005497 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005498 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005499 break;
5500
5501 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005502 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005503 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005504 break;
5505 }
5506
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005507 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005508
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005509 if (have_dif_prot || sdebug_dix)
5510 pr_info("host protection%s%s%s%s%s%s%s\n",
5511 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5512 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5513 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5514 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5515 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5516 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5517 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005518
Douglas Gilbert773642d2016-04-25 12:16:28 -04005519 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005520 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5521 else
5522 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5523
Douglas Gilbert773642d2016-04-25 12:16:28 -04005524 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5525 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005526 if (sdebug_every_nth) /* need stats counters for every_nth */
5527 sdebug_statistics = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 error = scsi_add_host(hpnt, &sdbg_host->dev);
5529 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005530 pr_err("scsi_add_host failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 error = -ENODEV;
5532 scsi_host_put(hpnt);
5533 } else
5534 scsi_scan_host(hpnt);
5535
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005536 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537}
5538
5539static int sdebug_driver_remove(struct device * dev)
5540{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005542 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543
5544 sdbg_host = to_sdebug_host(dev);
5545
5546 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005547 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 return -ENODEV;
5549 }
5550
5551 scsi_remove_host(sdbg_host->shost);
5552
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005553 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5554 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 list_del(&sdbg_devinfo->dev_list);
5556 kfree(sdbg_devinfo);
5557 }
5558
5559 scsi_host_put(sdbg_host->shost);
5560 return 0;
5561}
5562
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005563static int pseudo_lld_bus_match(struct device *dev,
5564 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005566 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005568
5569static struct bus_type pseudo_lld_bus = {
5570 .name = "pseudo",
5571 .match = pseudo_lld_bus_match,
5572 .probe = sdebug_driver_probe,
5573 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005574 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005575};