blob: 40de305de1d5f479d438cc6d93e46c696ccdf75a [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>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050044
45#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090046
Martin K. Petersen44d92692009-10-15 14:45:27 -040047#include <asm/unaligned.h>
48
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090049#include <scsi/scsi.h>
50#include <scsi/scsi_cmnd.h>
51#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <scsi/scsi_host.h>
53#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090054#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040055#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040056#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Martin K. Petersenc6a44282009-01-04 03:08:19 -050058#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Douglas Gilbert773642d2016-04-25 12:16:28 -040061/* make sure inq_product_rev string corresponds to this version */
62#define SCSI_DEBUG_VERSION "1.86"
63static const char *sdebug_version_date = "20160422";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040064
65#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050067/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040068#define NO_ADDITIONAL_SENSE 0x0
69#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050070#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040072#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050074#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040076#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040077#define UA_RESET_ASC 0x29
78#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050079#define TARGET_CHANGED_ASC 0x3f
80#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050081#define INSUFF_RES_ASC 0x55
82#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040083#define POWER_ON_RESET_ASCQ 0x0
84#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
85#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050086#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070087#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050088#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040089#define THRESHOLD_EXCEEDED 0x5d
90#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050091#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050092#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
93#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050095/* Additional Sense Code Qualifier (ASCQ) */
96#define ACK_NAK_TO 0x3
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99/* Default values for driver parameters */
100#define DEF_NUM_HOST 1
101#define DEF_NUM_TGTS 1
102#define DEF_MAX_LUNS 1
103/* With these defaults, this driver will make 1 host with 1 target
104 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
105 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500106#define DEF_ATO 1
Douglas Gilbertc2206092016-04-25 12:16:31 -0400107#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500109#define DEF_DIF 0
110#define DEF_DIX 0
111#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500113#define DEF_FAKE_RW 0
114#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400115#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500116#define DEF_LBPU 0
117#define DEF_LBPWS 0
118#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600119#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500120#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400121#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500122#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#define DEF_NUM_PARTS 0
124#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500125#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500126#define DEF_PHYSBLK_EXP 0
127#define DEF_PTYPE 0
Martin Pittd9867882012-09-06 12:04:33 +0200128#define DEF_REMOVABLE false
Douglas Gilberte46b0342014-08-05 12:21:53 +0200129#define DEF_SCSI_LEVEL 6 /* INQUIRY, byte2 [6->SPC-4] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500130#define DEF_SECTOR_SIZE 512
131#define DEF_UNMAP_ALIGNMENT 0
132#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400133#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
134#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500135#define DEF_VIRTUAL_GB 0
136#define DEF_VPD_USE_HOSTNO 1
137#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500138#define DEF_STRICT 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400139#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Douglas Gilbert773642d2016-04-25 12:16:28 -0400141/* bit mask values for sdebug_opts */
142#define SDEBUG_OPT_NOISE 1
143#define SDEBUG_OPT_MEDIUM_ERR 2
144#define SDEBUG_OPT_TIMEOUT 4
145#define SDEBUG_OPT_RECOVERED_ERR 8
146#define SDEBUG_OPT_TRANSPORT_ERR 16
147#define SDEBUG_OPT_DIF_ERR 32
148#define SDEBUG_OPT_DIX_ERR 64
149#define SDEBUG_OPT_MAC_TIMEOUT 128
150#define SDEBUG_OPT_SHORT_TRANSFER 0x100
151#define SDEBUG_OPT_Q_NOISE 0x200
152#define SDEBUG_OPT_ALL_TSF 0x400
153#define SDEBUG_OPT_RARE_TSF 0x800
154#define SDEBUG_OPT_N_WCE 0x1000
155#define SDEBUG_OPT_RESET_NOISE 0x2000
156#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
157#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
158 SDEBUG_OPT_RESET_NOISE)
159#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
160 SDEBUG_OPT_TRANSPORT_ERR | \
161 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
162 SDEBUG_OPT_SHORT_TRANSFER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400164 * - a no response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400166 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500167 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400168 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 *
170 * When "every_nth" < 0 then after "- every_nth" commands:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400171 * - a no response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400173 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500174 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400175 * commands if _DEBUG_OPT_TRANSPORT_ERR is set.
176 * This will continue on every subsequent command until some other action
177 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
178 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 */
180
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400181/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in
182 * priority order. In the subset implemented here lower numbers have higher
183 * priority. The UA numbers should be a sequence starting from 0 with
184 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
185#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
186#define SDEBUG_UA_BUS_RESET 1
187#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500188#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500189#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500190#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
191#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
192#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400193
194/* for check_readiness() */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500195#define UAS_ONLY 1 /* check for UAs only */
196#define UAS_TUR 0 /* if no UAs then check if media access possible */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400197
Douglas Gilbert773642d2016-04-25 12:16:28 -0400198/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 * sector on read commands: */
200#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500201#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
204 * or "peripheral device" addressing (value 0) */
205#define SAM2_LUN_ADDRESS_METHOD 0
206
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400207/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
208 * (for response) at one time. Can be reduced by max_queue option. Command
Douglas Gilbertc2206092016-04-25 12:16:31 -0400209 * responses are not queued when jdelay=0 and ndelay=0. The per-device
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400210 * DEF_CMD_PER_LUN can be changed via sysfs:
211 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
212 * SCSI_DEBUG_CANQUEUE. */
213#define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */
214#define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
215#define DEF_CMD_PER_LUN 255
216
217#if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
218#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
219#endif
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400220
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500221/* SCSI opcodes (first byte of cdb) mapped onto these indexes */
222enum sdeb_opcode_index {
223 SDEB_I_INVALID_OPCODE = 0,
224 SDEB_I_INQUIRY = 1,
225 SDEB_I_REPORT_LUNS = 2,
226 SDEB_I_REQUEST_SENSE = 3,
227 SDEB_I_TEST_UNIT_READY = 4,
228 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
229 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
230 SDEB_I_LOG_SENSE = 7,
231 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
232 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
233 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
234 SDEB_I_START_STOP = 11,
235 SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */
236 SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */
237 SDEB_I_MAINT_IN = 14,
238 SDEB_I_MAINT_OUT = 15,
239 SDEB_I_VERIFY = 16, /* 10 only */
240 SDEB_I_VARIABLE_LEN = 17,
241 SDEB_I_RESERVE = 18, /* 6, 10 */
242 SDEB_I_RELEASE = 19, /* 6, 10 */
243 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
244 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
245 SDEB_I_ATA_PT = 22, /* 12, 16 */
246 SDEB_I_SEND_DIAG = 23,
247 SDEB_I_UNMAP = 24,
248 SDEB_I_XDWRITEREAD = 25, /* 10 only */
249 SDEB_I_WRITE_BUFFER = 26,
250 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
251 SDEB_I_SYNC_CACHE = 28, /* 10 only */
252 SDEB_I_COMP_WRITE = 29,
253 SDEB_I_LAST_ELEMENT = 30, /* keep this last */
254};
255
256static const unsigned char opcode_ind_arr[256] = {
257/* 0x0; 0x0->0x1f: 6 byte cdbs */
258 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
259 0, 0, 0, 0,
260 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
261 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
262 SDEB_I_RELEASE,
263 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
264 SDEB_I_ALLOW_REMOVAL, 0,
265/* 0x20; 0x20->0x3f: 10 byte cdbs */
266 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
267 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
268 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
269 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
270/* 0x40; 0x40->0x5f: 10 byte cdbs */
271 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
272 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
273 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
274 SDEB_I_RELEASE,
275 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
276/* 0x60; 0x60->0x7d are reserved */
277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
279 0, SDEB_I_VARIABLE_LEN,
280/* 0x80; 0x80->0x9f: 16 byte cdbs */
281 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
282 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
283 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
284 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
285/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
286 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
287 SDEB_I_MAINT_OUT, 0, 0, 0,
288 SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
289 0, 0, 0, 0,
290 0, 0, 0, 0, 0, 0, 0, 0,
291 0, 0, 0, 0, 0, 0, 0, 0,
292/* 0xc0; 0xc0->0xff: vendor specific */
293 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
294 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
295 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
297};
298
299#define F_D_IN 1
300#define F_D_OUT 2
301#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
302#define F_D_UNKN 8
303#define F_RL_WLUN_OK 0x10
304#define F_SKIP_UA 0x20
305#define F_DELAY_OVERR 0x40
306#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
307#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
308#define F_INV_OP 0x200
309#define F_FAKE_RW 0x400
310#define F_M_ACCESS 0x800 /* media access */
311
312#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
313#define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
314#define FF_SA (F_SA_HIGH | F_SA_LOW)
315
316struct sdebug_dev_info;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500317static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
318static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
319static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
320static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
321static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
322static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
323static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
324static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
325static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
326static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
327static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
328static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
329static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
330static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500331static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
332static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500333static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
334static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
335static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500336static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500337static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500338
339struct opcode_info_t {
340 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff
341 * for terminating element */
342 u8 opcode; /* if num_attached > 0, preferred */
343 u16 sa; /* service action */
344 u32 flags; /* OR-ed set of SDEB_F_* */
345 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
346 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
347 u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */
348 /* ignore cdb bytes after position 15 */
349};
350
351static const struct opcode_info_t msense_iarr[1] = {
352 {0, 0x1a, 0, F_D_IN, NULL, NULL,
353 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
354};
355
356static const struct opcode_info_t mselect_iarr[1] = {
357 {0, 0x15, 0, F_D_OUT, NULL, NULL,
358 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
359};
360
361static const struct opcode_info_t read_iarr[3] = {
362 {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
363 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
364 0, 0, 0, 0} },
365 {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
366 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
367 {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
368 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
369 0xc7, 0, 0, 0, 0} },
370};
371
372static const struct opcode_info_t write_iarr[3] = {
373 {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */
374 {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
375 0, 0, 0, 0} },
376 {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */
377 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
378 {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */
379 {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
380 0xc7, 0, 0, 0, 0} },
381};
382
383static const struct opcode_info_t sa_in_iarr[1] = {
384 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
385 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
386 0xff, 0xff, 0xff, 0, 0xc7} },
387};
388
389static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
390 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
391 NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
392 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
393};
394
395static const struct opcode_info_t maint_in_iarr[2] = {
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500396 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500397 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
398 0xc7, 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500399 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500400 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
401 0, 0} },
402};
403
404static const struct opcode_info_t write_same_iarr[1] = {
405 {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
406 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
407 0xff, 0xff, 0xff, 0x1f, 0xc7} },
408};
409
410static const struct opcode_info_t reserve_iarr[1] = {
411 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
412 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
413};
414
415static const struct opcode_info_t release_iarr[1] = {
416 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
417 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
418};
419
420
421/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
422 * plus the terminating elements for logic that scans this table such as
423 * REPORT SUPPORTED OPERATION CODES. */
424static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
425/* 0 */
426 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
427 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
428 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
429 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
430 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
431 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
432 0, 0} },
433 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
434 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
435 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
436 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
437 {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
438 {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
439 0} },
440 {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
441 {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
442 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
443 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
444 0, 0, 0} },
445 {0, 0x25, 0, F_D_IN, resp_readcap, NULL,
446 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
447 0, 0} },
448 {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
449 {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
450 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */
451/* 10 */
452 {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
453 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
454 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */
455 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
456 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
457 {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
458 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
459 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */
460 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
461 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
462 {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
463 {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
464 0} },
465 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
466 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500467 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
468 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
469 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500470 {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
471 vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
472 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
473 {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
474 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
475 0} },
476 {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
477 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
478 0} },
479/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500480 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
481 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500482 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
483 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
484 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
485 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
486 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
487 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
488 {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
489 {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
490 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
491 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
492 0, 0, 0, 0, 0, 0} },
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500493 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
494 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
495 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500496 {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
497 write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
498 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
499 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
500 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
501 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500502 {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500503 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
504 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
505
506/* 30 */
507 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
508 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
509};
510
Douglas Gilbert817fd662014-11-24 20:18:02 -0500511struct sdebug_scmd_extra_t {
512 bool inj_recovered;
513 bool inj_transport;
514 bool inj_dif;
515 bool inj_dix;
516 bool inj_short;
517};
518
Douglas Gilbert773642d2016-04-25 12:16:28 -0400519static int sdebug_add_host = DEF_NUM_HOST;
520static int sdebug_ato = DEF_ATO;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400521static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400522static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
523static int sdebug_dif = DEF_DIF;
524static int sdebug_dix = DEF_DIX;
525static int sdebug_dsense = DEF_D_SENSE;
526static int sdebug_every_nth = DEF_EVERY_NTH;
527static int sdebug_fake_rw = DEF_FAKE_RW;
528static unsigned int sdebug_guard = DEF_GUARD;
529static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
530static int sdebug_max_luns = DEF_MAX_LUNS;
531static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400532static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400533static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400534static int sdebug_no_lun_0 = DEF_NO_LUN_0;
535static int sdebug_no_uld;
536static int sdebug_num_parts = DEF_NUM_PARTS;
537static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
538static int sdebug_opt_blks = DEF_OPT_BLKS;
539static int sdebug_opts = DEF_OPTS;
540static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
541static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
542static int sdebug_scsi_level = DEF_SCSI_LEVEL;
543static int sdebug_sector_size = DEF_SECTOR_SIZE;
544static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
545static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
546static unsigned int sdebug_lbpu = DEF_LBPU;
547static unsigned int sdebug_lbpws = DEF_LBPWS;
548static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
549static unsigned int sdebug_lbprz = DEF_LBPRZ;
550static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
551static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
552static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
553static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
554static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
555static bool sdebug_removable = DEF_REMOVABLE;
556static bool sdebug_clustering;
557static bool sdebug_host_lock = DEF_HOST_LOCK;
558static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500559static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400560static bool sdebug_verbose;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400562static atomic_t sdebug_cmnd_count;
563static atomic_t sdebug_completions;
564static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566#define DEV_READONLY(TGT) (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400568static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569static sector_t sdebug_capacity; /* in sectors */
570
571/* old BIOS stuff, kernel may get rid of them but some mode sense pages
572 may still need them */
573static int sdebug_heads; /* heads per disk */
574static int sdebug_cylinders_per; /* cylinders per surface */
575static int sdebug_sectors_per; /* sectors per cylinder */
576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577#define SDEBUG_MAX_PARTS 4
578
Martin K. Petersen395cef02009-09-18 17:33:03 -0400579#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900580
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500581static unsigned int scsi_debug_lbp(void)
582{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400583 return 0 == sdebug_fake_rw &&
584 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500585}
586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587struct sdebug_dev_info {
588 struct list_head dev_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 unsigned int channel;
590 unsigned int target;
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200591 u64 lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400593 unsigned long uas_bm[1];
594 atomic_t num_in_q;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500595 char stopped; /* TODO: should be atomic */
596 bool used;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597};
598
599struct sdebug_host_info {
600 struct list_head host_list;
601 struct Scsi_Host *shost;
602 struct device dev;
603 struct list_head dev_info_list;
604};
605
606#define to_sdebug_host(d) \
607 container_of(d, struct sdebug_host_info, dev)
608
609static LIST_HEAD(sdebug_host_list);
610static DEFINE_SPINLOCK(sdebug_host_list_lock);
611
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400612
Douglas Gilberta10bc122016-04-25 12:16:32 -0400613struct sdebug_defer {
614 struct hrtimer hrt;
615 struct execute_work ew;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400616 int qa_indx;
617};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619struct sdebug_queued_cmd {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400620 /* in_use flagged by a bit in queued_in_use_bm[] */
Douglas Gilberta10bc122016-04-25 12:16:32 -0400621 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 struct scsi_cmnd * a_cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623};
624static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400625static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628static unsigned char * fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900629static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400630static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Martin K. Petersen44d92692009-10-15 14:45:27 -0400632static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400633static int num_aborts;
634static int num_dev_resets;
635static int num_target_resets;
636static int num_bus_resets;
637static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500638static int dix_writes;
639static int dix_reads;
640static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642static DEFINE_SPINLOCK(queued_arr_lock);
643static DEFINE_RWLOCK(atomic_rw);
644
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400645static char sdebug_proc_name[] = MY_NAME;
646static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648static struct bus_type pseudo_lld_bus;
649
650static struct device_driver sdebug_driverfs_driver = {
651 .name = sdebug_proc_name,
652 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653};
654
655static const int check_condition_result =
656 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
657
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500658static const int illegal_condition_result =
659 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
660
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400661static const int device_qfull_result =
662 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
663
664static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
665 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
666 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400667static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
668 0, 0, 0x2, 0x4b};
669static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
670 0, 0, 0x0, 0x0};
671
Akinobu Mita14faa942013-09-18 21:27:24 +0900672static void *fake_store(unsigned long long lba)
673{
674 lba = do_div(lba, sdebug_store_sectors);
675
Douglas Gilbert773642d2016-04-25 12:16:28 -0400676 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900677}
678
679static struct sd_dif_tuple *dif_store(sector_t sector)
680{
Arnd Bergmann49413112015-11-20 17:38:28 +0100681 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900682
683 return dif_storep + sector;
684}
685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686static int sdebug_add_adapter(void);
687static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900689static void sdebug_max_tgts_luns(void)
690{
691 struct sdebug_host_info *sdbg_host;
692 struct Scsi_Host *hpnt;
693
694 spin_lock(&sdebug_host_list_lock);
695 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
696 hpnt = sdbg_host->shost;
697 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400698 (sdebug_num_tgts > hpnt->this_id))
699 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900700 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400701 hpnt->max_id = sdebug_num_tgts;
702 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300703 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900704 }
705 spin_unlock(&sdebug_host_list_lock);
706}
707
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500708enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
709
710/* Set in_bit to -1 to indicate no bit position of invalid field */
711static void
712mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d,
713 int in_byte, int in_bit)
714{
715 unsigned char *sbuff;
716 u8 sks[4];
717 int sl, asc;
718
719 sbuff = scp->sense_buffer;
720 if (!sbuff) {
721 sdev_printk(KERN_ERR, scp->device,
722 "%s: sense_buffer is NULL\n", __func__);
723 return;
724 }
725 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
726 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400727 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500728 memset(sks, 0, sizeof(sks));
729 sks[0] = 0x80;
730 if (c_d)
731 sks[0] |= 0x40;
732 if (in_bit >= 0) {
733 sks[0] |= 0x8;
734 sks[0] |= 0x7 & in_bit;
735 }
736 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400737 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500738 sl = sbuff[7] + 8;
739 sbuff[7] = sl;
740 sbuff[sl] = 0x2;
741 sbuff[sl + 1] = 0x6;
742 memcpy(sbuff + sl + 4, sks, 3);
743 } else
744 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400745 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500746 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
747 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
748 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
749}
750
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400751static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900752{
753 unsigned char *sbuff;
754
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400755 sbuff = scp->sense_buffer;
756 if (!sbuff) {
757 sdev_printk(KERN_ERR, scp->device,
758 "%s: sense_buffer is NULL\n", __func__);
759 return;
760 }
761 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900762
Douglas Gilbert773642d2016-04-25 12:16:28 -0400763 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900764
Douglas Gilbert773642d2016-04-25 12:16:28 -0400765 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400766 sdev_printk(KERN_INFO, scp->device,
767 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
768 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900769}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500771static void
772mk_sense_invalid_opcode(struct scsi_cmnd *scp)
773{
774 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
775}
776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
778{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400779 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400780 if (0x1261 == cmd)
781 sdev_printk(KERN_INFO, dev,
782 "%s: BLKFLSBUF [0x1261]\n", __func__);
783 else if (0x5331 == cmd)
784 sdev_printk(KERN_INFO, dev,
785 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
786 __func__);
787 else
788 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
789 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791 return -EINVAL;
792 /* return -ENOTTY; // correct return but upsets fdisk */
793}
794
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500795static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
796{
797 struct sdebug_host_info *sdhp;
798 struct sdebug_dev_info *dp;
799
800 spin_lock(&sdebug_host_list_lock);
801 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
802 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
803 if ((devip->sdbg_host == dp->sdbg_host) &&
804 (devip->target == dp->target))
805 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
806 }
807 }
808 spin_unlock(&sdebug_host_list_lock);
809}
810
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400811static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400812 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400814 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400815
816 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
817 if (k != SDEBUG_NUM_UAS) {
818 const char *cp = NULL;
819
820 switch (k) {
821 case SDEBUG_UA_POR:
822 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
823 UA_RESET_ASC, POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400824 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400825 cp = "power on reset";
826 break;
827 case SDEBUG_UA_BUS_RESET:
828 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
829 UA_RESET_ASC, BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400830 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400831 cp = "bus reset";
832 break;
833 case SDEBUG_UA_MODE_CHANGED:
834 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
835 UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400836 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400837 cp = "mode parameters changed";
838 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500839 case SDEBUG_UA_CAPACITY_CHANGED:
840 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
841 UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400842 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500843 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500844 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500845 case SDEBUG_UA_MICROCODE_CHANGED:
846 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
847 TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400848 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500849 cp = "microcode has been changed";
850 break;
851 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
852 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
853 TARGET_CHANGED_ASC,
854 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400855 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500856 cp = "microcode has been changed without reset";
857 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500858 case SDEBUG_UA_LUNS_CHANGED:
859 /*
860 * SPC-3 behavior is to report a UNIT ATTENTION with
861 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
862 * on the target, until a REPORT LUNS command is
863 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400864 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500865 * values as struct scsi_device->scsi_level.
866 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400867 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500868 clear_luns_changed_on_target(devip);
869 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
870 TARGET_CHANGED_ASC,
871 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400872 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500873 cp = "reported luns data has changed";
874 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400875 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400876 pr_warn("unexpected unit attention code=%d\n", k);
877 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400878 cp = "unknown";
879 break;
880 }
881 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400882 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400883 sdev_printk(KERN_INFO, SCpnt->device,
884 "%s reports: Unit attention: %s\n",
885 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return check_condition_result;
887 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400888 if ((UAS_TUR == uas_only) && devip->stopped) {
889 mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400890 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400891 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400892 sdev_printk(KERN_INFO, SCpnt->device,
893 "%s reports: Not ready: %s\n", my_name,
894 "initializing command required");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400895 return check_condition_result;
896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return 0;
898}
899
900/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900901static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 int arr_len)
903{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900904 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900905 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900907 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900909 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400910 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900911
912 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
913 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700914 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 return 0;
917}
918
919/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900920static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
921 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900923 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900925 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900927
928 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929}
930
931
932static const char * inq_vendor_id = "Linux ";
933static const char * inq_product_id = "scsi_debug ";
Douglas Gilbert773642d2016-04-25 12:16:28 -0400934static const char *inq_product_rev = "0186"; /* version less '.' */
935static const u64 naa5_comp_a = 0x5222222000000000ULL;
936static const u64 naa5_comp_b = 0x5333333000000000ULL;
937static const u64 naa5_comp_c = 0x5111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400939/* Device identification VPD page. Returns number of bytes placed in arr */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200940static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
941 int target_dev_id, int dev_id_num,
942 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400943 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400945 int num, port_a;
946 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400948 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 /* T10 vendor identifier field format (faked) */
950 arr[0] = 0x2; /* ASCII */
951 arr[1] = 0x1;
952 arr[2] = 0x0;
953 memcpy(&arr[4], inq_vendor_id, 8);
954 memcpy(&arr[12], inq_product_id, 16);
955 memcpy(&arr[28], dev_id_str, dev_id_str_len);
956 num = 8 + 16 + dev_id_str_len;
957 arr[3] = num;
958 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400959 if (dev_id_num >= 0) {
960 /* NAA-5, Logical unit identifier (binary) */
961 arr[num++] = 0x1; /* binary (not necessarily sas) */
962 arr[num++] = 0x3; /* PIV=0, lu, naa */
963 arr[num++] = 0x0;
964 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400965 put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
966 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400967 /* Target relative port number */
968 arr[num++] = 0x61; /* proto=sas, binary */
969 arr[num++] = 0x94; /* PIV=1, target port, rel port */
970 arr[num++] = 0x0; /* reserved */
971 arr[num++] = 0x4; /* length */
972 arr[num++] = 0x0; /* reserved */
973 arr[num++] = 0x0; /* reserved */
974 arr[num++] = 0x0;
975 arr[num++] = 0x1; /* relative port A */
976 }
977 /* NAA-5, Target port identifier */
978 arr[num++] = 0x61; /* proto=sas, binary */
979 arr[num++] = 0x93; /* piv=1, target port, naa */
980 arr[num++] = 0x0;
981 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400982 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
983 num += 8;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200984 /* NAA-5, Target port group identifier */
985 arr[num++] = 0x61; /* proto=sas, binary */
986 arr[num++] = 0x95; /* piv=1, target port group id */
987 arr[num++] = 0x0;
988 arr[num++] = 0x4;
989 arr[num++] = 0;
990 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400991 put_unaligned_be16(port_group_id, arr + num);
992 num += 2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400993 /* NAA-5, Target device identifier */
994 arr[num++] = 0x61; /* proto=sas, binary */
995 arr[num++] = 0xa3; /* piv=1, target device, naa */
996 arr[num++] = 0x0;
997 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400998 put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
999 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001000 /* SCSI name string: Target device identifier */
1001 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1002 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1003 arr[num++] = 0x0;
1004 arr[num++] = 24;
1005 memcpy(arr + num, "naa.52222220", 12);
1006 num += 12;
1007 snprintf(b, sizeof(b), "%08X", target_dev_id);
1008 memcpy(arr + num, b, 8);
1009 num += 8;
1010 memset(arr + num, 0, 4);
1011 num += 4;
1012 return num;
1013}
1014
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001015static unsigned char vpd84_data[] = {
1016/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1017 0x22,0x22,0x22,0x0,0xbb,0x1,
1018 0x22,0x22,0x22,0x0,0xbb,0x2,
1019};
1020
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001021/* Software interface identification VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001022static int inquiry_evpd_84(unsigned char * arr)
1023{
1024 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1025 return sizeof(vpd84_data);
1026}
1027
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001028/* Management network addresses VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001029static int inquiry_evpd_85(unsigned char * arr)
1030{
1031 int num = 0;
1032 const char * na1 = "https://www.kernel.org/config";
1033 const char * na2 = "http://www.kernel.org/log";
1034 int plen, olen;
1035
1036 arr[num++] = 0x1; /* lu, storage config */
1037 arr[num++] = 0x0; /* reserved */
1038 arr[num++] = 0x0;
1039 olen = strlen(na1);
1040 plen = olen + 1;
1041 if (plen % 4)
1042 plen = ((plen / 4) + 1) * 4;
1043 arr[num++] = plen; /* length, null termianted, padded */
1044 memcpy(arr + num, na1, olen);
1045 memset(arr + num + olen, 0, plen - olen);
1046 num += plen;
1047
1048 arr[num++] = 0x4; /* lu, logging */
1049 arr[num++] = 0x0; /* reserved */
1050 arr[num++] = 0x0;
1051 olen = strlen(na2);
1052 plen = olen + 1;
1053 if (plen % 4)
1054 plen = ((plen / 4) + 1) * 4;
1055 arr[num++] = plen; /* length, null terminated, padded */
1056 memcpy(arr + num, na2, olen);
1057 memset(arr + num + olen, 0, plen - olen);
1058 num += plen;
1059
1060 return num;
1061}
1062
1063/* SCSI ports VPD page */
1064static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1065{
1066 int num = 0;
1067 int port_a, port_b;
1068
1069 port_a = target_dev_id + 1;
1070 port_b = port_a + 1;
1071 arr[num++] = 0x0; /* reserved */
1072 arr[num++] = 0x0; /* reserved */
1073 arr[num++] = 0x0;
1074 arr[num++] = 0x1; /* relative port 1 (primary) */
1075 memset(arr + num, 0, 6);
1076 num += 6;
1077 arr[num++] = 0x0;
1078 arr[num++] = 12; /* length tp descriptor */
1079 /* naa-5 target port identifier (A) */
1080 arr[num++] = 0x61; /* proto=sas, binary */
1081 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1082 arr[num++] = 0x0; /* reserved */
1083 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001084 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1085 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001086 arr[num++] = 0x0; /* reserved */
1087 arr[num++] = 0x0; /* reserved */
1088 arr[num++] = 0x0;
1089 arr[num++] = 0x2; /* relative port 2 (secondary) */
1090 memset(arr + num, 0, 6);
1091 num += 6;
1092 arr[num++] = 0x0;
1093 arr[num++] = 12; /* length tp descriptor */
1094 /* naa-5 target port identifier (B) */
1095 arr[num++] = 0x61; /* proto=sas, binary */
1096 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1097 arr[num++] = 0x0; /* reserved */
1098 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001099 put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1100 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001101
1102 return num;
1103}
1104
1105
1106static unsigned char vpd89_data[] = {
1107/* from 4th byte */ 0,0,0,0,
1108'l','i','n','u','x',' ',' ',' ',
1109'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1110'1','2','3','4',
11110x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
11120xec,0,0,0,
11130x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
11140,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
11150x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
11160x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
11170x53,0x41,
11180x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11190x20,0x20,
11200x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11210x10,0x80,
11220,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
11230x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
11240x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
11250,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
11260x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
11270x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
11280,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
11290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11320x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
11330,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
11340xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
11350,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
11360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11370,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11380,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11420,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11450,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11470,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1148};
1149
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001150/* ATA Information VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001151static int inquiry_evpd_89(unsigned char * arr)
1152{
1153 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1154 return sizeof(vpd89_data);
1155}
1156
1157
1158static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001159 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1160 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1161 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1162 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001163};
1164
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001165/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001166static int inquiry_evpd_b0(unsigned char * arr)
1167{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001168 unsigned int gran;
1169
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001170 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001171
1172 /* Optimal transfer length granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001173 gran = 1 << sdebug_physblk_exp;
1174 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001175
1176 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001177 if (sdebug_store_sectors > 0x400)
1178 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001179
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001180 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001181 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001182
Douglas Gilbert773642d2016-04-25 12:16:28 -04001183 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001184 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001185 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001186
1187 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001188 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001189 }
1190
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001191 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001192 if (sdebug_unmap_alignment) {
1193 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001194 arr[28] |= 0x80; /* UGAVALID */
1195 }
1196
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001197 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001198 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001199
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001200 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001201 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001202
1203 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001204
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001205 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206}
1207
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001208/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001209static int inquiry_evpd_b1(unsigned char *arr)
1210{
1211 memset(arr, 0, 0x3c);
1212 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001213 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1214 arr[2] = 0;
1215 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001216
1217 return 0x3c;
1218}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001220/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001221static int inquiry_evpd_b2(unsigned char *arr)
1222{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001223 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001224 arr[0] = 0; /* threshold exponent */
1225
Douglas Gilbert773642d2016-04-25 12:16:28 -04001226 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001227 arr[1] = 1 << 7;
1228
Douglas Gilbert773642d2016-04-25 12:16:28 -04001229 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001230 arr[1] |= 1 << 6;
1231
Douglas Gilbert773642d2016-04-25 12:16:28 -04001232 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001233 arr[1] |= 1 << 5;
1234
Douglas Gilbert773642d2016-04-25 12:16:28 -04001235 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001236 arr[1] |= 1 << 2;
1237
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001238 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001239}
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001242#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001244static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245{
1246 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001247 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001248 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001249 int alloc_len, n, ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001250 bool have_wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Douglas Gilbert773642d2016-04-25 12:16:28 -04001252 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001253 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1254 if (! arr)
1255 return DID_REQUEUE << 16;
Tomas Winkler34d55432015-07-28 16:54:21 +03001256 have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001257 if (have_wlun)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001258 pq_pdt = 0x1e; /* present, wlun */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001259 else if (sdebug_no_lun_0 && (0 == devip->lun))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001260 pq_pdt = 0x7f; /* not present, no device type */
1261 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001262 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 arr[0] = pq_pdt;
1264 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001265 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001266 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 return check_condition_result;
1268 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001269 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001270 char lu_id_str[6];
1271 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001273 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1274 (devip->channel & 0x7f);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001275 if (0 == sdebug_vpd_use_hostno)
Douglas Gilbert23183912006-09-16 20:30:47 -04001276 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001277 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001278 (devip->target * 1000) + devip->lun);
1279 target_dev_id = ((host_no + 1) * 2000) +
1280 (devip->target * 1000) - 3;
1281 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001283 arr[1] = cmd[2]; /*sanity */
1284 n = 4;
1285 arr[n++] = 0x0; /* this page */
1286 arr[n++] = 0x80; /* unit serial number */
1287 arr[n++] = 0x83; /* device identification */
1288 arr[n++] = 0x84; /* software interface ident. */
1289 arr[n++] = 0x85; /* management network addresses */
1290 arr[n++] = 0x86; /* extended inquiry */
1291 arr[n++] = 0x87; /* mode page policy */
1292 arr[n++] = 0x88; /* SCSI ports */
1293 arr[n++] = 0x89; /* ATA information */
1294 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001295 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001296 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
1297 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001298 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001300 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001302 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001304 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001305 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1306 target_dev_id, lu_id_num,
1307 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001308 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1309 arr[1] = cmd[2]; /*sanity */
1310 arr[3] = inquiry_evpd_84(&arr[4]);
1311 } else if (0x85 == cmd[2]) { /* Management network addresses */
1312 arr[1] = cmd[2]; /*sanity */
1313 arr[3] = inquiry_evpd_85(&arr[4]);
1314 } else if (0x86 == cmd[2]) { /* extended inquiry */
1315 arr[1] = cmd[2]; /*sanity */
1316 arr[3] = 0x3c; /* number of following entries */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001317 if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001318 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001319 else if (sdebug_dif)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001320 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1321 else
1322 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001323 arr[5] = 0x7; /* head of q, ordered + simple q's */
1324 } else if (0x87 == cmd[2]) { /* mode page policy */
1325 arr[1] = cmd[2]; /*sanity */
1326 arr[3] = 0x8; /* number of following entries */
1327 arr[4] = 0x2; /* disconnect-reconnect mp */
1328 arr[6] = 0x80; /* mlus, shared */
1329 arr[8] = 0x18; /* protocol specific lu */
1330 arr[10] = 0x82; /* mlus, per initiator port */
1331 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1332 arr[1] = cmd[2]; /*sanity */
1333 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1334 } else if (0x89 == cmd[2]) { /* ATA information */
1335 arr[1] = cmd[2]; /*sanity */
1336 n = inquiry_evpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001337 put_unaligned_be16(n, arr + 2);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001338 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1339 arr[1] = cmd[2]; /*sanity */
1340 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001341 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1342 arr[1] = cmd[2]; /*sanity */
1343 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001344 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001345 arr[1] = cmd[2]; /*sanity */
1346 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001348 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001349 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 return check_condition_result;
1351 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001352 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001353 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001354 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001355 kfree(arr);
1356 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 }
1358 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001359 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1360 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 arr[3] = 2; /* response_data_format==2 */
1362 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001363 arr[5] = sdebug_dif ? 1 : 0; /* PROTECT bit */
1364 if (0 == sdebug_vpd_use_hostno)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001365 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001366 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001368 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 memcpy(&arr[8], inq_vendor_id, 8);
1370 memcpy(&arr[16], inq_product_id, 16);
1371 memcpy(&arr[32], inq_product_rev, 4);
1372 /* version descriptors (2 bytes each) follow */
Douglas Gilberte46b0342014-08-05 12:21:53 +02001373 arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */
1374 arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001375 n = 62;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001376 if (sdebug_ptype == 0) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001377 arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001378 } else if (sdebug_ptype == 1) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001379 arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
Douglas Gilberte46b0342014-08-05 12:21:53 +02001381 arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001382 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001384 kfree(arr);
1385 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386}
1387
1388static int resp_requests(struct scsi_cmnd * scp,
1389 struct sdebug_dev_info * devip)
1390{
1391 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001392 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001393 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001394 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 int len = 18;
1396
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001397 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001398 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001399 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001400 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001401 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001402 arr[0] = 0x72;
1403 arr[1] = 0x0; /* NO_SENSE in sense_key */
1404 arr[2] = THRESHOLD_EXCEEDED;
1405 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001406 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001407 } else {
1408 arr[0] = 0x70;
1409 arr[2] = 0x0; /* NO_SENSE in sense_key */
1410 arr[7] = 0xa; /* 18 byte sense buffer */
1411 arr[12] = THRESHOLD_EXCEEDED;
1412 arr[13] = 0xff; /* TEST set and MRIE==6 */
1413 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001414 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001415 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001416 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001417 ; /* have sense and formats match */
1418 else if (arr[0] <= 0x70) {
1419 if (dsense) {
1420 memset(arr, 0, 8);
1421 arr[0] = 0x72;
1422 len = 8;
1423 } else {
1424 memset(arr, 0, 18);
1425 arr[0] = 0x70;
1426 arr[7] = 0xa;
1427 }
1428 } else if (dsense) {
1429 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001430 arr[0] = 0x72;
1431 arr[1] = sbuff[2]; /* sense key */
1432 arr[2] = sbuff[12]; /* asc */
1433 arr[3] = sbuff[13]; /* ascq */
1434 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001435 } else {
1436 memset(arr, 0, 18);
1437 arr[0] = 0x70;
1438 arr[2] = sbuff[1];
1439 arr[7] = 0xa;
1440 arr[12] = sbuff[1];
1441 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001442 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001443
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001444 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001445 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 return fill_from_dev_buffer(scp, arr, len);
1447}
1448
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001449static int resp_start_stop(struct scsi_cmnd * scp,
1450 struct sdebug_dev_info * devip)
1451{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001452 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001453 int power_cond, start;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001454
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001455 power_cond = (cmd[4] & 0xf0) >> 4;
1456 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001457 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001458 return check_condition_result;
1459 }
1460 start = cmd[4] & 1;
1461 if (start == devip->stopped)
1462 devip->stopped = !start;
1463 return 0;
1464}
1465
FUJITA Tomonori28898872008-03-30 00:59:55 +09001466static sector_t get_sdebug_capacity(void)
1467{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001468 static const unsigned int gibibyte = 1073741824;
1469
1470 if (sdebug_virtual_gb > 0)
1471 return (sector_t)sdebug_virtual_gb *
1472 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001473 else
1474 return sdebug_store_sectors;
1475}
1476
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477#define SDEBUG_READCAP_ARR_SZ 8
1478static int resp_readcap(struct scsi_cmnd * scp,
1479 struct sdebug_dev_info * devip)
1480{
1481 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001482 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001485 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001487 if (sdebug_capacity < 0xffffffff) {
1488 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001489 put_unaligned_be32(capac, arr + 0);
1490 } else
1491 put_unaligned_be32(0xffffffff, arr + 0);
1492 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1494}
1495
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496#define SDEBUG_READCAP16_ARR_SZ 32
1497static int resp_readcap16(struct scsi_cmnd * scp,
1498 struct sdebug_dev_info * devip)
1499{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001500 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001501 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001502 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001503
Douglas Gilbert773642d2016-04-25 12:16:28 -04001504 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001505 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001506 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001507 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001508 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1509 put_unaligned_be32(sdebug_sector_size, arr + 8);
1510 arr[13] = sdebug_physblk_exp & 0xf;
1511 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001512
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001513 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001514 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001515 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001516 arr[14] |= 0x40; /* LBPRZ */
1517 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001518
Douglas Gilbert773642d2016-04-25 12:16:28 -04001519 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001520
Douglas Gilbert773642d2016-04-25 12:16:28 -04001521 if (sdebug_dif) {
1522 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001523 arr[12] |= 1; /* PROT_EN */
1524 }
1525
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001526 return fill_from_dev_buffer(scp, arr,
1527 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1528}
1529
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001530#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1531
1532static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1533 struct sdebug_dev_info * devip)
1534{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001535 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001536 unsigned char * arr;
1537 int host_no = devip->sdbg_host->shost->host_no;
1538 int n, ret, alen, rlen;
1539 int port_group_a, port_group_b, port_a, port_b;
1540
Douglas Gilbert773642d2016-04-25 12:16:28 -04001541 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001542 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1543 if (! arr)
1544 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001545 /*
1546 * EVPD page 0x88 states we have two ports, one
1547 * real and a fake port with no device connected.
1548 * So we create two port groups with one port each
1549 * and set the group with port B to unavailable.
1550 */
1551 port_a = 0x1; /* relative port A */
1552 port_b = 0x2; /* relative port B */
1553 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001554 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001555 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001556 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001557
1558 /*
1559 * The asymmetric access state is cycled according to the host_id.
1560 */
1561 n = 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001562 if (0 == sdebug_vpd_use_hostno) {
1563 arr[n++] = host_no % 3; /* Asymm access state */
1564 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001565 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001566 arr[n++] = 0x0; /* Active/Optimized path */
1567 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001568 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001569 put_unaligned_be16(port_group_a, arr + n);
1570 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001571 arr[n++] = 0; /* Reserved */
1572 arr[n++] = 0; /* Status code */
1573 arr[n++] = 0; /* Vendor unique */
1574 arr[n++] = 0x1; /* One port per group */
1575 arr[n++] = 0; /* Reserved */
1576 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001577 put_unaligned_be16(port_a, arr + n);
1578 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001579 arr[n++] = 3; /* Port unavailable */
1580 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001581 put_unaligned_be16(port_group_b, arr + n);
1582 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001583 arr[n++] = 0; /* Reserved */
1584 arr[n++] = 0; /* Status code */
1585 arr[n++] = 0; /* Vendor unique */
1586 arr[n++] = 0x1; /* One port per group */
1587 arr[n++] = 0; /* Reserved */
1588 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001589 put_unaligned_be16(port_b, arr + n);
1590 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001591
1592 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001593 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001594
1595 /*
1596 * Return the smallest value of either
1597 * - The allocated length
1598 * - The constructed command length
1599 * - The maximum array size
1600 */
1601 rlen = min(alen,n);
1602 ret = fill_from_dev_buffer(scp, arr,
1603 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1604 kfree(arr);
1605 return ret;
1606}
1607
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001608static int
1609resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1610{
1611 bool rctd;
1612 u8 reporting_opts, req_opcode, sdeb_i, supp;
1613 u16 req_sa, u;
1614 u32 alloc_len, a_len;
1615 int k, offset, len, errsts, count, bump, na;
1616 const struct opcode_info_t *oip;
1617 const struct opcode_info_t *r_oip;
1618 u8 *arr;
1619 u8 *cmd = scp->cmnd;
1620
1621 rctd = !!(cmd[2] & 0x80);
1622 reporting_opts = cmd[2] & 0x7;
1623 req_opcode = cmd[3];
1624 req_sa = get_unaligned_be16(cmd + 4);
1625 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001626 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001627 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1628 return check_condition_result;
1629 }
1630 if (alloc_len > 8192)
1631 a_len = 8192;
1632 else
1633 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001634 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001635 if (NULL == arr) {
1636 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1637 INSUFF_RES_ASCQ);
1638 return check_condition_result;
1639 }
1640 switch (reporting_opts) {
1641 case 0: /* all commands */
1642 /* count number of commands */
1643 for (count = 0, oip = opcode_info_arr;
1644 oip->num_attached != 0xff; ++oip) {
1645 if (F_INV_OP & oip->flags)
1646 continue;
1647 count += (oip->num_attached + 1);
1648 }
1649 bump = rctd ? 20 : 8;
1650 put_unaligned_be32(count * bump, arr);
1651 for (offset = 4, oip = opcode_info_arr;
1652 oip->num_attached != 0xff && offset < a_len; ++oip) {
1653 if (F_INV_OP & oip->flags)
1654 continue;
1655 na = oip->num_attached;
1656 arr[offset] = oip->opcode;
1657 put_unaligned_be16(oip->sa, arr + offset + 2);
1658 if (rctd)
1659 arr[offset + 5] |= 0x2;
1660 if (FF_SA & oip->flags)
1661 arr[offset + 5] |= 0x1;
1662 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1663 if (rctd)
1664 put_unaligned_be16(0xa, arr + offset + 8);
1665 r_oip = oip;
1666 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1667 if (F_INV_OP & oip->flags)
1668 continue;
1669 offset += bump;
1670 arr[offset] = oip->opcode;
1671 put_unaligned_be16(oip->sa, arr + offset + 2);
1672 if (rctd)
1673 arr[offset + 5] |= 0x2;
1674 if (FF_SA & oip->flags)
1675 arr[offset + 5] |= 0x1;
1676 put_unaligned_be16(oip->len_mask[0],
1677 arr + offset + 6);
1678 if (rctd)
1679 put_unaligned_be16(0xa,
1680 arr + offset + 8);
1681 }
1682 oip = r_oip;
1683 offset += bump;
1684 }
1685 break;
1686 case 1: /* one command: opcode only */
1687 case 2: /* one command: opcode plus service action */
1688 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1689 sdeb_i = opcode_ind_arr[req_opcode];
1690 oip = &opcode_info_arr[sdeb_i];
1691 if (F_INV_OP & oip->flags) {
1692 supp = 1;
1693 offset = 4;
1694 } else {
1695 if (1 == reporting_opts) {
1696 if (FF_SA & oip->flags) {
1697 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1698 2, 2);
1699 kfree(arr);
1700 return check_condition_result;
1701 }
1702 req_sa = 0;
1703 } else if (2 == reporting_opts &&
1704 0 == (FF_SA & oip->flags)) {
1705 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1706 kfree(arr); /* point at requested sa */
1707 return check_condition_result;
1708 }
1709 if (0 == (FF_SA & oip->flags) &&
1710 req_opcode == oip->opcode)
1711 supp = 3;
1712 else if (0 == (FF_SA & oip->flags)) {
1713 na = oip->num_attached;
1714 for (k = 0, oip = oip->arrp; k < na;
1715 ++k, ++oip) {
1716 if (req_opcode == oip->opcode)
1717 break;
1718 }
1719 supp = (k >= na) ? 1 : 3;
1720 } else if (req_sa != oip->sa) {
1721 na = oip->num_attached;
1722 for (k = 0, oip = oip->arrp; k < na;
1723 ++k, ++oip) {
1724 if (req_sa == oip->sa)
1725 break;
1726 }
1727 supp = (k >= na) ? 1 : 3;
1728 } else
1729 supp = 3;
1730 if (3 == supp) {
1731 u = oip->len_mask[0];
1732 put_unaligned_be16(u, arr + 2);
1733 arr[4] = oip->opcode;
1734 for (k = 1; k < u; ++k)
1735 arr[4 + k] = (k < 16) ?
1736 oip->len_mask[k] : 0xff;
1737 offset = 4 + u;
1738 } else
1739 offset = 4;
1740 }
1741 arr[1] = (rctd ? 0x80 : 0) | supp;
1742 if (rctd) {
1743 put_unaligned_be16(0xa, arr + offset);
1744 offset += 12;
1745 }
1746 break;
1747 default:
1748 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1749 kfree(arr);
1750 return check_condition_result;
1751 }
1752 offset = (offset < a_len) ? offset : a_len;
1753 len = (offset < alloc_len) ? offset : alloc_len;
1754 errsts = fill_from_dev_buffer(scp, arr, len);
1755 kfree(arr);
1756 return errsts;
1757}
1758
1759static int
1760resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1761{
1762 bool repd;
1763 u32 alloc_len, len;
1764 u8 arr[16];
1765 u8 *cmd = scp->cmnd;
1766
1767 memset(arr, 0, sizeof(arr));
1768 repd = !!(cmd[2] & 0x80);
1769 alloc_len = get_unaligned_be32(cmd + 6);
1770 if (alloc_len < 4) {
1771 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1772 return check_condition_result;
1773 }
1774 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1775 arr[1] = 0x1; /* ITNRS */
1776 if (repd) {
1777 arr[3] = 0xc;
1778 len = 16;
1779 } else
1780 len = 4;
1781
1782 len = (len < alloc_len) ? len : alloc_len;
1783 return fill_from_dev_buffer(scp, arr, len);
1784}
1785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786/* <<Following mode page info copied from ST318451LW>> */
1787
1788static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1789{ /* Read-Write Error Recovery page for mode_sense */
1790 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1791 5, 0, 0xff, 0xff};
1792
1793 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1794 if (1 == pcontrol)
1795 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1796 return sizeof(err_recov_pg);
1797}
1798
1799static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1800{ /* Disconnect-Reconnect page for mode_sense */
1801 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1802 0, 0, 0, 0, 0, 0, 0, 0};
1803
1804 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1805 if (1 == pcontrol)
1806 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1807 return sizeof(disconnect_pg);
1808}
1809
1810static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1811{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001812 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1813 0, 0, 0, 0, 0, 0, 0, 0,
1814 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
Martin K. Petersen597136a2008-06-05 00:12:59 -04001816 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001817 put_unaligned_be16(sdebug_sectors_per, p + 10);
1818 put_unaligned_be16(sdebug_sector_size, p + 12);
1819 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001820 p[20] |= 0x20; /* should agree with INQUIRY */
1821 if (1 == pcontrol)
1822 memset(p + 2, 0, sizeof(format_pg) - 2);
1823 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824}
1825
1826static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1827{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001828 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1829 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1830 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1832
Douglas Gilbert773642d2016-04-25 12:16:28 -04001833 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001834 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 memcpy(p, caching_pg, sizeof(caching_pg));
1836 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001837 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1838 else if (2 == pcontrol)
1839 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 return sizeof(caching_pg);
1841}
1842
1843static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1844{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001845 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1846 0, 0, 0, 0};
1847 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 0, 0, 0x2, 0x4b};
1849
Douglas Gilbert773642d2016-04-25 12:16:28 -04001850 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001852 else
1853 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001854
Douglas Gilbert773642d2016-04-25 12:16:28 -04001855 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001856 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1859 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001860 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1861 else if (2 == pcontrol)
1862 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 return sizeof(ctrl_m_pg);
1864}
1865
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001866
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1868{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001869 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1870 0, 0, 0x0, 0x0};
1871 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1872 0, 0, 0x0, 0x0};
1873
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1875 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001876 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1877 else if (2 == pcontrol)
1878 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 return sizeof(iec_m_pg);
1880}
1881
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001882static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1883{ /* SAS SSP mode page - short format for mode_sense */
1884 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1885 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1886
1887 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1888 if (1 == pcontrol)
1889 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1890 return sizeof(sas_sf_m_pg);
1891}
1892
1893
1894static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1895 int target_dev_id)
1896{ /* SAS phy control and discover mode page for mode_sense */
1897 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1898 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001899 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1900 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001901 0x2, 0, 0, 0, 0, 0, 0, 0,
1902 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1903 0, 0, 0, 0, 0, 0, 0, 0,
1904 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001905 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1906 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001907 0x3, 0, 0, 0, 0, 0, 0, 0,
1908 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1909 0, 0, 0, 0, 0, 0, 0, 0,
1910 };
1911 int port_a, port_b;
1912
Douglas Gilbert773642d2016-04-25 12:16:28 -04001913 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1914 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1915 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1916 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001917 port_a = target_dev_id + 1;
1918 port_b = port_a + 1;
1919 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001920 put_unaligned_be32(port_a, p + 20);
1921 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001922 if (1 == pcontrol)
1923 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1924 return sizeof(sas_pcd_m_pg);
1925}
1926
1927static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1928{ /* SAS SSP shared protocol specific port mode subpage */
1929 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1930 0, 0, 0, 0, 0, 0, 0, 0,
1931 };
1932
1933 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1934 if (1 == pcontrol)
1935 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1936 return sizeof(sas_sha_m_pg);
1937}
1938
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939#define SDEBUG_MAX_MSENSE_SZ 256
1940
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001941static int
1942resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
Douglas Gilbert23183912006-09-16 20:30:47 -04001944 unsigned char dbd, llbaa;
1945 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 unsigned char dev_spec;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001947 int alloc_len, msense_6, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001948 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 unsigned char * ap;
1950 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001951 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Douglas Gilbert23183912006-09-16 20:30:47 -04001953 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 pcontrol = (cmd[2] & 0xc0) >> 6;
1955 pcode = cmd[2] & 0x3f;
1956 subpcode = cmd[3];
1957 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001958 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001959 if ((0 == sdebug_ptype) && (0 == dbd))
Douglas Gilbert23183912006-09-16 20:30:47 -04001960 bd_len = llbaa ? 16 : 8;
1961 else
1962 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001963 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1965 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001966 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 return check_condition_result;
1968 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001969 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1970 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001971 /* set DPOFUA bit for disks */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001972 if (0 == sdebug_ptype)
Douglas Gilbert23183912006-09-16 20:30:47 -04001973 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1974 else
1975 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 if (msense_6) {
1977 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001978 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 offset = 4;
1980 } else {
1981 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001982 if (16 == bd_len)
1983 arr[4] = 0x1; /* set LONGLBA bit */
1984 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 offset = 8;
1986 }
1987 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001988 if ((bd_len > 0) && (!sdebug_capacity))
1989 sdebug_capacity = get_sdebug_capacity();
1990
Douglas Gilbert23183912006-09-16 20:30:47 -04001991 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001992 if (sdebug_capacity > 0xfffffffe)
1993 put_unaligned_be32(0xffffffff, ap + 0);
1994 else
1995 put_unaligned_be32(sdebug_capacity, ap + 0);
1996 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04001997 offset += bd_len;
1998 ap = arr + offset;
1999 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002000 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2001 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002002 offset += bd_len;
2003 ap = arr + offset;
2004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002006 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2007 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002008 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 return check_condition_result;
2010 }
2011 switch (pcode) {
2012 case 0x1: /* Read-Write error recovery page, direct access */
2013 len = resp_err_recov_pg(ap, pcontrol, target);
2014 offset += len;
2015 break;
2016 case 0x2: /* Disconnect-Reconnect page, all devices */
2017 len = resp_disconnect_pg(ap, pcontrol, target);
2018 offset += len;
2019 break;
2020 case 0x3: /* Format device page, direct access */
2021 len = resp_format_pg(ap, pcontrol, target);
2022 offset += len;
2023 break;
2024 case 0x8: /* Caching page, direct access */
2025 len = resp_caching_pg(ap, pcontrol, target);
2026 offset += len;
2027 break;
2028 case 0xa: /* Control Mode page, all devices */
2029 len = resp_ctrl_m_pg(ap, pcontrol, target);
2030 offset += len;
2031 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002032 case 0x19: /* if spc==1 then sas phy, control+discover */
2033 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002034 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002035 return check_condition_result;
2036 }
2037 len = 0;
2038 if ((0x0 == subpcode) || (0xff == subpcode))
2039 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2040 if ((0x1 == subpcode) || (0xff == subpcode))
2041 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2042 target_dev_id);
2043 if ((0x2 == subpcode) || (0xff == subpcode))
2044 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2045 offset += len;
2046 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 case 0x1c: /* Informational Exceptions Mode page, all devices */
2048 len = resp_iec_m_pg(ap, pcontrol, target);
2049 offset += len;
2050 break;
2051 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002052 if ((0 == subpcode) || (0xff == subpcode)) {
2053 len = resp_err_recov_pg(ap, pcontrol, target);
2054 len += resp_disconnect_pg(ap + len, pcontrol, target);
2055 len += resp_format_pg(ap + len, pcontrol, target);
2056 len += resp_caching_pg(ap + len, pcontrol, target);
2057 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2058 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2059 if (0xff == subpcode) {
2060 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2061 target, target_dev_id);
2062 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2063 }
2064 len += resp_iec_m_pg(ap + len, pcontrol, target);
2065 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002066 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002067 return check_condition_result;
2068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 offset += len;
2070 break;
2071 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002072 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 return check_condition_result;
2074 }
2075 if (msense_6)
2076 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002077 else
2078 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2080}
2081
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002082#define SDEBUG_MAX_MSELECT_SZ 512
2083
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002084static int
2085resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002086{
2087 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002088 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002089 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002090 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002091 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002092
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002093 memset(arr, 0, sizeof(arr));
2094 pf = cmd[1] & 0x10;
2095 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002096 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002097 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002098 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002099 return check_condition_result;
2100 }
2101 res = fetch_to_dev_buffer(scp, arr, param_len);
2102 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002103 return DID_ERROR << 16;
2104 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002105 sdev_printk(KERN_INFO, scp->device,
2106 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2107 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002108 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2109 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002110 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002111 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002112 return check_condition_result;
2113 }
2114 off = bd_len + (mselect6 ? 4 : 8);
2115 mpage = arr[off] & 0x3f;
2116 ps = !!(arr[off] & 0x80);
2117 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002118 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002119 return check_condition_result;
2120 }
2121 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002122 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002123 (arr[off + 1] + 2);
2124 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002125 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002126 PARAMETER_LIST_LENGTH_ERR, 0);
2127 return check_condition_result;
2128 }
2129 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002130 case 0x8: /* Caching Mode page */
2131 if (caching_pg[1] == arr[off + 1]) {
2132 memcpy(caching_pg + 2, arr + off + 2,
2133 sizeof(caching_pg) - 2);
2134 goto set_mode_changed_ua;
2135 }
2136 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002137 case 0xa: /* Control Mode page */
2138 if (ctrl_m_pg[1] == arr[off + 1]) {
2139 memcpy(ctrl_m_pg + 2, arr + off + 2,
2140 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002141 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002142 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002143 }
2144 break;
2145 case 0x1c: /* Informational Exceptions Mode page */
2146 if (iec_m_pg[1] == arr[off + 1]) {
2147 memcpy(iec_m_pg + 2, arr + off + 2,
2148 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002149 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002150 }
2151 break;
2152 default:
2153 break;
2154 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002155 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002156 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002157set_mode_changed_ua:
2158 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2159 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002160}
2161
2162static int resp_temp_l_pg(unsigned char * arr)
2163{
2164 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2165 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2166 };
2167
2168 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2169 return sizeof(temp_l_pg);
2170}
2171
2172static int resp_ie_l_pg(unsigned char * arr)
2173{
2174 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2175 };
2176
2177 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2178 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2179 arr[4] = THRESHOLD_EXCEEDED;
2180 arr[5] = 0xff;
2181 }
2182 return sizeof(ie_l_pg);
2183}
2184
2185#define SDEBUG_MAX_LSENSE_SZ 512
2186
2187static int resp_log_sense(struct scsi_cmnd * scp,
2188 struct sdebug_dev_info * devip)
2189{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002190 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002191 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002192 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002193
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002194 memset(arr, 0, sizeof(arr));
2195 ppc = cmd[1] & 0x2;
2196 sp = cmd[1] & 0x1;
2197 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002198 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002199 return check_condition_result;
2200 }
2201 pcontrol = (cmd[2] & 0xc0) >> 6;
2202 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002203 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002204 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002205 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002206 if (0 == subpcode) {
2207 switch (pcode) {
2208 case 0x0: /* Supported log pages log page */
2209 n = 4;
2210 arr[n++] = 0x0; /* this page */
2211 arr[n++] = 0xd; /* Temperature */
2212 arr[n++] = 0x2f; /* Informational exceptions */
2213 arr[3] = n - 4;
2214 break;
2215 case 0xd: /* Temperature log page */
2216 arr[3] = resp_temp_l_pg(arr + 4);
2217 break;
2218 case 0x2f: /* Informational exceptions log page */
2219 arr[3] = resp_ie_l_pg(arr + 4);
2220 break;
2221 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002222 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002223 return check_condition_result;
2224 }
2225 } else if (0xff == subpcode) {
2226 arr[0] |= 0x40;
2227 arr[1] = subpcode;
2228 switch (pcode) {
2229 case 0x0: /* Supported log pages and subpages log page */
2230 n = 4;
2231 arr[n++] = 0x0;
2232 arr[n++] = 0x0; /* 0,0 page */
2233 arr[n++] = 0x0;
2234 arr[n++] = 0xff; /* this page */
2235 arr[n++] = 0xd;
2236 arr[n++] = 0x0; /* Temperature */
2237 arr[n++] = 0x2f;
2238 arr[n++] = 0x0; /* Informational exceptions */
2239 arr[3] = n - 4;
2240 break;
2241 case 0xd: /* Temperature subpages */
2242 n = 4;
2243 arr[n++] = 0xd;
2244 arr[n++] = 0x0; /* Temperature */
2245 arr[3] = n - 4;
2246 break;
2247 case 0x2f: /* Informational exceptions subpages */
2248 n = 4;
2249 arr[n++] = 0x2f;
2250 arr[n++] = 0x0; /* Informational exceptions */
2251 arr[3] = n - 4;
2252 break;
2253 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002254 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002255 return check_condition_result;
2256 }
2257 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002258 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002259 return check_condition_result;
2260 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002261 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002262 return fill_from_dev_buffer(scp, arr,
2263 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2264}
2265
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002266static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002267 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002269 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002270 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 return check_condition_result;
2272 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002273 /* transfer length excessive (tie in to block limits VPD page) */
2274 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002275 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002276 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002277 return check_condition_result;
2278 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002279 return 0;
2280}
2281
Akinobu Mitaa4517512013-07-08 16:01:57 -07002282/* Returns number of bytes copied or -1 if error. */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002283static int
2284do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002285{
2286 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002287 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002288 struct scsi_data_buffer *sdb;
2289 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002290
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002291 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002292 sdb = scsi_out(scmd);
2293 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002294 } else {
2295 sdb = scsi_in(scmd);
2296 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002297 }
2298
2299 if (!sdb->length)
2300 return 0;
2301 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2302 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002303
2304 block = do_div(lba, sdebug_store_sectors);
2305 if (block + num > sdebug_store_sectors)
2306 rest = block + num - sdebug_store_sectors;
2307
Dave Gordon386ecb12015-06-30 14:58:57 -07002308 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002309 fake_storep + (block * sdebug_sector_size),
2310 (num - rest) * sdebug_sector_size, 0, do_write);
2311 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002312 return ret;
2313
2314 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002315 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002316 fake_storep, rest * sdebug_sector_size,
2317 (num - rest) * sdebug_sector_size, do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002318 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002319
2320 return ret;
2321}
2322
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002323/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2324 * arr into fake_store(lba,num) and return true. If comparison fails then
2325 * return false. */
2326static bool
2327comp_write_worker(u64 lba, u32 num, const u8 *arr)
2328{
2329 bool res;
2330 u64 block, rest = 0;
2331 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002332 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002333
2334 block = do_div(lba, store_blks);
2335 if (block + num > store_blks)
2336 rest = block + num - store_blks;
2337
2338 res = !memcmp(fake_storep + (block * lb_size), arr,
2339 (num - rest) * lb_size);
2340 if (!res)
2341 return res;
2342 if (rest)
2343 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2344 rest * lb_size);
2345 if (!res)
2346 return res;
2347 arr += num * lb_size;
2348 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2349 if (rest)
2350 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2351 rest * lb_size);
2352 return res;
2353}
2354
Akinobu Mita51d648a2013-09-18 21:27:28 +09002355static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002356{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002357 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002358
Douglas Gilbert773642d2016-04-25 12:16:28 -04002359 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002360 csum = (__force __be16)ip_compute_csum(buf, len);
2361 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002362 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002363
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002364 return csum;
2365}
2366
2367static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2368 sector_t sector, u32 ei_lba)
2369{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002370 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002371
2372 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002373 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002374 (unsigned long)sector,
2375 be16_to_cpu(sdt->guard_tag),
2376 be16_to_cpu(csum));
2377 return 0x01;
2378 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002379 if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002380 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002381 pr_err("REF check failed on sector %lu\n",
2382 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002383 return 0x03;
2384 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002385 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002386 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002387 pr_err("REF check failed on sector %lu\n",
2388 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002389 return 0x03;
2390 }
2391 return 0;
2392}
2393
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002394static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002395 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002396{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002397 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002398 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002399 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002400 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002401
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002402 /* Bytes of protection data to copy into sgl */
2403 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002404
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002405 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2406 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2407 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2408
2409 while (sg_miter_next(&miter) && resid > 0) {
2410 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002411 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002412 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002413
2414 if (dif_store_end < start + len)
2415 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002416
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002417 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002418
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002419 if (read)
2420 memcpy(paddr, start, len - rest);
2421 else
2422 memcpy(start, paddr, len - rest);
2423
2424 if (rest) {
2425 if (read)
2426 memcpy(paddr + len - rest, dif_storep, rest);
2427 else
2428 memcpy(dif_storep, paddr + len - rest, rest);
2429 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002430
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002431 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002432 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002433 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002434 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002435}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002436
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002437static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2438 unsigned int sectors, u32 ei_lba)
2439{
2440 unsigned int i;
2441 struct sd_dif_tuple *sdt;
2442 sector_t sector;
2443
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002444 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002445 int ret;
2446
2447 sector = start_sec + i;
2448 sdt = dif_store(sector);
2449
Akinobu Mita51d648a2013-09-18 21:27:28 +09002450 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002451 continue;
2452
2453 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2454 if (ret) {
2455 dif_errors++;
2456 return ret;
2457 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002458 }
2459
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002460 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002461 dix_reads++;
2462
2463 return 0;
2464}
2465
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002466static int
2467resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002468{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002469 u8 *cmd = scp->cmnd;
2470 u64 lba;
2471 u32 num;
2472 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002473 unsigned long iflags;
2474 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002475 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002476
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002477 switch (cmd[0]) {
2478 case READ_16:
2479 ei_lba = 0;
2480 lba = get_unaligned_be64(cmd + 2);
2481 num = get_unaligned_be32(cmd + 10);
2482 check_prot = true;
2483 break;
2484 case READ_10:
2485 ei_lba = 0;
2486 lba = get_unaligned_be32(cmd + 2);
2487 num = get_unaligned_be16(cmd + 7);
2488 check_prot = true;
2489 break;
2490 case READ_6:
2491 ei_lba = 0;
2492 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2493 (u32)(cmd[1] & 0x1f) << 16;
2494 num = (0 == cmd[4]) ? 256 : cmd[4];
2495 check_prot = true;
2496 break;
2497 case READ_12:
2498 ei_lba = 0;
2499 lba = get_unaligned_be32(cmd + 2);
2500 num = get_unaligned_be32(cmd + 6);
2501 check_prot = true;
2502 break;
2503 case XDWRITEREAD_10:
2504 ei_lba = 0;
2505 lba = get_unaligned_be32(cmd + 2);
2506 num = get_unaligned_be16(cmd + 7);
2507 check_prot = false;
2508 break;
2509 default: /* assume READ(32) */
2510 lba = get_unaligned_be64(cmd + 12);
2511 ei_lba = get_unaligned_be32(cmd + 20);
2512 num = get_unaligned_be32(cmd + 28);
2513 check_prot = false;
2514 break;
2515 }
2516 if (check_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002517 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002518 (cmd[1] & 0xe0)) {
2519 mk_sense_invalid_opcode(scp);
2520 return check_condition_result;
2521 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002522 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2523 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002524 (cmd[1] & 0xe0) == 0)
2525 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2526 "to DIF device\n");
2527 }
2528 if (sdebug_any_injecting_opt) {
2529 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2530
2531 if (ep->inj_short)
2532 num /= 2;
2533 }
2534
2535 /* inline check_device_access_params() */
2536 if (lba + num > sdebug_capacity) {
2537 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2538 return check_condition_result;
2539 }
2540 /* transfer length excessive (tie in to block limits VPD page) */
2541 if (num > sdebug_store_sectors) {
2542 /* needs work to find which cdb byte 'num' comes from */
2543 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2544 return check_condition_result;
2545 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002546
Douglas Gilbert773642d2016-04-25 12:16:28 -04002547 if ((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002548 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002549 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2550 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002551 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002552 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002553 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2554 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002555 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2556 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002557 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002558 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002559 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 return check_condition_result;
2561 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002562
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002563 read_lock_irqsave(&atomic_rw, iflags);
2564
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002565 /* DIX + T10 DIF */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002566 if (sdebug_dix && scsi_prot_sg_count(scp)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002567 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002568
2569 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002570 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002571 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002572 return illegal_condition_result;
2573 }
2574 }
2575
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002576 ret = do_device_access(scp, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 read_unlock_irqrestore(&atomic_rw, iflags);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002578 if (ret == -1)
2579 return DID_ERROR << 16;
2580
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002581 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002582
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002583 if (sdebug_any_injecting_opt) {
2584 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2585
2586 if (ep->inj_recovered) {
2587 mk_sense_buffer(scp, RECOVERED_ERROR,
2588 THRESHOLD_EXCEEDED, 0);
2589 return check_condition_result;
2590 } else if (ep->inj_transport) {
2591 mk_sense_buffer(scp, ABORTED_COMMAND,
2592 TRANSPORT_PROBLEM, ACK_NAK_TO);
2593 return check_condition_result;
2594 } else if (ep->inj_dif) {
2595 /* Logical block guard check failed */
2596 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2597 return illegal_condition_result;
2598 } else if (ep->inj_dix) {
2599 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2600 return illegal_condition_result;
2601 }
2602 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002603 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604}
2605
Tomas Winkler58a86352015-07-28 16:54:23 +03002606static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002607{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002608 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002609
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002610 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002611 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002612 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002613
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002614 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002615 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002616
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002617 if (c >= 0x20 && c < 0x7e)
2618 n += scnprintf(b + n, sizeof(b) - n,
2619 " %c ", buf[i+j]);
2620 else
2621 n += scnprintf(b + n, sizeof(b) - n,
2622 "%02x ", buf[i+j]);
2623 }
2624 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002625 }
2626}
2627
2628static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002629 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002630{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002631 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002632 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002633 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002634 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002635 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002636 int dpage_offset;
2637 struct sg_mapping_iter diter;
2638 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002639
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002640 BUG_ON(scsi_sg_count(SCpnt) == 0);
2641 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2642
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002643 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2644 scsi_prot_sg_count(SCpnt),
2645 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2646 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2647 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002648
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002649 /* For each protection page */
2650 while (sg_miter_next(&piter)) {
2651 dpage_offset = 0;
2652 if (WARN_ON(!sg_miter_next(&diter))) {
2653 ret = 0x01;
2654 goto out;
2655 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002656
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002657 for (ppage_offset = 0; ppage_offset < piter.length;
2658 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002659 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002660 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002661 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002662 if (dpage_offset >= diter.length) {
2663 if (WARN_ON(!sg_miter_next(&diter))) {
2664 ret = 0x01;
2665 goto out;
2666 }
2667 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002668 }
2669
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002670 sdt = piter.addr + ppage_offset;
2671 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002672
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002673 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002674 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002675 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002676 goto out;
2677 }
2678
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002679 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002680 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002681 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002682 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002683 diter.consumed = dpage_offset;
2684 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002685 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002686 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002687
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002688 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002689 dix_writes++;
2690
2691 return 0;
2692
2693out:
2694 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002695 sg_miter_stop(&diter);
2696 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002697 return ret;
2698}
2699
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002700static unsigned long lba_to_map_index(sector_t lba)
2701{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002702 if (sdebug_unmap_alignment)
2703 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2704 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002705 return lba;
2706}
2707
2708static sector_t map_index_to_lba(unsigned long index)
2709{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002710 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002711
Douglas Gilbert773642d2016-04-25 12:16:28 -04002712 if (sdebug_unmap_alignment)
2713 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002714 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002715}
2716
Martin K. Petersen44d92692009-10-15 14:45:27 -04002717static unsigned int map_state(sector_t lba, unsigned int *num)
2718{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002719 sector_t end;
2720 unsigned int mapped;
2721 unsigned long index;
2722 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002723
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002724 index = lba_to_map_index(lba);
2725 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002726
2727 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002728 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002729 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002730 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002731
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002732 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002733 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002734 return mapped;
2735}
2736
2737static void map_region(sector_t lba, unsigned int len)
2738{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002739 sector_t end = lba + len;
2740
Martin K. Petersen44d92692009-10-15 14:45:27 -04002741 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002742 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002743
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002744 if (index < map_size)
2745 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002746
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002747 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002748 }
2749}
2750
2751static void unmap_region(sector_t lba, unsigned int len)
2752{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002753 sector_t end = lba + len;
2754
Martin K. Petersen44d92692009-10-15 14:45:27 -04002755 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002756 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002757
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002758 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002759 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002760 index < map_size) {
2761 clear_bit(index, map_storep);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002762 if (sdebug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002763 memset(fake_storep +
Douglas Gilbert773642d2016-04-25 12:16:28 -04002764 lba * sdebug_sector_size, 0,
2765 sdebug_sector_size *
2766 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002767 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002768 if (dif_storep) {
2769 memset(dif_storep + lba, 0xff,
2770 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002771 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002772 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002773 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002774 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002775 }
2776}
2777
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002778static int
2779resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002781 u8 *cmd = scp->cmnd;
2782 u64 lba;
2783 u32 num;
2784 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002786 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002787 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002789 switch (cmd[0]) {
2790 case WRITE_16:
2791 ei_lba = 0;
2792 lba = get_unaligned_be64(cmd + 2);
2793 num = get_unaligned_be32(cmd + 10);
2794 check_prot = true;
2795 break;
2796 case WRITE_10:
2797 ei_lba = 0;
2798 lba = get_unaligned_be32(cmd + 2);
2799 num = get_unaligned_be16(cmd + 7);
2800 check_prot = true;
2801 break;
2802 case WRITE_6:
2803 ei_lba = 0;
2804 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2805 (u32)(cmd[1] & 0x1f) << 16;
2806 num = (0 == cmd[4]) ? 256 : cmd[4];
2807 check_prot = true;
2808 break;
2809 case WRITE_12:
2810 ei_lba = 0;
2811 lba = get_unaligned_be32(cmd + 2);
2812 num = get_unaligned_be32(cmd + 6);
2813 check_prot = true;
2814 break;
2815 case 0x53: /* XDWRITEREAD(10) */
2816 ei_lba = 0;
2817 lba = get_unaligned_be32(cmd + 2);
2818 num = get_unaligned_be16(cmd + 7);
2819 check_prot = false;
2820 break;
2821 default: /* assume WRITE(32) */
2822 lba = get_unaligned_be64(cmd + 12);
2823 ei_lba = get_unaligned_be32(cmd + 20);
2824 num = get_unaligned_be32(cmd + 28);
2825 check_prot = false;
2826 break;
2827 }
2828 if (check_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002829 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002830 (cmd[1] & 0xe0)) {
2831 mk_sense_invalid_opcode(scp);
2832 return check_condition_result;
2833 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002834 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2835 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002836 (cmd[1] & 0xe0) == 0)
2837 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2838 "to DIF device\n");
2839 }
2840
2841 /* inline check_device_access_params() */
2842 if (lba + num > sdebug_capacity) {
2843 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2844 return check_condition_result;
2845 }
2846 /* transfer length excessive (tie in to block limits VPD page) */
2847 if (num > sdebug_store_sectors) {
2848 /* needs work to find which cdb byte 'num' comes from */
2849 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2850 return check_condition_result;
2851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002853 write_lock_irqsave(&atomic_rw, iflags);
2854
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002855 /* DIX + T10 DIF */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002856 if (sdebug_dix && scsi_prot_sg_count(scp)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002857 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002858
2859 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002860 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002861 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002862 return illegal_condition_result;
2863 }
2864 }
2865
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002866 ret = do_device_access(scp, lba, num, true);
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002867 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002868 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002870 if (-1 == ret)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002871 return DID_ERROR << 16;
2872 else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002873 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002874 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002875 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002876
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002877 if (sdebug_any_injecting_opt) {
2878 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2879
2880 if (ep->inj_recovered) {
2881 mk_sense_buffer(scp, RECOVERED_ERROR,
2882 THRESHOLD_EXCEEDED, 0);
2883 return check_condition_result;
2884 } else if (ep->inj_dif) {
2885 /* Logical block guard check failed */
2886 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2887 return illegal_condition_result;
2888 } else if (ep->inj_dix) {
2889 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2890 return illegal_condition_result;
2891 }
2892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 return 0;
2894}
2895
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002896static int
2897resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba,
2898 bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002899{
2900 unsigned long iflags;
2901 unsigned long long i;
2902 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002903 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002904
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002905 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002906 if (ret)
2907 return ret;
2908
2909 write_lock_irqsave(&atomic_rw, iflags);
2910
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002911 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002912 unmap_region(lba, num);
2913 goto out;
2914 }
2915
Douglas Gilbert773642d2016-04-25 12:16:28 -04002916 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002917 /* if ndob then zero 1 logical block, else fetch 1 logical block */
2918 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002919 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002920 ret = 0;
2921 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04002922 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2923 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002924
2925 if (-1 == ret) {
2926 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002927 return DID_ERROR << 16;
2928 } else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002929 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002930 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2931 my_name, "write same",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002932 num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002933
2934 /* Copy first sector to remaining blocks */
2935 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002936 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2937 fake_storep + lba_off,
2938 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002939
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002940 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002941 map_region(lba, num);
2942out:
2943 write_unlock_irqrestore(&atomic_rw, iflags);
2944
2945 return 0;
2946}
2947
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002948static int
2949resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2950{
2951 u8 *cmd = scp->cmnd;
2952 u32 lba;
2953 u16 num;
2954 u32 ei_lba = 0;
2955 bool unmap = false;
2956
2957 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002958 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002959 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2960 return check_condition_result;
2961 } else
2962 unmap = true;
2963 }
2964 lba = get_unaligned_be32(cmd + 2);
2965 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002966 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002967 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2968 return check_condition_result;
2969 }
2970 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2971}
2972
2973static int
2974resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2975{
2976 u8 *cmd = scp->cmnd;
2977 u64 lba;
2978 u32 num;
2979 u32 ei_lba = 0;
2980 bool unmap = false;
2981 bool ndob = false;
2982
2983 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002984 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002985 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2986 return check_condition_result;
2987 } else
2988 unmap = true;
2989 }
2990 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
2991 ndob = true;
2992 lba = get_unaligned_be64(cmd + 2);
2993 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002994 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002995 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
2996 return check_condition_result;
2997 }
2998 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
2999}
3000
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003001/* Note the mode field is in the same position as the (lower) service action
3002 * field. For the Report supported operation codes command, SPC-4 suggests
3003 * each mode of this command should be reported separately; for future. */
3004static int
3005resp_write_buffer(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3006{
3007 u8 *cmd = scp->cmnd;
3008 struct scsi_device *sdp = scp->device;
3009 struct sdebug_dev_info *dp;
3010 u8 mode;
3011
3012 mode = cmd[1] & 0x1f;
3013 switch (mode) {
3014 case 0x4: /* download microcode (MC) and activate (ACT) */
3015 /* set UAs on this device only */
3016 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3017 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3018 break;
3019 case 0x5: /* download MC, save and ACT */
3020 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3021 break;
3022 case 0x6: /* download MC with offsets and ACT */
3023 /* set UAs on most devices (LUs) in this target */
3024 list_for_each_entry(dp,
3025 &devip->sdbg_host->dev_info_list,
3026 dev_list)
3027 if (dp->target == sdp->id) {
3028 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3029 if (devip != dp)
3030 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3031 dp->uas_bm);
3032 }
3033 break;
3034 case 0x7: /* download MC with offsets, save, and ACT */
3035 /* set UA on all devices (LUs) in this target */
3036 list_for_each_entry(dp,
3037 &devip->sdbg_host->dev_info_list,
3038 dev_list)
3039 if (dp->target == sdp->id)
3040 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3041 dp->uas_bm);
3042 break;
3043 default:
3044 /* do nothing for this command for other mode values */
3045 break;
3046 }
3047 return 0;
3048}
3049
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003050static int
3051resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3052{
3053 u8 *cmd = scp->cmnd;
3054 u8 *arr;
3055 u8 *fake_storep_hold;
3056 u64 lba;
3057 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003058 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003059 u8 num;
3060 unsigned long iflags;
3061 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003062 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003063
Douglas Gilbertd467d312014-11-26 12:33:48 -05003064 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003065 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3066 if (0 == num)
3067 return 0; /* degenerate case, not an error */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003068 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003069 (cmd[1] & 0xe0)) {
3070 mk_sense_invalid_opcode(scp);
3071 return check_condition_result;
3072 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003073 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3074 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003075 (cmd[1] & 0xe0) == 0)
3076 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3077 "to DIF device\n");
3078
3079 /* inline check_device_access_params() */
3080 if (lba + num > sdebug_capacity) {
3081 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3082 return check_condition_result;
3083 }
3084 /* transfer length excessive (tie in to block limits VPD page) */
3085 if (num > sdebug_store_sectors) {
3086 /* needs work to find which cdb byte 'num' comes from */
3087 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3088 return check_condition_result;
3089 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003090 dnum = 2 * num;
3091 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3092 if (NULL == arr) {
3093 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3094 INSUFF_RES_ASCQ);
3095 return check_condition_result;
3096 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003097
3098 write_lock_irqsave(&atomic_rw, iflags);
3099
3100 /* trick do_device_access() to fetch both compare and write buffers
3101 * from data-in into arr. Safe (atomic) since write_lock held. */
3102 fake_storep_hold = fake_storep;
3103 fake_storep = arr;
3104 ret = do_device_access(scp, 0, dnum, true);
3105 fake_storep = fake_storep_hold;
3106 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003107 retval = DID_ERROR << 16;
3108 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003109 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003110 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3111 "indicated=%u, IO sent=%d bytes\n", my_name,
3112 dnum * lb_size, ret);
3113 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003114 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003115 retval = check_condition_result;
3116 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003117 }
3118 if (scsi_debug_lbp())
3119 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003120cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003121 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003122 kfree(arr);
3123 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003124}
3125
Martin K. Petersen44d92692009-10-15 14:45:27 -04003126struct unmap_block_desc {
3127 __be64 lba;
3128 __be32 blocks;
3129 __be32 __reserved;
3130};
3131
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003132static int
3133resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003134{
3135 unsigned char *buf;
3136 struct unmap_block_desc *desc;
3137 unsigned int i, payload_len, descriptors;
3138 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003139 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003140
Martin K. Petersen44d92692009-10-15 14:45:27 -04003141
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003142 if (!scsi_debug_lbp())
3143 return 0; /* fib and say its done */
3144 payload_len = get_unaligned_be16(scp->cmnd + 7);
3145 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003146
3147 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003148 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003149 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003150 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003151 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003152
Douglas Gilbertb333a812016-04-25 12:16:30 -04003153 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003154 if (!buf) {
3155 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3156 INSUFF_RES_ASCQ);
3157 return check_condition_result;
3158 }
3159
3160 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003161
3162 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3163 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3164
3165 desc = (void *)&buf[8];
3166
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003167 write_lock_irqsave(&atomic_rw, iflags);
3168
Martin K. Petersen44d92692009-10-15 14:45:27 -04003169 for (i = 0 ; i < descriptors ; i++) {
3170 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3171 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3172
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003173 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003174 if (ret)
3175 goto out;
3176
3177 unmap_region(lba, num);
3178 }
3179
3180 ret = 0;
3181
3182out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003183 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003184 kfree(buf);
3185
3186 return ret;
3187}
3188
3189#define SDEBUG_GET_LBA_STATUS_LEN 32
3190
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003191static int
3192resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003193{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003194 u8 *cmd = scp->cmnd;
3195 u64 lba;
3196 u32 alloc_len, mapped, num;
3197 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003198 int ret;
3199
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003200 lba = get_unaligned_be64(cmd + 2);
3201 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003202
3203 if (alloc_len < 24)
3204 return 0;
3205
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003206 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003207 if (ret)
3208 return ret;
3209
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003210 if (scsi_debug_lbp())
3211 mapped = map_state(lba, &num);
3212 else {
3213 mapped = 1;
3214 /* following just in case virtual_gb changed */
3215 sdebug_capacity = get_sdebug_capacity();
3216 if (sdebug_capacity - lba <= 0xffffffff)
3217 num = sdebug_capacity - lba;
3218 else
3219 num = 0xffffffff;
3220 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003221
3222 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003223 put_unaligned_be32(20, arr); /* Parameter Data Length */
3224 put_unaligned_be64(lba, arr + 8); /* LBA */
3225 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3226 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003227
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003228 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003229}
3230
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003231#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232
3233static int resp_report_luns(struct scsi_cmnd * scp,
3234 struct sdebug_dev_info * devip)
3235{
3236 unsigned int alloc_len;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003237 int lun_cnt, i, upper, num, n, want_wlun, shortish;
3238 u64 lun;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003239 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 int select_report = (int)cmd[2];
3241 struct scsi_lun *one_lun;
3242 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003243 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003245 clear_luns_changed_on_target(devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003247 shortish = (alloc_len < 4);
3248 if (shortish || (select_report > 2)) {
3249 mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 return check_condition_result;
3251 }
3252 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
3253 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003254 lun_cnt = sdebug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003255 if (1 == select_report)
3256 lun_cnt = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003257 else if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003258 --lun_cnt;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003259 want_wlun = (select_report > 0) ? 1 : 0;
3260 num = lun_cnt + want_wlun;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003261 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3262 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3263 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3264 sizeof(struct scsi_lun)), num);
3265 if (n < num) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003266 want_wlun = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003267 lun_cnt = n;
3268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003270 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003271 for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003272 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3273 i++, lun++) {
3274 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 if (upper)
3276 one_lun[i].scsi_lun[0] =
3277 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003278 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003280 if (want_wlun) {
Tomas Winkler34d55432015-07-28 16:54:21 +03003281 one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
3282 one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003283 i++;
3284 }
3285 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 return fill_from_dev_buffer(scp, arr,
3287 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
3288}
3289
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003290static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3291 unsigned int num, struct sdebug_dev_info *devip)
3292{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003293 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003294 unsigned char *kaddr, *buf;
3295 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003296 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003297 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003298
3299 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003300 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003301 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003302 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3303 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003304 return check_condition_result;
3305 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003306
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003307 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003308
3309 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003310 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3311 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003312
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003313 while (sg_miter_next(&miter)) {
3314 kaddr = miter.addr;
3315 for (j = 0; j < miter.length; j++)
3316 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003317
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003318 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003319 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003320 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003321 kfree(buf);
3322
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003323 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003324}
3325
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003326static int
3327resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3328{
3329 u8 *cmd = scp->cmnd;
3330 u64 lba;
3331 u32 num;
3332 int errsts;
3333
3334 if (!scsi_bidi_cmnd(scp)) {
3335 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3336 INSUFF_RES_ASCQ);
3337 return check_condition_result;
3338 }
3339 errsts = resp_read_dt0(scp, devip);
3340 if (errsts)
3341 return errsts;
3342 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3343 errsts = resp_write_dt0(scp, devip);
3344 if (errsts)
3345 return errsts;
3346 }
3347 lba = get_unaligned_be32(cmd + 2);
3348 num = get_unaligned_be16(cmd + 7);
3349 return resp_xdwriteread(scp, lba, num, devip);
3350}
3351
Douglas Gilberta10bc122016-04-25 12:16:32 -04003352/* Queued command completions converge here. */
3353static void
3354sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003356 int qa_indx;
3357 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003359 struct sdebug_queued_cmd *sqcp;
3360 struct scsi_cmnd *scp;
3361 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003363 atomic_inc(&sdebug_completions);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003364 qa_indx = sd_dp->qa_indx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003365 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003366 pr_err("wild qa_indx=%d\n", qa_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 return;
3368 }
3369 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003370 sqcp = &queued_arr[qa_indx];
3371 scp = sqcp->a_cmnd;
3372 if (NULL == scp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003374 pr_err("scp is NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 return;
3376 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003377 devip = (struct sdebug_dev_info *)scp->device->hostdata;
3378 if (devip)
3379 atomic_dec(&devip->num_in_q);
3380 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003381 pr_err("devip=NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003382 if (atomic_read(&retired_max_queue) > 0)
3383 retiring = 1;
3384
3385 sqcp->a_cmnd = NULL;
3386 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3387 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003388 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003389 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003391
3392 if (unlikely(retiring)) { /* user has reduced max_queue */
3393 int k, retval;
3394
3395 retval = atomic_read(&retired_max_queue);
3396 if (qa_indx >= retval) {
3397 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003398 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003399 return;
3400 }
3401 k = find_last_bit(queued_in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003402 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003403 atomic_set(&retired_max_queue, 0);
3404 else
3405 atomic_set(&retired_max_queue, k + 1);
3406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003408 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409}
3410
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003411/* When high resolution timer goes off this function is called. */
3412static enum hrtimer_restart
3413sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3414{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003415 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3416 hrt);
3417 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003418 return HRTIMER_NORESTART;
3419}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420
Douglas Gilberta10bc122016-04-25 12:16:32 -04003421/* When work queue schedules work, it calls this function. */
3422static void
3423sdebug_q_cmd_wq_complete(struct work_struct *work)
3424{
3425 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3426 ew.work);
3427 sdebug_q_cmd_complete(sd_dp);
3428}
3429
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003430static struct sdebug_dev_info *
3431sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003432{
3433 struct sdebug_dev_info *devip;
3434
3435 devip = kzalloc(sizeof(*devip), flags);
3436 if (devip) {
3437 devip->sdbg_host = sdbg_host;
3438 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3439 }
3440 return devip;
3441}
3442
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
3444{
3445 struct sdebug_host_info * sdbg_host;
3446 struct sdebug_dev_info * open_devip = NULL;
3447 struct sdebug_dev_info * devip =
3448 (struct sdebug_dev_info *)sdev->hostdata;
3449
3450 if (devip)
3451 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003452 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3453 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003454 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 return NULL;
3456 }
3457 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3458 if ((devip->used) && (devip->channel == sdev->channel) &&
3459 (devip->target == sdev->id) &&
3460 (devip->lun == sdev->lun))
3461 return devip;
3462 else {
3463 if ((!devip->used) && (!open_devip))
3464 open_devip = devip;
3465 }
3466 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003467 if (!open_devip) { /* try and make a new one */
3468 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3469 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003470 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 return NULL;
3472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003474
3475 open_devip->channel = sdev->channel;
3476 open_devip->target = sdev->id;
3477 open_devip->lun = sdev->lun;
3478 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003479 atomic_set(&open_devip->num_in_q, 0);
3480 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003481 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003482 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483}
3484
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003485static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003487 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003488 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003489 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003490 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003491 return 0;
3492}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003494static int scsi_debug_slave_configure(struct scsi_device *sdp)
3495{
3496 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003497
Douglas Gilbert773642d2016-04-25 12:16:28 -04003498 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003499 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003500 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3501 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
3502 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
3503 devip = devInfoReg(sdp);
3504 if (NULL == devip)
3505 return 1; /* no resources, will be marked offline */
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003506 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003507 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003508 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003509 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003510 return 0;
3511}
3512
3513static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3514{
3515 struct sdebug_dev_info *devip =
3516 (struct sdebug_dev_info *)sdp->hostdata;
3517
Douglas Gilbert773642d2016-04-25 12:16:28 -04003518 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003519 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003520 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3521 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003522 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003523 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003524 sdp->hostdata = NULL;
3525 }
3526}
3527
Douglas Gilberta10bc122016-04-25 12:16:32 -04003528/* If @cmnd found deletes its timer or work queue and returns true; else
3529 returns false */
3530static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003531{
3532 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003533 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003534 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003535 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003536 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003537
3538 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003539 qmax = sdebug_max_queue;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003540 r_qmax = atomic_read(&retired_max_queue);
3541 if (r_qmax > qmax)
3542 qmax = r_qmax;
3543 for (k = 0; k < qmax; ++k) {
3544 if (test_bit(k, queued_in_use_bm)) {
3545 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003546 if (cmnd != sqcp->a_cmnd)
3547 continue;
3548 /* found command */
3549 devip = (struct sdebug_dev_info *)
3550 cmnd->device->hostdata;
3551 if (devip)
3552 atomic_dec(&devip->num_in_q);
3553 sqcp->a_cmnd = NULL;
3554 sd_dp = sqcp->sd_dp;
3555 spin_unlock_irqrestore(&queued_arr_lock,
3556 iflags);
3557 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
3558 if (sd_dp)
3559 hrtimer_cancel(&sd_dp->hrt);
3560 } else if (sdebug_jdelay < 0) {
3561 if (sd_dp)
3562 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003563 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003564 clear_bit(k, queued_in_use_bm);
3565 return true;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003566 }
3567 }
3568 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003569 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003570}
3571
Douglas Gilberta10bc122016-04-25 12:16:32 -04003572/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003573static void stop_all_queued(void)
3574{
3575 unsigned long iflags;
3576 int k;
3577 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003578 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003579 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003580
3581 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003582 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3583 if (test_bit(k, queued_in_use_bm)) {
3584 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003585 if (NULL == sqcp->a_cmnd)
3586 continue;
3587 devip = (struct sdebug_dev_info *)
3588 sqcp->a_cmnd->device->hostdata;
3589 if (devip)
3590 atomic_dec(&devip->num_in_q);
3591 sqcp->a_cmnd = NULL;
3592 sd_dp = sqcp->sd_dp;
3593 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3594 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
3595 if (sd_dp)
3596 hrtimer_cancel(&sd_dp->hrt);
3597 } else if (sdebug_jdelay < 0) {
3598 if (sd_dp)
3599 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003600 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003601 clear_bit(k, queued_in_use_bm);
3602 spin_lock_irqsave(&queued_arr_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003603 }
3604 }
3605 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606}
3607
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003608/* Free queued command memory on heap */
3609static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003611 int k;
3612 struct sdebug_queued_cmd *sqcp;
3613
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003614 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3615 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003616 kfree(sqcp->sd_dp);
3617 sqcp->sd_dp = NULL;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619}
3620
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003621static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003623 bool ok;
3624
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003625 ++num_aborts;
3626 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003627 ok = stop_queued_cmnd(SCpnt);
3628 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3629 sdev_printk(KERN_INFO, SCpnt->device,
3630 "%s: command%s found\n", __func__,
3631 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003633 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634}
3635
3636static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3637{
3638 struct sdebug_dev_info * devip;
3639
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003641 if (SCpnt && SCpnt->device) {
3642 struct scsi_device *sdp = SCpnt->device;
3643
Douglas Gilbert773642d2016-04-25 12:16:28 -04003644 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003645 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3646 devip = devInfoReg(sdp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003648 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 }
3650 return SUCCESS;
3651}
3652
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003653static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3654{
3655 struct sdebug_host_info *sdbg_host;
3656 struct sdebug_dev_info *devip;
3657 struct scsi_device *sdp;
3658 struct Scsi_Host *hp;
3659 int k = 0;
3660
3661 ++num_target_resets;
3662 if (!SCpnt)
3663 goto lie;
3664 sdp = SCpnt->device;
3665 if (!sdp)
3666 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003667 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003668 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3669 hp = sdp->host;
3670 if (!hp)
3671 goto lie;
3672 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3673 if (sdbg_host) {
3674 list_for_each_entry(devip,
3675 &sdbg_host->dev_info_list,
3676 dev_list)
3677 if (devip->target == sdp->id) {
3678 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3679 ++k;
3680 }
3681 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003682 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003683 sdev_printk(KERN_INFO, sdp,
3684 "%s: %d device(s) found in target\n", __func__, k);
3685lie:
3686 return SUCCESS;
3687}
3688
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3690{
3691 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003692 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 struct scsi_device * sdp;
3694 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003695 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003698 if (!(SCpnt && SCpnt->device))
3699 goto lie;
3700 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003701 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003702 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3703 hp = sdp->host;
3704 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003705 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003707 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003709 dev_list) {
3710 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3711 ++k;
3712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 }
3714 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003715 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003716 sdev_printk(KERN_INFO, sdp,
3717 "%s: %d device(s) found in host\n", __func__, k);
3718lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 return SUCCESS;
3720}
3721
3722static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3723{
3724 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003725 struct sdebug_dev_info *devip;
3726 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003729 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003730 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 spin_lock(&sdebug_host_list_lock);
3732 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003733 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3734 dev_list) {
3735 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3736 ++k;
3737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 }
3739 spin_unlock(&sdebug_host_list_lock);
3740 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003741 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003742 sdev_printk(KERN_INFO, SCpnt->device,
3743 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 return SUCCESS;
3745}
3746
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003747static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003748 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749{
3750 struct partition * pp;
3751 int starts[SDEBUG_MAX_PARTS + 2];
3752 int sectors_per_part, num_sectors, k;
3753 int heads_by_sects, start_sec, end_sec;
3754
3755 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003756 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003758 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3759 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003760 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003762 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003764 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3766 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003767 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3769 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003770 starts[sdebug_num_parts] = num_sectors;
3771 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772
3773 ramp[510] = 0x55; /* magic partition markings */
3774 ramp[511] = 0xAA;
3775 pp = (struct partition *)(ramp + 0x1be);
3776 for (k = 0; starts[k + 1]; ++k, ++pp) {
3777 start_sec = starts[k];
3778 end_sec = starts[k + 1] - 1;
3779 pp->boot_ind = 0;
3780
3781 pp->cyl = start_sec / heads_by_sects;
3782 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3783 / sdebug_sectors_per;
3784 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3785
3786 pp->end_cyl = end_sec / heads_by_sects;
3787 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3788 / sdebug_sectors_per;
3789 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3790
Akinobu Mita150c3542013-08-26 22:08:40 +09003791 pp->start_sect = cpu_to_le32(start_sec);
3792 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 pp->sys_ind = 0x83; /* plain Linux partition */
3794 }
3795}
3796
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003797static int
3798schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3799 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003801 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003802 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003803 struct sdebug_queued_cmd *sqcp = NULL;
Tomas Winkler299b6c02015-07-28 16:54:24 +03003804 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003805 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806
Tomas Winkler299b6c02015-07-28 16:54:24 +03003807 /* this should never happen */
3808 if (WARN_ON(!cmnd))
3809 return SCSI_MLQUEUE_HOST_BUSY;
3810
3811 if (NULL == devip) {
3812 pr_warn("called devip == NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003813 /* no particularly good error to report back */
3814 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03003816
3817 sdp = cmnd->device;
3818
Douglas Gilbert773642d2016-04-25 12:16:28 -04003819 if (sdebug_verbose && scsi_result)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003820 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3821 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003822 if (delta_jiff == 0)
3823 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003825 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003826 spin_lock_irqsave(&queued_arr_lock, iflags);
3827 num_in_q = atomic_read(&devip->num_in_q);
3828 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003829 inject = 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003830 if ((qdepth > 0) && (num_in_q >= qdepth)) {
3831 if (scsi_result) {
3832 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3833 goto respond_in_thread;
3834 } else
3835 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003836 } else if ((sdebug_every_nth != 0) &&
3837 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003838 (scsi_result == 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003839 if ((num_in_q == (qdepth - 1)) &&
3840 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04003841 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003842 atomic_set(&sdebug_a_tsf, 0);
3843 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003844 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003846 }
3847
Douglas Gilbert773642d2016-04-25 12:16:28 -04003848 k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
3849 if (k >= sdebug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003851 if (scsi_result)
3852 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003853 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003854 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003855 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003856 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003857 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003858 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003859 (scsi_result ? "status: TASK SET FULL" :
3860 "report: host busy"));
3861 if (scsi_result)
3862 goto respond_in_thread;
3863 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003864 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003866 __set_bit(k, queued_in_use_bm);
3867 atomic_inc(&devip->num_in_q);
3868 sqcp = &queued_arr[k];
3869 sqcp->a_cmnd = cmnd;
3870 cmnd->result = scsi_result;
3871 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003872 sd_dp = sqcp->sd_dp;
Douglas Gilbertb333a812016-04-25 12:16:30 -04003873 if ((delta_jiff > 0) || (sdebug_ndelay > 0)) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04003874 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003875
Douglas Gilbertb333a812016-04-25 12:16:30 -04003876 if (delta_jiff > 0) {
3877 struct timespec ts;
3878
3879 jiffies_to_timespec(delta_jiff, &ts);
3880 kt = ktime_set(ts.tv_sec, ts.tv_nsec);
3881 } else
3882 kt = ktime_set(0, sdebug_ndelay);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003883 if (NULL == sd_dp) {
3884 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
3885 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003886 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003887 sqcp->sd_dp = sd_dp;
3888 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003889 HRTIMER_MODE_REL);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003890 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
3891 sd_dp->qa_indx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003892 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003893 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003894 } else { /* jdelay < 0 */
Douglas Gilberta10bc122016-04-25 12:16:32 -04003895 if (NULL == sd_dp) {
3896 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
3897 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003898 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003899 sqcp->sd_dp = sd_dp;
3900 sd_dp->qa_indx = k;
3901 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003902 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003903 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003904 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003905 if ((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003906 (scsi_result == device_qfull_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003907 sdev_printk(KERN_INFO, sdp,
3908 "%s: num_in_q=%d +1, %s%s\n", __func__,
3909 num_in_q, (inject ? "<inject> " : ""),
3910 "status: TASK SET FULL");
3911 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003912
3913respond_in_thread: /* call back to mid-layer using invocation thread */
3914 cmnd->result = scsi_result;
3915 cmnd->scsi_done(cmnd);
3916 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003918
Douglas Gilbert23183912006-09-16 20:30:47 -04003919/* Note: The following macros create attribute files in the
3920 /sys/module/scsi_debug/parameters directory. Unfortunately this
3921 driver is unaware of a change and cannot trigger auxiliary actions
3922 as it can when the corresponding attribute in the
3923 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3924 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003925module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
3926module_param_named(ato, sdebug_ato, int, S_IRUGO);
3927module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003928module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003929module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
3930module_param_named(dif, sdebug_dif, int, S_IRUGO);
3931module_param_named(dix, sdebug_dix, int, S_IRUGO);
3932module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
3933module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
3934module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
3935module_param_named(guard, sdebug_guard, uint, S_IRUGO);
3936module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
3937module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
3938module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
3939module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
3940module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
3941module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
3942module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
3943module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
3944module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
3945module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
3946module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
3947module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
3948module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
3949module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
3950module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
3951module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
3952module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
3953module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
3954module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
3955module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
3956module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
3957module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
3958module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
3959module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
3960module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
3961module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
3962module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04003963 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003964module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003965 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966
3967MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
3968MODULE_DESCRIPTION("SCSI debug adapter driver");
3969MODULE_LICENSE("GPL");
3970MODULE_VERSION(SCSI_DEBUG_VERSION);
3971
3972MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003973MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09003974MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003975MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003976MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003977MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
3978MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003979MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07003980MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04003981MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003982MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04003983MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003984MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
3985MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
3986MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003987MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003988MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003989MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003990MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3991MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003992MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003993MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003995MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05003996MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05003997MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003998MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004000MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02004001MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004002MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004003MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004004MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4005MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004006MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4007MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004008MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004009MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4010MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011
4012static char sdebug_info[256];
4013
4014static const char * scsi_debug_info(struct Scsi_Host * shp)
4015{
4016 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
4017 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004018 sdebug_version_date, sdebug_dev_size_mb, sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 return sdebug_info;
4020}
4021
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004022/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Al Viroc8ed5552013-03-31 01:46:06 -04004023static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024{
Al Viroc8ed5552013-03-31 01:46:06 -04004025 char arr[16];
4026 int opts;
4027 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028
Al Viroc8ed5552013-03-31 01:46:06 -04004029 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4030 return -EACCES;
4031 memcpy(arr, buffer, minLen);
4032 arr[minLen] = '\0';
4033 if (1 != sscanf(arr, "%d", &opts))
4034 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004035 sdebug_opts = opts;
4036 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4037 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4038 if (sdebug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004039 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04004040 return length;
4041}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004043/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4044 * same for each scsi_debug host (if more than one). Some of the counters
4045 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004046static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4047{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004048 int f, l;
4049 char b[32];
4050
Douglas Gilbert773642d2016-04-25 12:16:28 -04004051 if (sdebug_every_nth > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004052 snprintf(b, sizeof(b), " (curr:%d)",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004053 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004054 atomic_read(&sdebug_a_tsf) :
4055 atomic_read(&sdebug_cmnd_count)));
4056 else
4057 b[0] = '\0';
4058
4059 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
4060 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4061 "every_nth=%d%s\n"
4062 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
4063 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4064 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4065 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4066 "usec_in_jiffy=%lu\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004067 SCSI_DEBUG_VERSION, sdebug_version_date,
4068 sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04004069 sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004070 sdebug_max_luns, atomic_read(&sdebug_completions),
4071 sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004072 sdebug_sectors_per, num_aborts, num_dev_resets,
4073 num_target_resets, num_bus_resets, num_host_resets,
4074 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4075
Douglas Gilbert773642d2016-04-25 12:16:28 -04004076 f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4077 if (f != sdebug_max_queue) {
4078 l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004079 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
4080 "queued_in_use_bm", f, l);
4081 }
Al Viroc8ed5552013-03-31 01:46:06 -04004082 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083}
4084
Akinobu Mita82069372013-10-14 22:48:04 +09004085static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004087 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088}
Douglas Gilbertc2206092016-04-25 12:16:31 -04004089/* Returns -EBUSY if jdelay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09004090static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4091 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004093 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094
Douglas Gilbertc2206092016-04-25 12:16:31 -04004095 if ((count > 0) && (1 == sscanf(buf, "%d", &jdelay))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004096 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004097 if (sdebug_jdelay != jdelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004098 unsigned long iflags;
4099 int k;
4100
4101 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004102 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4103 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004104 res = -EBUSY; /* have queued commands */
4105 else {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004106 /* make sure sdebug_defer instances get
4107 * re-allocated for new delay variant */
4108 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004109 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004110 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004111 }
4112 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004114 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 }
4116 return -EINVAL;
4117}
Akinobu Mita82069372013-10-14 22:48:04 +09004118static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004120static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4121{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004122 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004123}
4124/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004125/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004126static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4127 size_t count)
4128{
4129 unsigned long iflags;
4130 int ndelay, res, k;
4131
4132 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4133 (ndelay >= 0) && (ndelay < 1000000000)) {
4134 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004135 if (sdebug_ndelay != ndelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004136 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004137 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4138 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004139 res = -EBUSY; /* have queued commands */
4140 else {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004141 /* make sure sdebug_defer instances get
4142 * re-allocated for new delay variant */
4143 free_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004144 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004145 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4146 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004147 }
4148 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4149 }
4150 return res;
4151 }
4152 return -EINVAL;
4153}
4154static DRIVER_ATTR_RW(ndelay);
4155
Akinobu Mita82069372013-10-14 22:48:04 +09004156static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004158 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159}
4160
Akinobu Mita82069372013-10-14 22:48:04 +09004161static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4162 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163{
4164 int opts;
4165 char work[20];
4166
4167 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07004168 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 if (1 == sscanf(&work[2], "%x", &opts))
4170 goto opts_done;
4171 } else {
4172 if (1 == sscanf(work, "%d", &opts))
4173 goto opts_done;
4174 }
4175 }
4176 return -EINVAL;
4177opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004178 sdebug_opts = opts;
4179 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4180 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004181 atomic_set(&sdebug_cmnd_count, 0);
4182 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 return count;
4184}
Akinobu Mita82069372013-10-14 22:48:04 +09004185static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
Akinobu Mita82069372013-10-14 22:48:04 +09004187static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004189 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190}
Akinobu Mita82069372013-10-14 22:48:04 +09004191static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4192 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193{
4194 int n;
4195
4196 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004197 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 return count;
4199 }
4200 return -EINVAL;
4201}
Akinobu Mita82069372013-10-14 22:48:04 +09004202static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203
Akinobu Mita82069372013-10-14 22:48:04 +09004204static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004206 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207}
Akinobu Mita82069372013-10-14 22:48:04 +09004208static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4209 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210{
4211 int n;
4212
4213 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004214 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 return count;
4216 }
4217 return -EINVAL;
4218}
Akinobu Mita82069372013-10-14 22:48:04 +09004219static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220
Akinobu Mita82069372013-10-14 22:48:04 +09004221static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004222{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004223 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004224}
Akinobu Mita82069372013-10-14 22:48:04 +09004225static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4226 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004227{
4228 int n;
4229
4230 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004231 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004232 sdebug_fake_rw = (sdebug_fake_rw > 0);
4233 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004234 if ((0 == n) && (NULL == fake_storep)) {
4235 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004236 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004237 1048576;
4238
4239 fake_storep = vmalloc(sz);
4240 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004241 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004242 return -ENOMEM;
4243 }
4244 memset(fake_storep, 0, sz);
4245 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004246 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004247 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004248 return count;
4249 }
4250 return -EINVAL;
4251}
Akinobu Mita82069372013-10-14 22:48:04 +09004252static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004253
Akinobu Mita82069372013-10-14 22:48:04 +09004254static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004255{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004256 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004257}
Akinobu Mita82069372013-10-14 22:48:04 +09004258static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4259 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004260{
4261 int n;
4262
4263 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004264 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004265 return count;
4266 }
4267 return -EINVAL;
4268}
Akinobu Mita82069372013-10-14 22:48:04 +09004269static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004270
Akinobu Mita82069372013-10-14 22:48:04 +09004271static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004273 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274}
Akinobu Mita82069372013-10-14 22:48:04 +09004275static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4276 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277{
4278 int n;
4279
4280 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004281 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 sdebug_max_tgts_luns();
4283 return count;
4284 }
4285 return -EINVAL;
4286}
Akinobu Mita82069372013-10-14 22:48:04 +09004287static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288
Akinobu Mita82069372013-10-14 22:48:04 +09004289static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004291 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292}
Akinobu Mita82069372013-10-14 22:48:04 +09004293static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294
Akinobu Mita82069372013-10-14 22:48:04 +09004295static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004297 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298}
Akinobu Mita82069372013-10-14 22:48:04 +09004299static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300
Akinobu Mita82069372013-10-14 22:48:04 +09004301static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004303 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304}
Akinobu Mita82069372013-10-14 22:48:04 +09004305static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4306 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307{
4308 int nth;
4309
4310 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004311 sdebug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004312 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 return count;
4314 }
4315 return -EINVAL;
4316}
Akinobu Mita82069372013-10-14 22:48:04 +09004317static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
Akinobu Mita82069372013-10-14 22:48:04 +09004319static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004321 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322}
Akinobu Mita82069372013-10-14 22:48:04 +09004323static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4324 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325{
4326 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004327 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328
4329 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004330 changed = (sdebug_max_luns != n);
4331 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004333 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004334 struct sdebug_host_info *sdhp;
4335 struct sdebug_dev_info *dp;
4336
4337 spin_lock(&sdebug_host_list_lock);
4338 list_for_each_entry(sdhp, &sdebug_host_list,
4339 host_list) {
4340 list_for_each_entry(dp, &sdhp->dev_info_list,
4341 dev_list) {
4342 set_bit(SDEBUG_UA_LUNS_CHANGED,
4343 dp->uas_bm);
4344 }
4345 }
4346 spin_unlock(&sdebug_host_list_lock);
4347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 return count;
4349 }
4350 return -EINVAL;
4351}
Akinobu Mita82069372013-10-14 22:48:04 +09004352static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353
Akinobu Mita82069372013-10-14 22:48:04 +09004354static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004355{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004356 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004357}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004358/* N.B. max_queue can be changed while there are queued commands. In flight
4359 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004360static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4361 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004362{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004363 unsigned long iflags;
4364 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004365
4366 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4367 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004368 spin_lock_irqsave(&queued_arr_lock, iflags);
4369 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004370 sdebug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004371 if (SCSI_DEBUG_CANQUEUE == k)
4372 atomic_set(&retired_max_queue, 0);
4373 else if (k >= n)
4374 atomic_set(&retired_max_queue, k + 1);
4375 else
4376 atomic_set(&retired_max_queue, 0);
4377 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004378 return count;
4379 }
4380 return -EINVAL;
4381}
Akinobu Mita82069372013-10-14 22:48:04 +09004382static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004383
Akinobu Mita82069372013-10-14 22:48:04 +09004384static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004385{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004386 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004387}
Akinobu Mita82069372013-10-14 22:48:04 +09004388static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004389
Akinobu Mita82069372013-10-14 22:48:04 +09004390static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004392 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393}
Akinobu Mita82069372013-10-14 22:48:04 +09004394static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395
Akinobu Mita82069372013-10-14 22:48:04 +09004396static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004397{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004398 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004399}
Akinobu Mita82069372013-10-14 22:48:04 +09004400static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4401 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004402{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004403 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004404 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004405
4406 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004407 changed = (sdebug_virtual_gb != n);
4408 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004409 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004410 if (changed) {
4411 struct sdebug_host_info *sdhp;
4412 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004413
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004414 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004415 list_for_each_entry(sdhp, &sdebug_host_list,
4416 host_list) {
4417 list_for_each_entry(dp, &sdhp->dev_info_list,
4418 dev_list) {
4419 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4420 dp->uas_bm);
4421 }
4422 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004423 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004424 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004425 return count;
4426 }
4427 return -EINVAL;
4428}
Akinobu Mita82069372013-10-14 22:48:04 +09004429static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004430
Akinobu Mita82069372013-10-14 22:48:04 +09004431static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004433 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434}
4435
Akinobu Mita82069372013-10-14 22:48:04 +09004436static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4437 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004439 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004441 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 if (delta_hosts > 0) {
4444 do {
4445 sdebug_add_adapter();
4446 } while (--delta_hosts);
4447 } else if (delta_hosts < 0) {
4448 do {
4449 sdebug_remove_adapter();
4450 } while (++delta_hosts);
4451 }
4452 return count;
4453}
Akinobu Mita82069372013-10-14 22:48:04 +09004454static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455
Akinobu Mita82069372013-10-14 22:48:04 +09004456static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004457{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004458 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004459}
Akinobu Mita82069372013-10-14 22:48:04 +09004460static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4461 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004462{
4463 int n;
4464
4465 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004466 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004467 return count;
4468 }
4469 return -EINVAL;
4470}
Akinobu Mita82069372013-10-14 22:48:04 +09004471static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004472
Akinobu Mita82069372013-10-14 22:48:04 +09004473static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04004474{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004475 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004476}
Akinobu Mita82069372013-10-14 22:48:04 +09004477static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004478
Akinobu Mita82069372013-10-14 22:48:04 +09004479static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004480{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004481 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004482}
Akinobu Mita82069372013-10-14 22:48:04 +09004483static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004484
Akinobu Mita82069372013-10-14 22:48:04 +09004485static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004486{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004487 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004488}
Akinobu Mita82069372013-10-14 22:48:04 +09004489static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004490
Akinobu Mita82069372013-10-14 22:48:04 +09004491static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004492{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004493 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004494}
Akinobu Mita82069372013-10-14 22:48:04 +09004495static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004496
Akinobu Mita82069372013-10-14 22:48:04 +09004497static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004498{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004499 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004500}
Akinobu Mita82069372013-10-14 22:48:04 +09004501static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004502
Akinobu Mita82069372013-10-14 22:48:04 +09004503static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004504{
4505 ssize_t count;
4506
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004507 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004508 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4509 sdebug_store_sectors);
4510
Tejun Heoc7badc92015-02-13 14:37:51 -08004511 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4512 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004513 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004514 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004515
4516 return count;
4517}
Akinobu Mita82069372013-10-14 22:48:04 +09004518static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004519
Akinobu Mita82069372013-10-14 22:48:04 +09004520static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004521{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004522 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004523}
Akinobu Mita82069372013-10-14 22:48:04 +09004524static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4525 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004526{
4527 int n;
4528
4529 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004530 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004531 return count;
4532 }
4533 return -EINVAL;
4534}
Akinobu Mita82069372013-10-14 22:48:04 +09004535static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004536
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004537static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4538{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004539 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004540}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004541/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004542static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4543 size_t count)
4544{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004545 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004546
4547 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004548 sdebug_host_lock = (n > 0);
4549 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004550 }
4551 return -EINVAL;
4552}
4553static DRIVER_ATTR_RW(host_lock);
4554
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004555static ssize_t strict_show(struct device_driver *ddp, char *buf)
4556{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004557 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004558}
4559static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4560 size_t count)
4561{
4562 int n;
4563
4564 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004565 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004566 return count;
4567 }
4568 return -EINVAL;
4569}
4570static DRIVER_ATTR_RW(strict);
4571
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004572
Akinobu Mita82069372013-10-14 22:48:04 +09004573/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004574 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4575 files (over those found in the /sys/module/scsi_debug/parameters
4576 directory) is that auxiliary actions can be triggered when an attribute
4577 is changed. For example see: sdebug_add_host_store() above.
4578 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004579
Akinobu Mita82069372013-10-14 22:48:04 +09004580static struct attribute *sdebug_drv_attrs[] = {
4581 &driver_attr_delay.attr,
4582 &driver_attr_opts.attr,
4583 &driver_attr_ptype.attr,
4584 &driver_attr_dsense.attr,
4585 &driver_attr_fake_rw.attr,
4586 &driver_attr_no_lun_0.attr,
4587 &driver_attr_num_tgts.attr,
4588 &driver_attr_dev_size_mb.attr,
4589 &driver_attr_num_parts.attr,
4590 &driver_attr_every_nth.attr,
4591 &driver_attr_max_luns.attr,
4592 &driver_attr_max_queue.attr,
4593 &driver_attr_no_uld.attr,
4594 &driver_attr_scsi_level.attr,
4595 &driver_attr_virtual_gb.attr,
4596 &driver_attr_add_host.attr,
4597 &driver_attr_vpd_use_hostno.attr,
4598 &driver_attr_sector_size.attr,
4599 &driver_attr_dix.attr,
4600 &driver_attr_dif.attr,
4601 &driver_attr_guard.attr,
4602 &driver_attr_ato.attr,
4603 &driver_attr_map.attr,
4604 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004605 &driver_attr_host_lock.attr,
4606 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004607 &driver_attr_strict.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004608 NULL,
4609};
4610ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004612static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004613
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614static int __init scsi_debug_init(void)
4615{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004616 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 int host_to_add;
4618 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004619 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004621 atomic_set(&sdebug_cmnd_count, 0);
4622 atomic_set(&sdebug_completions, 0);
4623 atomic_set(&retired_max_queue, 0);
4624
Douglas Gilbert773642d2016-04-25 12:16:28 -04004625 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004626 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04004627 sdebug_ndelay = 0;
4628 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04004629 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004630
Douglas Gilbert773642d2016-04-25 12:16:28 -04004631 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04004632 case 512:
4633 case 1024:
4634 case 2048:
4635 case 4096:
4636 break;
4637 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004638 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004639 return -EINVAL;
4640 }
4641
Douglas Gilbert773642d2016-04-25 12:16:28 -04004642 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004643
4644 case SD_DIF_TYPE0_PROTECTION:
4645 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004646 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004647 case SD_DIF_TYPE3_PROTECTION:
4648 break;
4649
4650 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03004651 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004652 return -EINVAL;
4653 }
4654
Douglas Gilbert773642d2016-04-25 12:16:28 -04004655 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004656 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004657 return -EINVAL;
4658 }
4659
Douglas Gilbert773642d2016-04-25 12:16:28 -04004660 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004661 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004662 return -EINVAL;
4663 }
4664
Douglas Gilbert773642d2016-04-25 12:16:28 -04004665 if (sdebug_physblk_exp > 15) {
4666 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004667 return -EINVAL;
4668 }
4669
Douglas Gilbert773642d2016-04-25 12:16:28 -04004670 if (sdebug_lowest_aligned > 0x3fff) {
4671 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004672 return -EINVAL;
4673 }
4674
Douglas Gilbert773642d2016-04-25 12:16:28 -04004675 if (sdebug_dev_size_mb < 1)
4676 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
4677 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4678 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004679 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680
4681 /* play around with geometry, don't waste too much on track 0 */
4682 sdebug_heads = 8;
4683 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004684 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004686 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02004687 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4689 (sdebug_sectors_per * sdebug_heads);
4690 if (sdebug_cylinders_per >= 1024) {
4691 /* other LLDs do this; implies >= 1GB ram disk ... */
4692 sdebug_heads = 255;
4693 sdebug_sectors_per = 63;
4694 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4695 (sdebug_sectors_per * sdebug_heads);
4696 }
4697
Douglas Gilbert773642d2016-04-25 12:16:28 -04004698 if (0 == sdebug_fake_rw) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004699 fake_storep = vmalloc(sz);
4700 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004701 pr_err("out of memory, 1\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004702 return -ENOMEM;
4703 }
4704 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004705 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004706 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708
Douglas Gilbert773642d2016-04-25 12:16:28 -04004709 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004710 int dif_size;
4711
4712 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4713 dif_storep = vmalloc(dif_size);
4714
Tomas Winklerc12879702015-07-28 16:54:20 +03004715 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004716
4717 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004718 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004719 ret = -ENOMEM;
4720 goto free_vm;
4721 }
4722
4723 memset(dif_storep, 0xff, dif_size);
4724 }
4725
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004726 /* Logical Block Provisioning */
4727 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004728 sdebug_unmap_max_blocks =
4729 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004730
Douglas Gilbert773642d2016-04-25 12:16:28 -04004731 sdebug_unmap_max_desc =
4732 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04004733
Douglas Gilbert773642d2016-04-25 12:16:28 -04004734 sdebug_unmap_granularity =
4735 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004736
Douglas Gilbert773642d2016-04-25 12:16:28 -04004737 if (sdebug_unmap_alignment &&
4738 sdebug_unmap_granularity <=
4739 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004740 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004741 return -EINVAL;
4742 }
4743
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004744 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4745 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04004746
Tomas Winklerc12879702015-07-28 16:54:20 +03004747 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004748
4749 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004750 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004751 ret = -ENOMEM;
4752 goto free_vm;
4753 }
4754
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004755 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004756
4757 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004758 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004759 map_region(0, 2);
4760 }
4761
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004762 pseudo_primary = root_device_register("pseudo_0");
4763 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004764 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004765 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004766 goto free_vm;
4767 }
4768 ret = bus_register(&pseudo_lld_bus);
4769 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004770 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004771 goto dev_unreg;
4772 }
4773 ret = driver_register(&sdebug_driverfs_driver);
4774 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004775 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004776 goto bus_unreg;
4777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778
Douglas Gilbert773642d2016-04-25 12:16:28 -04004779 host_to_add = sdebug_add_host;
4780 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781
4782 for (k = 0; k < host_to_add; k++) {
4783 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004784 pr_err("sdebug_add_adapter failed k=%d\n", k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 break;
4786 }
4787 }
4788
Douglas Gilbert773642d2016-04-25 12:16:28 -04004789 if (sdebug_verbose)
4790 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03004791
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004793
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004794bus_unreg:
4795 bus_unregister(&pseudo_lld_bus);
4796dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004797 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004798free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03004799 vfree(map_storep);
4800 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004801 vfree(fake_storep);
4802
4803 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804}
4805
4806static void __exit scsi_debug_exit(void)
4807{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004808 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809
4810 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004811 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 for (; k; k--)
4813 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 driver_unregister(&sdebug_driverfs_driver);
4815 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004816 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817
Tomas Winklerde232af2015-07-28 16:54:22 +03004818 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 vfree(fake_storep);
4820}
4821
4822device_initcall(scsi_debug_init);
4823module_exit(scsi_debug_exit);
4824
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825static void sdebug_release_adapter(struct device * dev)
4826{
4827 struct sdebug_host_info *sdbg_host;
4828
4829 sdbg_host = to_sdebug_host(dev);
4830 kfree(sdbg_host);
4831}
4832
4833static int sdebug_add_adapter(void)
4834{
4835 int k, devs_per_host;
4836 int error = 0;
4837 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004838 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004840 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 if (NULL == sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004842 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 return -ENOMEM;
4844 }
4845
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4847
Douglas Gilbert773642d2016-04-25 12:16:28 -04004848 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004850 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4851 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004852 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 error = -ENOMEM;
4854 goto clean;
4855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 }
4857
4858 spin_lock(&sdebug_host_list_lock);
4859 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4860 spin_unlock(&sdebug_host_list_lock);
4861
4862 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004863 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004865 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866
4867 error = device_register(&sdbg_host->dev);
4868
4869 if (error)
4870 goto clean;
4871
Douglas Gilbert773642d2016-04-25 12:16:28 -04004872 ++sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 return error;
4874
4875clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004876 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4877 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 list_del(&sdbg_devinfo->dev_list);
4879 kfree(sdbg_devinfo);
4880 }
4881
4882 kfree(sdbg_host);
4883 return error;
4884}
4885
4886static void sdebug_remove_adapter(void)
4887{
4888 struct sdebug_host_info * sdbg_host = NULL;
4889
4890 spin_lock(&sdebug_host_list_lock);
4891 if (!list_empty(&sdebug_host_list)) {
4892 sdbg_host = list_entry(sdebug_host_list.prev,
4893 struct sdebug_host_info, host_list);
4894 list_del(&sdbg_host->host_list);
4895 }
4896 spin_unlock(&sdebug_host_list_lock);
4897
4898 if (!sdbg_host)
4899 return;
4900
Douglas Gilbert773642d2016-04-25 12:16:28 -04004901 device_unregister(&sdbg_host->dev);
4902 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903}
4904
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004905static int
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004906sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004907{
4908 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004909 unsigned long iflags;
4910 struct sdebug_dev_info *devip;
4911
4912 spin_lock_irqsave(&queued_arr_lock, iflags);
4913 devip = (struct sdebug_dev_info *)sdev->hostdata;
4914 if (NULL == devip) {
4915 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4916 return -ENODEV;
4917 }
4918 num_in_q = atomic_read(&devip->num_in_q);
4919 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004920
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004921 if (qdepth < 1)
4922 qdepth = 1;
4923 /* allow to exceed max host queued_arr elements for testing */
4924 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4925 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004926 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004927
Douglas Gilbert773642d2016-04-25 12:16:28 -04004928 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004929 sdev_printk(KERN_INFO, sdev,
4930 "%s: qdepth=%d, num_in_q=%d\n",
4931 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004932 }
4933 return sdev->queue_depth;
4934}
4935
4936static int
Douglas Gilbert817fd662014-11-24 20:18:02 -05004937check_inject(struct scsi_cmnd *scp)
4938{
4939 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4940
4941 memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4942
Douglas Gilbert773642d2016-04-25 12:16:28 -04004943 if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
Douglas Gilbert817fd662014-11-24 20:18:02 -05004944 atomic_set(&sdebug_cmnd_count, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004945 if (sdebug_every_nth < -1)
4946 sdebug_every_nth = -1;
4947 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004948 return 1; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004949 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05004950 scsi_medium_access_command(scp))
4951 return 1; /* time out reads and writes */
4952 if (sdebug_any_injecting_opt) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004953 if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004954 ep->inj_recovered = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004955 if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004956 ep->inj_transport = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004957 if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004958 ep->inj_dif = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004959 if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004960 ep->inj_dix = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004961 if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004962 ep->inj_short = true;
4963 }
4964 }
4965 return 0;
4966}
4967
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004968static int
Douglas Gilbert185dd232016-04-25 12:16:29 -04004969scsi_debug_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004970{
4971 u8 sdeb_i;
4972 struct scsi_device *sdp = scp->device;
4973 const struct opcode_info_t *oip;
4974 const struct opcode_info_t *r_oip;
4975 struct sdebug_dev_info *devip;
4976 u8 *cmd = scp->cmnd;
4977 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
4978 int k, na;
4979 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004980 u32 flags;
4981 u16 sa;
4982 u8 opcode = cmd[0];
4983 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004984
4985 scsi_set_resid(scp, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004986 if (sdebug_verbose && !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004987 char b[120];
4988 int n, len, sb;
4989
4990 len = scp->cmd_len;
4991 sb = (int)sizeof(b);
4992 if (len > 32)
4993 strcpy(b, "too long, over 32 bytes");
4994 else {
4995 for (k = 0, n = 0; k < len && n < sb; ++k)
4996 n += scnprintf(b + n, sb - n, "%02x ",
4997 (u32)cmd[k]);
4998 }
4999 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
5000 }
Tomas Winkler34d55432015-07-28 16:54:21 +03005001 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005002 if ((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)
5003 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005004
5005 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5006 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5007 devip = (struct sdebug_dev_info *)sdp->hostdata;
5008 if (!devip) {
5009 devip = devInfoReg(sdp);
5010 if (NULL == devip)
Douglas Gilbert773642d2016-04-25 12:16:28 -04005011 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16,
5012 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005013 }
5014 na = oip->num_attached;
5015 r_pfp = oip->pfp;
5016 if (na) { /* multiple commands with this opcode */
5017 r_oip = oip;
5018 if (FF_SA & r_oip->flags) {
5019 if (F_SA_LOW & oip->flags)
5020 sa = 0x1f & cmd[1];
5021 else
5022 sa = get_unaligned_be16(cmd + 8);
5023 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5024 if (opcode == oip->opcode && sa == oip->sa)
5025 break;
5026 }
5027 } else { /* since no service action only check opcode */
5028 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5029 if (opcode == oip->opcode)
5030 break;
5031 }
5032 }
5033 if (k > na) {
5034 if (F_SA_LOW & r_oip->flags)
5035 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5036 else if (F_SA_HIGH & r_oip->flags)
5037 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5038 else
5039 mk_sense_invalid_opcode(scp);
5040 goto check_cond;
5041 }
5042 } /* else (when na==0) we assume the oip is a match */
5043 flags = oip->flags;
5044 if (F_INV_OP & flags) {
5045 mk_sense_invalid_opcode(scp);
5046 goto check_cond;
5047 }
5048 if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005049 if (sdebug_verbose)
5050 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5051 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005052 mk_sense_invalid_opcode(scp);
5053 goto check_cond;
5054 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005055 if (sdebug_strict) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005056 u8 rem;
5057 int j;
5058
5059 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5060 rem = ~oip->len_mask[k] & cmd[k];
5061 if (rem) {
5062 for (j = 7; j >= 0; --j, rem <<= 1) {
5063 if (0x80 & rem)
5064 break;
5065 }
5066 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5067 goto check_cond;
5068 }
5069 }
5070 }
5071 if (!(F_SKIP_UA & flags) &&
5072 SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) {
5073 errsts = check_readiness(scp, UAS_ONLY, devip);
5074 if (errsts)
5075 goto check_cond;
5076 }
5077 if ((F_M_ACCESS & flags) && devip->stopped) {
5078 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005079 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005080 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5081 "%s\n", my_name, "initializing command "
5082 "required");
5083 errsts = check_condition_result;
5084 goto fini;
5085 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005086 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005087 goto fini;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005088 if (sdebug_every_nth) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005089 if (check_inject(scp))
5090 return 0; /* ignore command: make trouble */
5091 }
5092 if (oip->pfp) /* if this command has a resp_* function, call it */
5093 errsts = oip->pfp(scp, devip);
5094 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5095 errsts = r_pfp(scp, devip);
5096
5097fini:
5098 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005099 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005100check_cond:
5101 return schedule_resp(scp, devip, check_condition_result, 0);
5102}
5103
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005104static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005105 .show_info = scsi_debug_show_info,
5106 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005107 .proc_name = sdebug_proc_name,
5108 .name = "SCSI DEBUG",
5109 .info = scsi_debug_info,
5110 .slave_alloc = scsi_debug_slave_alloc,
5111 .slave_configure = scsi_debug_slave_configure,
5112 .slave_destroy = scsi_debug_slave_destroy,
5113 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005114 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005115 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005116 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005117 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005118 .eh_target_reset_handler = scsi_debug_target_reset,
5119 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005120 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005121 .can_queue = SCSI_DEBUG_CANQUEUE,
5122 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005123 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005124 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005125 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005126 .use_clustering = DISABLE_CLUSTERING,
5127 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005128 .track_queue_depth = 1,
Douglas Gilbert817fd662014-11-24 20:18:02 -05005129 .cmd_size = sizeof(struct sdebug_scmd_extra_t),
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005130};
5131
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132static int sdebug_driver_probe(struct device * dev)
5133{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005134 int error = 0;
5135 struct sdebug_host_info *sdbg_host;
5136 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005137 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138
5139 sdbg_host = to_sdebug_host(dev);
5140
Douglas Gilbert773642d2016-04-25 12:16:28 -04005141 sdebug_driver_template.can_queue = sdebug_max_queue;
5142 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005143 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005144 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5145 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005146 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005147 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150
5151 sdbg_host->shost = hpnt;
5152 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005153 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5154 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005156 hpnt->max_id = sdebug_num_tgts;
5157 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005158 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005160 host_prot = 0;
5161
Douglas Gilbert773642d2016-04-25 12:16:28 -04005162 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005163
5164 case SD_DIF_TYPE1_PROTECTION:
5165 host_prot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005166 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005167 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
5168 break;
5169
5170 case SD_DIF_TYPE2_PROTECTION:
5171 host_prot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005172 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005173 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
5174 break;
5175
5176 case SD_DIF_TYPE3_PROTECTION:
5177 host_prot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005178 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005179 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
5180 break;
5181
5182 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005183 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005184 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
5185 break;
5186 }
5187
5188 scsi_host_set_prot(hpnt, host_prot);
5189
Tomas Winklerc12879702015-07-28 16:54:20 +03005190 pr_info("host protection%s%s%s%s%s%s%s\n",
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005191 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5192 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5193 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5194 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5195 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5196 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5197 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5198
Douglas Gilbert773642d2016-04-25 12:16:28 -04005199 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005200 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5201 else
5202 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5203
Douglas Gilbert773642d2016-04-25 12:16:28 -04005204 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5205 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206 error = scsi_add_host(hpnt, &sdbg_host->dev);
5207 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005208 pr_err("scsi_add_host failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 error = -ENODEV;
5210 scsi_host_put(hpnt);
5211 } else
5212 scsi_scan_host(hpnt);
5213
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005214 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215}
5216
5217static int sdebug_driver_remove(struct device * dev)
5218{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005220 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221
5222 sdbg_host = to_sdebug_host(dev);
5223
5224 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005225 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 return -ENODEV;
5227 }
5228
5229 scsi_remove_host(sdbg_host->shost);
5230
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005231 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5232 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 list_del(&sdbg_devinfo->dev_list);
5234 kfree(sdbg_devinfo);
5235 }
5236
5237 scsi_host_put(sdbg_host->shost);
5238 return 0;
5239}
5240
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005241static int pseudo_lld_bus_match(struct device *dev,
5242 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005244 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005246
5247static struct bus_type pseudo_lld_bus = {
5248 .name = "pseudo",
5249 .match = pseudo_lld_bus_match,
5250 .probe = sdebug_driver_probe,
5251 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005252 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005253};