blob: 88bfe0fb72ee1103f013c5488fe56b6e8e0a1424 [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>
27#include <linux/timer.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 Gilbertcbf67842014-07-26 11:55:35 -0400107#define DEF_DELAY 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 Gilbertcbf67842014-07-26 11:55:35 -0400139#define DELAY_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
209 * responses are not queued when delay=0 and ndelay=0. The per-device
210 * 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;
521static int sdebug_delay = DEF_DELAY;
522static 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 Gilbert773642d2016-04-25 12:16:28 -0400533static int sdebug_ndelay = DEF_NDELAY;
534static 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
613struct sdebug_hrtimer { /* ... is derived from hrtimer */
614 struct hrtimer hrt; /* must be first element */
615 int qa_indx;
616};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618struct sdebug_queued_cmd {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400619 /* in_use flagged by a bit in queued_in_use_bm[] */
620 struct timer_list *cmnd_timerp;
621 struct tasklet_struct *tletp;
622 struct sdebug_hrtimer *sd_hrtp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 struct scsi_cmnd * a_cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624};
625static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400626static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629static unsigned char * fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900630static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400631static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Martin K. Petersen44d92692009-10-15 14:45:27 -0400633static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400634static int num_aborts;
635static int num_dev_resets;
636static int num_target_resets;
637static int num_bus_resets;
638static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500639static int dix_writes;
640static int dix_reads;
641static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643static DEFINE_SPINLOCK(queued_arr_lock);
644static DEFINE_RWLOCK(atomic_rw);
645
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400646static char sdebug_proc_name[] = MY_NAME;
647static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649static struct bus_type pseudo_lld_bus;
650
651static struct device_driver sdebug_driverfs_driver = {
652 .name = sdebug_proc_name,
653 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654};
655
656static const int check_condition_result =
657 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
658
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500659static const int illegal_condition_result =
660 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
661
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400662static const int device_qfull_result =
663 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
664
665static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
666 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
667 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400668static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
669 0, 0, 0x2, 0x4b};
670static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
671 0, 0, 0x0, 0x0};
672
Akinobu Mita14faa942013-09-18 21:27:24 +0900673static void *fake_store(unsigned long long lba)
674{
675 lba = do_div(lba, sdebug_store_sectors);
676
Douglas Gilbert773642d2016-04-25 12:16:28 -0400677 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900678}
679
680static struct sd_dif_tuple *dif_store(sector_t sector)
681{
Arnd Bergmann49413112015-11-20 17:38:28 +0100682 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900683
684 return dif_storep + sector;
685}
686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687static int sdebug_add_adapter(void);
688static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900690static void sdebug_max_tgts_luns(void)
691{
692 struct sdebug_host_info *sdbg_host;
693 struct Scsi_Host *hpnt;
694
695 spin_lock(&sdebug_host_list_lock);
696 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
697 hpnt = sdbg_host->shost;
698 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400699 (sdebug_num_tgts > hpnt->this_id))
700 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900701 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400702 hpnt->max_id = sdebug_num_tgts;
703 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300704 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900705 }
706 spin_unlock(&sdebug_host_list_lock);
707}
708
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500709enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
710
711/* Set in_bit to -1 to indicate no bit position of invalid field */
712static void
713mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d,
714 int in_byte, int in_bit)
715{
716 unsigned char *sbuff;
717 u8 sks[4];
718 int sl, asc;
719
720 sbuff = scp->sense_buffer;
721 if (!sbuff) {
722 sdev_printk(KERN_ERR, scp->device,
723 "%s: sense_buffer is NULL\n", __func__);
724 return;
725 }
726 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
727 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400728 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500729 memset(sks, 0, sizeof(sks));
730 sks[0] = 0x80;
731 if (c_d)
732 sks[0] |= 0x40;
733 if (in_bit >= 0) {
734 sks[0] |= 0x8;
735 sks[0] |= 0x7 & in_bit;
736 }
737 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400738 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500739 sl = sbuff[7] + 8;
740 sbuff[7] = sl;
741 sbuff[sl] = 0x2;
742 sbuff[sl + 1] = 0x6;
743 memcpy(sbuff + sl + 4, sks, 3);
744 } else
745 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400746 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500747 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
748 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
749 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
750}
751
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400752static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900753{
754 unsigned char *sbuff;
755
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400756 sbuff = scp->sense_buffer;
757 if (!sbuff) {
758 sdev_printk(KERN_ERR, scp->device,
759 "%s: sense_buffer is NULL\n", __func__);
760 return;
761 }
762 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900763
Douglas Gilbert773642d2016-04-25 12:16:28 -0400764 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900765
Douglas Gilbert773642d2016-04-25 12:16:28 -0400766 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400767 sdev_printk(KERN_INFO, scp->device,
768 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
769 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900770}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500772static void
773mk_sense_invalid_opcode(struct scsi_cmnd *scp)
774{
775 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
776}
777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
779{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400780 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400781 if (0x1261 == cmd)
782 sdev_printk(KERN_INFO, dev,
783 "%s: BLKFLSBUF [0x1261]\n", __func__);
784 else if (0x5331 == cmd)
785 sdev_printk(KERN_INFO, dev,
786 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
787 __func__);
788 else
789 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
790 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
792 return -EINVAL;
793 /* return -ENOTTY; // correct return but upsets fdisk */
794}
795
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500796static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
797{
798 struct sdebug_host_info *sdhp;
799 struct sdebug_dev_info *dp;
800
801 spin_lock(&sdebug_host_list_lock);
802 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
803 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
804 if ((devip->sdbg_host == dp->sdbg_host) &&
805 (devip->target == dp->target))
806 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
807 }
808 }
809 spin_unlock(&sdebug_host_list_lock);
810}
811
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400812static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400813 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400815 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400816
817 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
818 if (k != SDEBUG_NUM_UAS) {
819 const char *cp = NULL;
820
821 switch (k) {
822 case SDEBUG_UA_POR:
823 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
824 UA_RESET_ASC, POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400825 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400826 cp = "power on reset";
827 break;
828 case SDEBUG_UA_BUS_RESET:
829 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
830 UA_RESET_ASC, BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400831 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400832 cp = "bus reset";
833 break;
834 case SDEBUG_UA_MODE_CHANGED:
835 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
836 UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400837 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400838 cp = "mode parameters changed";
839 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500840 case SDEBUG_UA_CAPACITY_CHANGED:
841 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
842 UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400843 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500844 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500845 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500846 case SDEBUG_UA_MICROCODE_CHANGED:
847 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
848 TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400849 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500850 cp = "microcode has been changed";
851 break;
852 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
853 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
854 TARGET_CHANGED_ASC,
855 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400856 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500857 cp = "microcode has been changed without reset";
858 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500859 case SDEBUG_UA_LUNS_CHANGED:
860 /*
861 * SPC-3 behavior is to report a UNIT ATTENTION with
862 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
863 * on the target, until a REPORT LUNS command is
864 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400865 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500866 * values as struct scsi_device->scsi_level.
867 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400868 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500869 clear_luns_changed_on_target(devip);
870 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
871 TARGET_CHANGED_ASC,
872 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400873 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500874 cp = "reported luns data has changed";
875 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400876 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400877 pr_warn("unexpected unit attention code=%d\n", k);
878 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400879 cp = "unknown";
880 break;
881 }
882 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400883 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400884 sdev_printk(KERN_INFO, SCpnt->device,
885 "%s reports: Unit attention: %s\n",
886 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 return check_condition_result;
888 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400889 if ((UAS_TUR == uas_only) && devip->stopped) {
890 mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400891 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400892 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400893 sdev_printk(KERN_INFO, SCpnt->device,
894 "%s reports: Not ready: %s\n", my_name,
895 "initializing command required");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400896 return check_condition_result;
897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 return 0;
899}
900
901/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900902static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 int arr_len)
904{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900905 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900906 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900908 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900910 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400911 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900912
913 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
914 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700915 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 return 0;
918}
919
920/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900921static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
922 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900924 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900926 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900928
929 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930}
931
932
933static const char * inq_vendor_id = "Linux ";
934static const char * inq_product_id = "scsi_debug ";
Douglas Gilbert773642d2016-04-25 12:16:28 -0400935static const char *inq_product_rev = "0186"; /* version less '.' */
936static const u64 naa5_comp_a = 0x5222222000000000ULL;
937static const u64 naa5_comp_b = 0x5333333000000000ULL;
938static const u64 naa5_comp_c = 0x5111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400940/* Device identification VPD page. Returns number of bytes placed in arr */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200941static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
942 int target_dev_id, int dev_id_num,
943 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400944 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400946 int num, port_a;
947 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400949 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 /* T10 vendor identifier field format (faked) */
951 arr[0] = 0x2; /* ASCII */
952 arr[1] = 0x1;
953 arr[2] = 0x0;
954 memcpy(&arr[4], inq_vendor_id, 8);
955 memcpy(&arr[12], inq_product_id, 16);
956 memcpy(&arr[28], dev_id_str, dev_id_str_len);
957 num = 8 + 16 + dev_id_str_len;
958 arr[3] = num;
959 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400960 if (dev_id_num >= 0) {
961 /* NAA-5, Logical unit identifier (binary) */
962 arr[num++] = 0x1; /* binary (not necessarily sas) */
963 arr[num++] = 0x3; /* PIV=0, lu, naa */
964 arr[num++] = 0x0;
965 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400966 put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
967 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400968 /* Target relative port number */
969 arr[num++] = 0x61; /* proto=sas, binary */
970 arr[num++] = 0x94; /* PIV=1, target port, rel port */
971 arr[num++] = 0x0; /* reserved */
972 arr[num++] = 0x4; /* length */
973 arr[num++] = 0x0; /* reserved */
974 arr[num++] = 0x0; /* reserved */
975 arr[num++] = 0x0;
976 arr[num++] = 0x1; /* relative port A */
977 }
978 /* NAA-5, Target port identifier */
979 arr[num++] = 0x61; /* proto=sas, binary */
980 arr[num++] = 0x93; /* piv=1, target port, naa */
981 arr[num++] = 0x0;
982 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400983 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
984 num += 8;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200985 /* NAA-5, Target port group identifier */
986 arr[num++] = 0x61; /* proto=sas, binary */
987 arr[num++] = 0x95; /* piv=1, target port group id */
988 arr[num++] = 0x0;
989 arr[num++] = 0x4;
990 arr[num++] = 0;
991 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400992 put_unaligned_be16(port_group_id, arr + num);
993 num += 2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400994 /* NAA-5, Target device identifier */
995 arr[num++] = 0x61; /* proto=sas, binary */
996 arr[num++] = 0xa3; /* piv=1, target device, naa */
997 arr[num++] = 0x0;
998 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400999 put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
1000 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001001 /* SCSI name string: Target device identifier */
1002 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1003 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1004 arr[num++] = 0x0;
1005 arr[num++] = 24;
1006 memcpy(arr + num, "naa.52222220", 12);
1007 num += 12;
1008 snprintf(b, sizeof(b), "%08X", target_dev_id);
1009 memcpy(arr + num, b, 8);
1010 num += 8;
1011 memset(arr + num, 0, 4);
1012 num += 4;
1013 return num;
1014}
1015
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001016static unsigned char vpd84_data[] = {
1017/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1018 0x22,0x22,0x22,0x0,0xbb,0x1,
1019 0x22,0x22,0x22,0x0,0xbb,0x2,
1020};
1021
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001022/* Software interface identification VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001023static int inquiry_evpd_84(unsigned char * arr)
1024{
1025 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1026 return sizeof(vpd84_data);
1027}
1028
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001029/* Management network addresses VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001030static int inquiry_evpd_85(unsigned char * arr)
1031{
1032 int num = 0;
1033 const char * na1 = "https://www.kernel.org/config";
1034 const char * na2 = "http://www.kernel.org/log";
1035 int plen, olen;
1036
1037 arr[num++] = 0x1; /* lu, storage config */
1038 arr[num++] = 0x0; /* reserved */
1039 arr[num++] = 0x0;
1040 olen = strlen(na1);
1041 plen = olen + 1;
1042 if (plen % 4)
1043 plen = ((plen / 4) + 1) * 4;
1044 arr[num++] = plen; /* length, null termianted, padded */
1045 memcpy(arr + num, na1, olen);
1046 memset(arr + num + olen, 0, plen - olen);
1047 num += plen;
1048
1049 arr[num++] = 0x4; /* lu, logging */
1050 arr[num++] = 0x0; /* reserved */
1051 arr[num++] = 0x0;
1052 olen = strlen(na2);
1053 plen = olen + 1;
1054 if (plen % 4)
1055 plen = ((plen / 4) + 1) * 4;
1056 arr[num++] = plen; /* length, null terminated, padded */
1057 memcpy(arr + num, na2, olen);
1058 memset(arr + num + olen, 0, plen - olen);
1059 num += plen;
1060
1061 return num;
1062}
1063
1064/* SCSI ports VPD page */
1065static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1066{
1067 int num = 0;
1068 int port_a, port_b;
1069
1070 port_a = target_dev_id + 1;
1071 port_b = port_a + 1;
1072 arr[num++] = 0x0; /* reserved */
1073 arr[num++] = 0x0; /* reserved */
1074 arr[num++] = 0x0;
1075 arr[num++] = 0x1; /* relative port 1 (primary) */
1076 memset(arr + num, 0, 6);
1077 num += 6;
1078 arr[num++] = 0x0;
1079 arr[num++] = 12; /* length tp descriptor */
1080 /* naa-5 target port identifier (A) */
1081 arr[num++] = 0x61; /* proto=sas, binary */
1082 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1083 arr[num++] = 0x0; /* reserved */
1084 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001085 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1086 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001087 arr[num++] = 0x0; /* reserved */
1088 arr[num++] = 0x0; /* reserved */
1089 arr[num++] = 0x0;
1090 arr[num++] = 0x2; /* relative port 2 (secondary) */
1091 memset(arr + num, 0, 6);
1092 num += 6;
1093 arr[num++] = 0x0;
1094 arr[num++] = 12; /* length tp descriptor */
1095 /* naa-5 target port identifier (B) */
1096 arr[num++] = 0x61; /* proto=sas, binary */
1097 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1098 arr[num++] = 0x0; /* reserved */
1099 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001100 put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1101 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001102
1103 return num;
1104}
1105
1106
1107static unsigned char vpd89_data[] = {
1108/* from 4th byte */ 0,0,0,0,
1109'l','i','n','u','x',' ',' ',' ',
1110'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1111'1','2','3','4',
11120x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
11130xec,0,0,0,
11140x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
11150,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
11160x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
11170x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
11180x53,0x41,
11190x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11200x20,0x20,
11210x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11220x10,0x80,
11230,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
11240x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
11250x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
11260,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
11270x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
11280x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
11290,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,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,
11320,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11330x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
11340,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
11350xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
11360,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
11480,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1149};
1150
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001151/* ATA Information VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001152static int inquiry_evpd_89(unsigned char * arr)
1153{
1154 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1155 return sizeof(vpd89_data);
1156}
1157
1158
1159static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001160 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
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,
1163 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001164};
1165
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001166/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001167static int inquiry_evpd_b0(unsigned char * arr)
1168{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001169 unsigned int gran;
1170
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001171 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001172
1173 /* Optimal transfer length granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001174 gran = 1 << sdebug_physblk_exp;
1175 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001176
1177 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001178 if (sdebug_store_sectors > 0x400)
1179 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001180
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001181 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001182 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001183
Douglas Gilbert773642d2016-04-25 12:16:28 -04001184 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001185 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001186 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001187
1188 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001189 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001190 }
1191
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001192 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001193 if (sdebug_unmap_alignment) {
1194 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001195 arr[28] |= 0x80; /* UGAVALID */
1196 }
1197
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001198 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001199 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001200
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001201 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001202 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001203
1204 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001205
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001206 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207}
1208
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001209/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001210static int inquiry_evpd_b1(unsigned char *arr)
1211{
1212 memset(arr, 0, 0x3c);
1213 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001214 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1215 arr[2] = 0;
1216 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001217
1218 return 0x3c;
1219}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001221/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001222static int inquiry_evpd_b2(unsigned char *arr)
1223{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001224 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001225 arr[0] = 0; /* threshold exponent */
1226
Douglas Gilbert773642d2016-04-25 12:16:28 -04001227 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001228 arr[1] = 1 << 7;
1229
Douglas Gilbert773642d2016-04-25 12:16:28 -04001230 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001231 arr[1] |= 1 << 6;
1232
Douglas Gilbert773642d2016-04-25 12:16:28 -04001233 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001234 arr[1] |= 1 << 5;
1235
Douglas Gilbert773642d2016-04-25 12:16:28 -04001236 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001237 arr[1] |= 1 << 2;
1238
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001239 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001240}
1241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001243#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001245static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246{
1247 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001248 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001249 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001250 int alloc_len, n, ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001251 bool have_wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
Douglas Gilbert773642d2016-04-25 12:16:28 -04001253 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001254 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1255 if (! arr)
1256 return DID_REQUEUE << 16;
Tomas Winkler34d55432015-07-28 16:54:21 +03001257 have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001258 if (have_wlun)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001259 pq_pdt = 0x1e; /* present, wlun */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001260 else if (sdebug_no_lun_0 && (0 == devip->lun))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001261 pq_pdt = 0x7f; /* not present, no device type */
1262 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001263 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 arr[0] = pq_pdt;
1265 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001266 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001267 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return check_condition_result;
1269 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001270 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001271 char lu_id_str[6];
1272 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001274 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1275 (devip->channel & 0x7f);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001276 if (0 == sdebug_vpd_use_hostno)
Douglas Gilbert23183912006-09-16 20:30:47 -04001277 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001278 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001279 (devip->target * 1000) + devip->lun);
1280 target_dev_id = ((host_no + 1) * 2000) +
1281 (devip->target * 1000) - 3;
1282 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001284 arr[1] = cmd[2]; /*sanity */
1285 n = 4;
1286 arr[n++] = 0x0; /* this page */
1287 arr[n++] = 0x80; /* unit serial number */
1288 arr[n++] = 0x83; /* device identification */
1289 arr[n++] = 0x84; /* software interface ident. */
1290 arr[n++] = 0x85; /* management network addresses */
1291 arr[n++] = 0x86; /* extended inquiry */
1292 arr[n++] = 0x87; /* mode page policy */
1293 arr[n++] = 0x88; /* SCSI ports */
1294 arr[n++] = 0x89; /* ATA information */
1295 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001296 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001297 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
1298 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001299 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001301 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001303 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001305 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001306 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1307 target_dev_id, lu_id_num,
1308 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001309 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1310 arr[1] = cmd[2]; /*sanity */
1311 arr[3] = inquiry_evpd_84(&arr[4]);
1312 } else if (0x85 == cmd[2]) { /* Management network addresses */
1313 arr[1] = cmd[2]; /*sanity */
1314 arr[3] = inquiry_evpd_85(&arr[4]);
1315 } else if (0x86 == cmd[2]) { /* extended inquiry */
1316 arr[1] = cmd[2]; /*sanity */
1317 arr[3] = 0x3c; /* number of following entries */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001318 if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001319 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001320 else if (sdebug_dif)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001321 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1322 else
1323 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001324 arr[5] = 0x7; /* head of q, ordered + simple q's */
1325 } else if (0x87 == cmd[2]) { /* mode page policy */
1326 arr[1] = cmd[2]; /*sanity */
1327 arr[3] = 0x8; /* number of following entries */
1328 arr[4] = 0x2; /* disconnect-reconnect mp */
1329 arr[6] = 0x80; /* mlus, shared */
1330 arr[8] = 0x18; /* protocol specific lu */
1331 arr[10] = 0x82; /* mlus, per initiator port */
1332 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1333 arr[1] = cmd[2]; /*sanity */
1334 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1335 } else if (0x89 == cmd[2]) { /* ATA information */
1336 arr[1] = cmd[2]; /*sanity */
1337 n = inquiry_evpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001338 put_unaligned_be16(n, arr + 2);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001339 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1340 arr[1] = cmd[2]; /*sanity */
1341 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001342 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1343 arr[1] = cmd[2]; /*sanity */
1344 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001345 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001346 arr[1] = cmd[2]; /*sanity */
1347 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001349 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001350 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 return check_condition_result;
1352 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001353 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001354 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001355 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001356 kfree(arr);
1357 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 }
1359 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001360 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1361 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 arr[3] = 2; /* response_data_format==2 */
1363 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001364 arr[5] = sdebug_dif ? 1 : 0; /* PROTECT bit */
1365 if (0 == sdebug_vpd_use_hostno)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001366 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001367 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001369 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 memcpy(&arr[8], inq_vendor_id, 8);
1371 memcpy(&arr[16], inq_product_id, 16);
1372 memcpy(&arr[32], inq_product_rev, 4);
1373 /* version descriptors (2 bytes each) follow */
Douglas Gilberte46b0342014-08-05 12:21:53 +02001374 arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */
1375 arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001376 n = 62;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001377 if (sdebug_ptype == 0) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001378 arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001379 } else if (sdebug_ptype == 1) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001380 arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 }
Douglas Gilberte46b0342014-08-05 12:21:53 +02001382 arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001383 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001385 kfree(arr);
1386 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387}
1388
1389static int resp_requests(struct scsi_cmnd * scp,
1390 struct sdebug_dev_info * devip)
1391{
1392 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001393 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001394 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001395 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 int len = 18;
1397
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001398 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001399 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001400 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001401 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001402 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001403 arr[0] = 0x72;
1404 arr[1] = 0x0; /* NO_SENSE in sense_key */
1405 arr[2] = THRESHOLD_EXCEEDED;
1406 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001407 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001408 } else {
1409 arr[0] = 0x70;
1410 arr[2] = 0x0; /* NO_SENSE in sense_key */
1411 arr[7] = 0xa; /* 18 byte sense buffer */
1412 arr[12] = THRESHOLD_EXCEEDED;
1413 arr[13] = 0xff; /* TEST set and MRIE==6 */
1414 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001415 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001416 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001417 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001418 ; /* have sense and formats match */
1419 else if (arr[0] <= 0x70) {
1420 if (dsense) {
1421 memset(arr, 0, 8);
1422 arr[0] = 0x72;
1423 len = 8;
1424 } else {
1425 memset(arr, 0, 18);
1426 arr[0] = 0x70;
1427 arr[7] = 0xa;
1428 }
1429 } else if (dsense) {
1430 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001431 arr[0] = 0x72;
1432 arr[1] = sbuff[2]; /* sense key */
1433 arr[2] = sbuff[12]; /* asc */
1434 arr[3] = sbuff[13]; /* ascq */
1435 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001436 } else {
1437 memset(arr, 0, 18);
1438 arr[0] = 0x70;
1439 arr[2] = sbuff[1];
1440 arr[7] = 0xa;
1441 arr[12] = sbuff[1];
1442 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001443 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001444
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001445 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001446 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 return fill_from_dev_buffer(scp, arr, len);
1448}
1449
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001450static int resp_start_stop(struct scsi_cmnd * scp,
1451 struct sdebug_dev_info * devip)
1452{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001453 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001454 int power_cond, start;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001455
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001456 power_cond = (cmd[4] & 0xf0) >> 4;
1457 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001458 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001459 return check_condition_result;
1460 }
1461 start = cmd[4] & 1;
1462 if (start == devip->stopped)
1463 devip->stopped = !start;
1464 return 0;
1465}
1466
FUJITA Tomonori28898872008-03-30 00:59:55 +09001467static sector_t get_sdebug_capacity(void)
1468{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001469 static const unsigned int gibibyte = 1073741824;
1470
1471 if (sdebug_virtual_gb > 0)
1472 return (sector_t)sdebug_virtual_gb *
1473 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001474 else
1475 return sdebug_store_sectors;
1476}
1477
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478#define SDEBUG_READCAP_ARR_SZ 8
1479static int resp_readcap(struct scsi_cmnd * scp,
1480 struct sdebug_dev_info * devip)
1481{
1482 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001483 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001485 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001486 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001488 if (sdebug_capacity < 0xffffffff) {
1489 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001490 put_unaligned_be32(capac, arr + 0);
1491 } else
1492 put_unaligned_be32(0xffffffff, arr + 0);
1493 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1495}
1496
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001497#define SDEBUG_READCAP16_ARR_SZ 32
1498static int resp_readcap16(struct scsi_cmnd * scp,
1499 struct sdebug_dev_info * devip)
1500{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001501 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001502 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001503 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001504
Douglas Gilbert773642d2016-04-25 12:16:28 -04001505 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001506 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001507 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001508 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001509 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1510 put_unaligned_be32(sdebug_sector_size, arr + 8);
1511 arr[13] = sdebug_physblk_exp & 0xf;
1512 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001513
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001514 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001515 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001516 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001517 arr[14] |= 0x40; /* LBPRZ */
1518 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001519
Douglas Gilbert773642d2016-04-25 12:16:28 -04001520 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001521
Douglas Gilbert773642d2016-04-25 12:16:28 -04001522 if (sdebug_dif) {
1523 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001524 arr[12] |= 1; /* PROT_EN */
1525 }
1526
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001527 return fill_from_dev_buffer(scp, arr,
1528 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1529}
1530
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001531#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1532
1533static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1534 struct sdebug_dev_info * devip)
1535{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001536 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001537 unsigned char * arr;
1538 int host_no = devip->sdbg_host->shost->host_no;
1539 int n, ret, alen, rlen;
1540 int port_group_a, port_group_b, port_a, port_b;
1541
Douglas Gilbert773642d2016-04-25 12:16:28 -04001542 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001543 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1544 if (! arr)
1545 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001546 /*
1547 * EVPD page 0x88 states we have two ports, one
1548 * real and a fake port with no device connected.
1549 * So we create two port groups with one port each
1550 * and set the group with port B to unavailable.
1551 */
1552 port_a = 0x1; /* relative port A */
1553 port_b = 0x2; /* relative port B */
1554 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001555 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001556 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001557 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001558
1559 /*
1560 * The asymmetric access state is cycled according to the host_id.
1561 */
1562 n = 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001563 if (0 == sdebug_vpd_use_hostno) {
1564 arr[n++] = host_no % 3; /* Asymm access state */
1565 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001566 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001567 arr[n++] = 0x0; /* Active/Optimized path */
1568 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001569 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001570 put_unaligned_be16(port_group_a, arr + n);
1571 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001572 arr[n++] = 0; /* Reserved */
1573 arr[n++] = 0; /* Status code */
1574 arr[n++] = 0; /* Vendor unique */
1575 arr[n++] = 0x1; /* One port per group */
1576 arr[n++] = 0; /* Reserved */
1577 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001578 put_unaligned_be16(port_a, arr + n);
1579 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001580 arr[n++] = 3; /* Port unavailable */
1581 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001582 put_unaligned_be16(port_group_b, arr + n);
1583 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001584 arr[n++] = 0; /* Reserved */
1585 arr[n++] = 0; /* Status code */
1586 arr[n++] = 0; /* Vendor unique */
1587 arr[n++] = 0x1; /* One port per group */
1588 arr[n++] = 0; /* Reserved */
1589 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001590 put_unaligned_be16(port_b, arr + n);
1591 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001592
1593 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001594 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001595
1596 /*
1597 * Return the smallest value of either
1598 * - The allocated length
1599 * - The constructed command length
1600 * - The maximum array size
1601 */
1602 rlen = min(alen,n);
1603 ret = fill_from_dev_buffer(scp, arr,
1604 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1605 kfree(arr);
1606 return ret;
1607}
1608
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001609static int
1610resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1611{
1612 bool rctd;
1613 u8 reporting_opts, req_opcode, sdeb_i, supp;
1614 u16 req_sa, u;
1615 u32 alloc_len, a_len;
1616 int k, offset, len, errsts, count, bump, na;
1617 const struct opcode_info_t *oip;
1618 const struct opcode_info_t *r_oip;
1619 u8 *arr;
1620 u8 *cmd = scp->cmnd;
1621
1622 rctd = !!(cmd[2] & 0x80);
1623 reporting_opts = cmd[2] & 0x7;
1624 req_opcode = cmd[3];
1625 req_sa = get_unaligned_be16(cmd + 4);
1626 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001627 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001628 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1629 return check_condition_result;
1630 }
1631 if (alloc_len > 8192)
1632 a_len = 8192;
1633 else
1634 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001635 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001636 if (NULL == arr) {
1637 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1638 INSUFF_RES_ASCQ);
1639 return check_condition_result;
1640 }
1641 switch (reporting_opts) {
1642 case 0: /* all commands */
1643 /* count number of commands */
1644 for (count = 0, oip = opcode_info_arr;
1645 oip->num_attached != 0xff; ++oip) {
1646 if (F_INV_OP & oip->flags)
1647 continue;
1648 count += (oip->num_attached + 1);
1649 }
1650 bump = rctd ? 20 : 8;
1651 put_unaligned_be32(count * bump, arr);
1652 for (offset = 4, oip = opcode_info_arr;
1653 oip->num_attached != 0xff && offset < a_len; ++oip) {
1654 if (F_INV_OP & oip->flags)
1655 continue;
1656 na = oip->num_attached;
1657 arr[offset] = oip->opcode;
1658 put_unaligned_be16(oip->sa, arr + offset + 2);
1659 if (rctd)
1660 arr[offset + 5] |= 0x2;
1661 if (FF_SA & oip->flags)
1662 arr[offset + 5] |= 0x1;
1663 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1664 if (rctd)
1665 put_unaligned_be16(0xa, arr + offset + 8);
1666 r_oip = oip;
1667 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1668 if (F_INV_OP & oip->flags)
1669 continue;
1670 offset += bump;
1671 arr[offset] = oip->opcode;
1672 put_unaligned_be16(oip->sa, arr + offset + 2);
1673 if (rctd)
1674 arr[offset + 5] |= 0x2;
1675 if (FF_SA & oip->flags)
1676 arr[offset + 5] |= 0x1;
1677 put_unaligned_be16(oip->len_mask[0],
1678 arr + offset + 6);
1679 if (rctd)
1680 put_unaligned_be16(0xa,
1681 arr + offset + 8);
1682 }
1683 oip = r_oip;
1684 offset += bump;
1685 }
1686 break;
1687 case 1: /* one command: opcode only */
1688 case 2: /* one command: opcode plus service action */
1689 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1690 sdeb_i = opcode_ind_arr[req_opcode];
1691 oip = &opcode_info_arr[sdeb_i];
1692 if (F_INV_OP & oip->flags) {
1693 supp = 1;
1694 offset = 4;
1695 } else {
1696 if (1 == reporting_opts) {
1697 if (FF_SA & oip->flags) {
1698 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1699 2, 2);
1700 kfree(arr);
1701 return check_condition_result;
1702 }
1703 req_sa = 0;
1704 } else if (2 == reporting_opts &&
1705 0 == (FF_SA & oip->flags)) {
1706 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1707 kfree(arr); /* point at requested sa */
1708 return check_condition_result;
1709 }
1710 if (0 == (FF_SA & oip->flags) &&
1711 req_opcode == oip->opcode)
1712 supp = 3;
1713 else if (0 == (FF_SA & oip->flags)) {
1714 na = oip->num_attached;
1715 for (k = 0, oip = oip->arrp; k < na;
1716 ++k, ++oip) {
1717 if (req_opcode == oip->opcode)
1718 break;
1719 }
1720 supp = (k >= na) ? 1 : 3;
1721 } else if (req_sa != oip->sa) {
1722 na = oip->num_attached;
1723 for (k = 0, oip = oip->arrp; k < na;
1724 ++k, ++oip) {
1725 if (req_sa == oip->sa)
1726 break;
1727 }
1728 supp = (k >= na) ? 1 : 3;
1729 } else
1730 supp = 3;
1731 if (3 == supp) {
1732 u = oip->len_mask[0];
1733 put_unaligned_be16(u, arr + 2);
1734 arr[4] = oip->opcode;
1735 for (k = 1; k < u; ++k)
1736 arr[4 + k] = (k < 16) ?
1737 oip->len_mask[k] : 0xff;
1738 offset = 4 + u;
1739 } else
1740 offset = 4;
1741 }
1742 arr[1] = (rctd ? 0x80 : 0) | supp;
1743 if (rctd) {
1744 put_unaligned_be16(0xa, arr + offset);
1745 offset += 12;
1746 }
1747 break;
1748 default:
1749 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1750 kfree(arr);
1751 return check_condition_result;
1752 }
1753 offset = (offset < a_len) ? offset : a_len;
1754 len = (offset < alloc_len) ? offset : alloc_len;
1755 errsts = fill_from_dev_buffer(scp, arr, len);
1756 kfree(arr);
1757 return errsts;
1758}
1759
1760static int
1761resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1762{
1763 bool repd;
1764 u32 alloc_len, len;
1765 u8 arr[16];
1766 u8 *cmd = scp->cmnd;
1767
1768 memset(arr, 0, sizeof(arr));
1769 repd = !!(cmd[2] & 0x80);
1770 alloc_len = get_unaligned_be32(cmd + 6);
1771 if (alloc_len < 4) {
1772 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1773 return check_condition_result;
1774 }
1775 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1776 arr[1] = 0x1; /* ITNRS */
1777 if (repd) {
1778 arr[3] = 0xc;
1779 len = 16;
1780 } else
1781 len = 4;
1782
1783 len = (len < alloc_len) ? len : alloc_len;
1784 return fill_from_dev_buffer(scp, arr, len);
1785}
1786
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787/* <<Following mode page info copied from ST318451LW>> */
1788
1789static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1790{ /* Read-Write Error Recovery page for mode_sense */
1791 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1792 5, 0, 0xff, 0xff};
1793
1794 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1795 if (1 == pcontrol)
1796 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1797 return sizeof(err_recov_pg);
1798}
1799
1800static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1801{ /* Disconnect-Reconnect page for mode_sense */
1802 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1803 0, 0, 0, 0, 0, 0, 0, 0};
1804
1805 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1806 if (1 == pcontrol)
1807 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1808 return sizeof(disconnect_pg);
1809}
1810
1811static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1812{ /* Format device page for mode_sense */
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001813 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1814 0, 0, 0, 0, 0, 0, 0, 0,
1815 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001817 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001818 put_unaligned_be16(sdebug_sectors_per, p + 10);
1819 put_unaligned_be16(sdebug_sector_size, p + 12);
1820 if (sdebug_removable)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001821 p[20] |= 0x20; /* should agree with INQUIRY */
1822 if (1 == pcontrol)
1823 memset(p + 2, 0, sizeof(format_pg) - 2);
1824 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825}
1826
1827static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1828{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001829 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1830 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1831 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1833
Douglas Gilbert773642d2016-04-25 12:16:28 -04001834 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001835 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 memcpy(p, caching_pg, sizeof(caching_pg));
1837 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001838 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1839 else if (2 == pcontrol)
1840 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 return sizeof(caching_pg);
1842}
1843
1844static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1845{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001846 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1847 0, 0, 0, 0};
1848 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 0, 0, 0x2, 0x4b};
1850
Douglas Gilbert773642d2016-04-25 12:16:28 -04001851 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001853 else
1854 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001855
Douglas Gilbert773642d2016-04-25 12:16:28 -04001856 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001857 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1860 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001861 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1862 else if (2 == pcontrol)
1863 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 return sizeof(ctrl_m_pg);
1865}
1866
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001867
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1869{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001870 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1871 0, 0, 0x0, 0x0};
1872 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1873 0, 0, 0x0, 0x0};
1874
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1876 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001877 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1878 else if (2 == pcontrol)
1879 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 return sizeof(iec_m_pg);
1881}
1882
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001883static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1884{ /* SAS SSP mode page - short format for mode_sense */
1885 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1886 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1887
1888 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1889 if (1 == pcontrol)
1890 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1891 return sizeof(sas_sf_m_pg);
1892}
1893
1894
1895static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1896 int target_dev_id)
1897{ /* SAS phy control and discover mode page for mode_sense */
1898 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1899 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001900 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1901 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001902 0x2, 0, 0, 0, 0, 0, 0, 0,
1903 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1904 0, 0, 0, 0, 0, 0, 0, 0,
1905 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001906 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1907 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001908 0x3, 0, 0, 0, 0, 0, 0, 0,
1909 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1910 0, 0, 0, 0, 0, 0, 0, 0,
1911 };
1912 int port_a, port_b;
1913
Douglas Gilbert773642d2016-04-25 12:16:28 -04001914 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1915 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1916 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1917 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001918 port_a = target_dev_id + 1;
1919 port_b = port_a + 1;
1920 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001921 put_unaligned_be32(port_a, p + 20);
1922 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001923 if (1 == pcontrol)
1924 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1925 return sizeof(sas_pcd_m_pg);
1926}
1927
1928static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1929{ /* SAS SSP shared protocol specific port mode subpage */
1930 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1931 0, 0, 0, 0, 0, 0, 0, 0,
1932 };
1933
1934 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1935 if (1 == pcontrol)
1936 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1937 return sizeof(sas_sha_m_pg);
1938}
1939
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940#define SDEBUG_MAX_MSENSE_SZ 256
1941
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001942static int
1943resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944{
Douglas Gilbert23183912006-09-16 20:30:47 -04001945 unsigned char dbd, llbaa;
1946 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 unsigned char dev_spec;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001948 int alloc_len, msense_6, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001949 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 unsigned char * ap;
1951 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001952 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953
Douglas Gilbert23183912006-09-16 20:30:47 -04001954 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 pcontrol = (cmd[2] & 0xc0) >> 6;
1956 pcode = cmd[2] & 0x3f;
1957 subpcode = cmd[3];
1958 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001959 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001960 if ((0 == sdebug_ptype) && (0 == dbd))
Douglas Gilbert23183912006-09-16 20:30:47 -04001961 bd_len = llbaa ? 16 : 8;
1962 else
1963 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001964 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1966 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001967 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 return check_condition_result;
1969 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001970 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1971 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001972 /* set DPOFUA bit for disks */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001973 if (0 == sdebug_ptype)
Douglas Gilbert23183912006-09-16 20:30:47 -04001974 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1975 else
1976 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 if (msense_6) {
1978 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001979 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 offset = 4;
1981 } else {
1982 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001983 if (16 == bd_len)
1984 arr[4] = 0x1; /* set LONGLBA bit */
1985 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 offset = 8;
1987 }
1988 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001989 if ((bd_len > 0) && (!sdebug_capacity))
1990 sdebug_capacity = get_sdebug_capacity();
1991
Douglas Gilbert23183912006-09-16 20:30:47 -04001992 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001993 if (sdebug_capacity > 0xfffffffe)
1994 put_unaligned_be32(0xffffffff, ap + 0);
1995 else
1996 put_unaligned_be32(sdebug_capacity, ap + 0);
1997 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04001998 offset += bd_len;
1999 ap = arr + offset;
2000 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002001 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2002 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002003 offset += bd_len;
2004 ap = arr + offset;
2005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002007 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2008 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002009 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 return check_condition_result;
2011 }
2012 switch (pcode) {
2013 case 0x1: /* Read-Write error recovery page, direct access */
2014 len = resp_err_recov_pg(ap, pcontrol, target);
2015 offset += len;
2016 break;
2017 case 0x2: /* Disconnect-Reconnect page, all devices */
2018 len = resp_disconnect_pg(ap, pcontrol, target);
2019 offset += len;
2020 break;
2021 case 0x3: /* Format device page, direct access */
2022 len = resp_format_pg(ap, pcontrol, target);
2023 offset += len;
2024 break;
2025 case 0x8: /* Caching page, direct access */
2026 len = resp_caching_pg(ap, pcontrol, target);
2027 offset += len;
2028 break;
2029 case 0xa: /* Control Mode page, all devices */
2030 len = resp_ctrl_m_pg(ap, pcontrol, target);
2031 offset += len;
2032 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002033 case 0x19: /* if spc==1 then sas phy, control+discover */
2034 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002035 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002036 return check_condition_result;
2037 }
2038 len = 0;
2039 if ((0x0 == subpcode) || (0xff == subpcode))
2040 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2041 if ((0x1 == subpcode) || (0xff == subpcode))
2042 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2043 target_dev_id);
2044 if ((0x2 == subpcode) || (0xff == subpcode))
2045 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2046 offset += len;
2047 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 case 0x1c: /* Informational Exceptions Mode page, all devices */
2049 len = resp_iec_m_pg(ap, pcontrol, target);
2050 offset += len;
2051 break;
2052 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002053 if ((0 == subpcode) || (0xff == subpcode)) {
2054 len = resp_err_recov_pg(ap, pcontrol, target);
2055 len += resp_disconnect_pg(ap + len, pcontrol, target);
2056 len += resp_format_pg(ap + len, pcontrol, target);
2057 len += resp_caching_pg(ap + len, pcontrol, target);
2058 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2059 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2060 if (0xff == subpcode) {
2061 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2062 target, target_dev_id);
2063 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2064 }
2065 len += resp_iec_m_pg(ap + len, pcontrol, target);
2066 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002067 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002068 return check_condition_result;
2069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 offset += len;
2071 break;
2072 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002073 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 return check_condition_result;
2075 }
2076 if (msense_6)
2077 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002078 else
2079 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2081}
2082
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002083#define SDEBUG_MAX_MSELECT_SZ 512
2084
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002085static int
2086resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002087{
2088 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002089 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002090 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002091 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002092 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002093
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002094 memset(arr, 0, sizeof(arr));
2095 pf = cmd[1] & 0x10;
2096 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002097 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002098 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002099 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002100 return check_condition_result;
2101 }
2102 res = fetch_to_dev_buffer(scp, arr, param_len);
2103 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002104 return DID_ERROR << 16;
2105 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002106 sdev_printk(KERN_INFO, scp->device,
2107 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2108 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002109 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2110 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002111 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002112 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002113 return check_condition_result;
2114 }
2115 off = bd_len + (mselect6 ? 4 : 8);
2116 mpage = arr[off] & 0x3f;
2117 ps = !!(arr[off] & 0x80);
2118 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002119 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002120 return check_condition_result;
2121 }
2122 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002123 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002124 (arr[off + 1] + 2);
2125 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002126 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002127 PARAMETER_LIST_LENGTH_ERR, 0);
2128 return check_condition_result;
2129 }
2130 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002131 case 0x8: /* Caching Mode page */
2132 if (caching_pg[1] == arr[off + 1]) {
2133 memcpy(caching_pg + 2, arr + off + 2,
2134 sizeof(caching_pg) - 2);
2135 goto set_mode_changed_ua;
2136 }
2137 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002138 case 0xa: /* Control Mode page */
2139 if (ctrl_m_pg[1] == arr[off + 1]) {
2140 memcpy(ctrl_m_pg + 2, arr + off + 2,
2141 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002142 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002143 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002144 }
2145 break;
2146 case 0x1c: /* Informational Exceptions Mode page */
2147 if (iec_m_pg[1] == arr[off + 1]) {
2148 memcpy(iec_m_pg + 2, arr + off + 2,
2149 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002150 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002151 }
2152 break;
2153 default:
2154 break;
2155 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002156 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002157 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002158set_mode_changed_ua:
2159 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2160 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002161}
2162
2163static int resp_temp_l_pg(unsigned char * arr)
2164{
2165 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2166 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2167 };
2168
2169 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2170 return sizeof(temp_l_pg);
2171}
2172
2173static int resp_ie_l_pg(unsigned char * arr)
2174{
2175 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2176 };
2177
2178 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2179 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2180 arr[4] = THRESHOLD_EXCEEDED;
2181 arr[5] = 0xff;
2182 }
2183 return sizeof(ie_l_pg);
2184}
2185
2186#define SDEBUG_MAX_LSENSE_SZ 512
2187
2188static int resp_log_sense(struct scsi_cmnd * scp,
2189 struct sdebug_dev_info * devip)
2190{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002191 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002192 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002193 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002194
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002195 memset(arr, 0, sizeof(arr));
2196 ppc = cmd[1] & 0x2;
2197 sp = cmd[1] & 0x1;
2198 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002199 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002200 return check_condition_result;
2201 }
2202 pcontrol = (cmd[2] & 0xc0) >> 6;
2203 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002204 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002205 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002206 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002207 if (0 == subpcode) {
2208 switch (pcode) {
2209 case 0x0: /* Supported log pages log page */
2210 n = 4;
2211 arr[n++] = 0x0; /* this page */
2212 arr[n++] = 0xd; /* Temperature */
2213 arr[n++] = 0x2f; /* Informational exceptions */
2214 arr[3] = n - 4;
2215 break;
2216 case 0xd: /* Temperature log page */
2217 arr[3] = resp_temp_l_pg(arr + 4);
2218 break;
2219 case 0x2f: /* Informational exceptions log page */
2220 arr[3] = resp_ie_l_pg(arr + 4);
2221 break;
2222 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002223 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002224 return check_condition_result;
2225 }
2226 } else if (0xff == subpcode) {
2227 arr[0] |= 0x40;
2228 arr[1] = subpcode;
2229 switch (pcode) {
2230 case 0x0: /* Supported log pages and subpages log page */
2231 n = 4;
2232 arr[n++] = 0x0;
2233 arr[n++] = 0x0; /* 0,0 page */
2234 arr[n++] = 0x0;
2235 arr[n++] = 0xff; /* this page */
2236 arr[n++] = 0xd;
2237 arr[n++] = 0x0; /* Temperature */
2238 arr[n++] = 0x2f;
2239 arr[n++] = 0x0; /* Informational exceptions */
2240 arr[3] = n - 4;
2241 break;
2242 case 0xd: /* Temperature subpages */
2243 n = 4;
2244 arr[n++] = 0xd;
2245 arr[n++] = 0x0; /* Temperature */
2246 arr[3] = n - 4;
2247 break;
2248 case 0x2f: /* Informational exceptions subpages */
2249 n = 4;
2250 arr[n++] = 0x2f;
2251 arr[n++] = 0x0; /* Informational exceptions */
2252 arr[3] = n - 4;
2253 break;
2254 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002255 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002256 return check_condition_result;
2257 }
2258 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002259 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002260 return check_condition_result;
2261 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002262 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002263 return fill_from_dev_buffer(scp, arr,
2264 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2265}
2266
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002267static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002268 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002270 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002271 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 return check_condition_result;
2273 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002274 /* transfer length excessive (tie in to block limits VPD page) */
2275 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002276 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002277 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002278 return check_condition_result;
2279 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002280 return 0;
2281}
2282
Akinobu Mitaa4517512013-07-08 16:01:57 -07002283/* Returns number of bytes copied or -1 if error. */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002284static int
2285do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002286{
2287 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002288 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002289 struct scsi_data_buffer *sdb;
2290 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002291
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002292 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002293 sdb = scsi_out(scmd);
2294 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002295 } else {
2296 sdb = scsi_in(scmd);
2297 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002298 }
2299
2300 if (!sdb->length)
2301 return 0;
2302 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2303 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002304
2305 block = do_div(lba, sdebug_store_sectors);
2306 if (block + num > sdebug_store_sectors)
2307 rest = block + num - sdebug_store_sectors;
2308
Dave Gordon386ecb12015-06-30 14:58:57 -07002309 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002310 fake_storep + (block * sdebug_sector_size),
2311 (num - rest) * sdebug_sector_size, 0, do_write);
2312 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002313 return ret;
2314
2315 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002316 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002317 fake_storep, rest * sdebug_sector_size,
2318 (num - rest) * sdebug_sector_size, do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002319 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002320
2321 return ret;
2322}
2323
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002324/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2325 * arr into fake_store(lba,num) and return true. If comparison fails then
2326 * return false. */
2327static bool
2328comp_write_worker(u64 lba, u32 num, const u8 *arr)
2329{
2330 bool res;
2331 u64 block, rest = 0;
2332 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002333 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002334
2335 block = do_div(lba, store_blks);
2336 if (block + num > store_blks)
2337 rest = block + num - store_blks;
2338
2339 res = !memcmp(fake_storep + (block * lb_size), arr,
2340 (num - rest) * lb_size);
2341 if (!res)
2342 return res;
2343 if (rest)
2344 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2345 rest * lb_size);
2346 if (!res)
2347 return res;
2348 arr += num * lb_size;
2349 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2350 if (rest)
2351 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2352 rest * lb_size);
2353 return res;
2354}
2355
Akinobu Mita51d648a2013-09-18 21:27:28 +09002356static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002357{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002358 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002359
Douglas Gilbert773642d2016-04-25 12:16:28 -04002360 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002361 csum = (__force __be16)ip_compute_csum(buf, len);
2362 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002363 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002364
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002365 return csum;
2366}
2367
2368static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2369 sector_t sector, u32 ei_lba)
2370{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002371 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002372
2373 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002374 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002375 (unsigned long)sector,
2376 be16_to_cpu(sdt->guard_tag),
2377 be16_to_cpu(csum));
2378 return 0x01;
2379 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002380 if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002381 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002382 pr_err("REF check failed on sector %lu\n",
2383 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002384 return 0x03;
2385 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002386 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002387 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002388 pr_err("REF check failed on sector %lu\n",
2389 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002390 return 0x03;
2391 }
2392 return 0;
2393}
2394
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002395static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002396 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002397{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002398 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002399 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002400 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002401 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002402
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002403 /* Bytes of protection data to copy into sgl */
2404 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002405
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002406 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2407 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2408 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2409
2410 while (sg_miter_next(&miter) && resid > 0) {
2411 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002412 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002413 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002414
2415 if (dif_store_end < start + len)
2416 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002417
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002418 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002419
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002420 if (read)
2421 memcpy(paddr, start, len - rest);
2422 else
2423 memcpy(start, paddr, len - rest);
2424
2425 if (rest) {
2426 if (read)
2427 memcpy(paddr + len - rest, dif_storep, rest);
2428 else
2429 memcpy(dif_storep, paddr + len - rest, rest);
2430 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002431
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002432 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002433 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002434 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002435 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002436}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002437
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002438static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2439 unsigned int sectors, u32 ei_lba)
2440{
2441 unsigned int i;
2442 struct sd_dif_tuple *sdt;
2443 sector_t sector;
2444
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002445 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002446 int ret;
2447
2448 sector = start_sec + i;
2449 sdt = dif_store(sector);
2450
Akinobu Mita51d648a2013-09-18 21:27:28 +09002451 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002452 continue;
2453
2454 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2455 if (ret) {
2456 dif_errors++;
2457 return ret;
2458 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002459 }
2460
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002461 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002462 dix_reads++;
2463
2464 return 0;
2465}
2466
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002467static int
2468resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002469{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002470 u8 *cmd = scp->cmnd;
2471 u64 lba;
2472 u32 num;
2473 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002474 unsigned long iflags;
2475 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002476 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002477
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002478 switch (cmd[0]) {
2479 case READ_16:
2480 ei_lba = 0;
2481 lba = get_unaligned_be64(cmd + 2);
2482 num = get_unaligned_be32(cmd + 10);
2483 check_prot = true;
2484 break;
2485 case READ_10:
2486 ei_lba = 0;
2487 lba = get_unaligned_be32(cmd + 2);
2488 num = get_unaligned_be16(cmd + 7);
2489 check_prot = true;
2490 break;
2491 case READ_6:
2492 ei_lba = 0;
2493 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2494 (u32)(cmd[1] & 0x1f) << 16;
2495 num = (0 == cmd[4]) ? 256 : cmd[4];
2496 check_prot = true;
2497 break;
2498 case READ_12:
2499 ei_lba = 0;
2500 lba = get_unaligned_be32(cmd + 2);
2501 num = get_unaligned_be32(cmd + 6);
2502 check_prot = true;
2503 break;
2504 case XDWRITEREAD_10:
2505 ei_lba = 0;
2506 lba = get_unaligned_be32(cmd + 2);
2507 num = get_unaligned_be16(cmd + 7);
2508 check_prot = false;
2509 break;
2510 default: /* assume READ(32) */
2511 lba = get_unaligned_be64(cmd + 12);
2512 ei_lba = get_unaligned_be32(cmd + 20);
2513 num = get_unaligned_be32(cmd + 28);
2514 check_prot = false;
2515 break;
2516 }
2517 if (check_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002518 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002519 (cmd[1] & 0xe0)) {
2520 mk_sense_invalid_opcode(scp);
2521 return check_condition_result;
2522 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002523 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2524 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002525 (cmd[1] & 0xe0) == 0)
2526 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2527 "to DIF device\n");
2528 }
2529 if (sdebug_any_injecting_opt) {
2530 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2531
2532 if (ep->inj_short)
2533 num /= 2;
2534 }
2535
2536 /* inline check_device_access_params() */
2537 if (lba + num > sdebug_capacity) {
2538 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2539 return check_condition_result;
2540 }
2541 /* transfer length excessive (tie in to block limits VPD page) */
2542 if (num > sdebug_store_sectors) {
2543 /* needs work to find which cdb byte 'num' comes from */
2544 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2545 return check_condition_result;
2546 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002547
Douglas Gilbert773642d2016-04-25 12:16:28 -04002548 if ((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002549 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002550 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2551 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002552 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002553 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002554 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2555 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002556 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2557 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002558 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002559 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002560 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 return check_condition_result;
2562 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002563
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002564 read_lock_irqsave(&atomic_rw, iflags);
2565
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002566 /* DIX + T10 DIF */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002567 if (sdebug_dix && scsi_prot_sg_count(scp)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002568 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002569
2570 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002571 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002572 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002573 return illegal_condition_result;
2574 }
2575 }
2576
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002577 ret = do_device_access(scp, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 read_unlock_irqrestore(&atomic_rw, iflags);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002579 if (ret == -1)
2580 return DID_ERROR << 16;
2581
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002582 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002583
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002584 if (sdebug_any_injecting_opt) {
2585 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2586
2587 if (ep->inj_recovered) {
2588 mk_sense_buffer(scp, RECOVERED_ERROR,
2589 THRESHOLD_EXCEEDED, 0);
2590 return check_condition_result;
2591 } else if (ep->inj_transport) {
2592 mk_sense_buffer(scp, ABORTED_COMMAND,
2593 TRANSPORT_PROBLEM, ACK_NAK_TO);
2594 return check_condition_result;
2595 } else if (ep->inj_dif) {
2596 /* Logical block guard check failed */
2597 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2598 return illegal_condition_result;
2599 } else if (ep->inj_dix) {
2600 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2601 return illegal_condition_result;
2602 }
2603 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002604 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605}
2606
Tomas Winkler58a86352015-07-28 16:54:23 +03002607static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002608{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002609 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002610
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002611 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002612 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002613 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002614
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002615 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002616 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002617
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002618 if (c >= 0x20 && c < 0x7e)
2619 n += scnprintf(b + n, sizeof(b) - n,
2620 " %c ", buf[i+j]);
2621 else
2622 n += scnprintf(b + n, sizeof(b) - n,
2623 "%02x ", buf[i+j]);
2624 }
2625 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002626 }
2627}
2628
2629static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002630 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002631{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002632 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002633 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002634 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002635 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002636 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002637 int dpage_offset;
2638 struct sg_mapping_iter diter;
2639 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002640
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002641 BUG_ON(scsi_sg_count(SCpnt) == 0);
2642 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2643
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002644 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2645 scsi_prot_sg_count(SCpnt),
2646 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2647 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2648 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002649
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002650 /* For each protection page */
2651 while (sg_miter_next(&piter)) {
2652 dpage_offset = 0;
2653 if (WARN_ON(!sg_miter_next(&diter))) {
2654 ret = 0x01;
2655 goto out;
2656 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002657
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002658 for (ppage_offset = 0; ppage_offset < piter.length;
2659 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002660 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002661 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002662 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002663 if (dpage_offset >= diter.length) {
2664 if (WARN_ON(!sg_miter_next(&diter))) {
2665 ret = 0x01;
2666 goto out;
2667 }
2668 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002669 }
2670
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002671 sdt = piter.addr + ppage_offset;
2672 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002673
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002674 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002675 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002676 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002677 goto out;
2678 }
2679
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002680 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002681 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002682 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002683 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002684 diter.consumed = dpage_offset;
2685 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002686 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002687 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002688
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002689 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002690 dix_writes++;
2691
2692 return 0;
2693
2694out:
2695 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002696 sg_miter_stop(&diter);
2697 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002698 return ret;
2699}
2700
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002701static unsigned long lba_to_map_index(sector_t lba)
2702{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002703 if (sdebug_unmap_alignment)
2704 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2705 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002706 return lba;
2707}
2708
2709static sector_t map_index_to_lba(unsigned long index)
2710{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002711 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002712
Douglas Gilbert773642d2016-04-25 12:16:28 -04002713 if (sdebug_unmap_alignment)
2714 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002715 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002716}
2717
Martin K. Petersen44d92692009-10-15 14:45:27 -04002718static unsigned int map_state(sector_t lba, unsigned int *num)
2719{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002720 sector_t end;
2721 unsigned int mapped;
2722 unsigned long index;
2723 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002724
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002725 index = lba_to_map_index(lba);
2726 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002727
2728 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002729 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002730 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002731 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002732
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002733 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002734 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002735 return mapped;
2736}
2737
2738static void map_region(sector_t lba, unsigned int len)
2739{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002740 sector_t end = lba + len;
2741
Martin K. Petersen44d92692009-10-15 14:45:27 -04002742 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002743 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002744
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002745 if (index < map_size)
2746 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002747
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002748 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002749 }
2750}
2751
2752static void unmap_region(sector_t lba, unsigned int len)
2753{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002754 sector_t end = lba + len;
2755
Martin K. Petersen44d92692009-10-15 14:45:27 -04002756 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002757 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002758
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002759 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002760 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002761 index < map_size) {
2762 clear_bit(index, map_storep);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002763 if (sdebug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002764 memset(fake_storep +
Douglas Gilbert773642d2016-04-25 12:16:28 -04002765 lba * sdebug_sector_size, 0,
2766 sdebug_sector_size *
2767 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002768 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002769 if (dif_storep) {
2770 memset(dif_storep + lba, 0xff,
2771 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002772 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002773 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002774 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002775 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002776 }
2777}
2778
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002779static int
2780resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002782 u8 *cmd = scp->cmnd;
2783 u64 lba;
2784 u32 num;
2785 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002787 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002788 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002790 switch (cmd[0]) {
2791 case WRITE_16:
2792 ei_lba = 0;
2793 lba = get_unaligned_be64(cmd + 2);
2794 num = get_unaligned_be32(cmd + 10);
2795 check_prot = true;
2796 break;
2797 case WRITE_10:
2798 ei_lba = 0;
2799 lba = get_unaligned_be32(cmd + 2);
2800 num = get_unaligned_be16(cmd + 7);
2801 check_prot = true;
2802 break;
2803 case WRITE_6:
2804 ei_lba = 0;
2805 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2806 (u32)(cmd[1] & 0x1f) << 16;
2807 num = (0 == cmd[4]) ? 256 : cmd[4];
2808 check_prot = true;
2809 break;
2810 case WRITE_12:
2811 ei_lba = 0;
2812 lba = get_unaligned_be32(cmd + 2);
2813 num = get_unaligned_be32(cmd + 6);
2814 check_prot = true;
2815 break;
2816 case 0x53: /* XDWRITEREAD(10) */
2817 ei_lba = 0;
2818 lba = get_unaligned_be32(cmd + 2);
2819 num = get_unaligned_be16(cmd + 7);
2820 check_prot = false;
2821 break;
2822 default: /* assume WRITE(32) */
2823 lba = get_unaligned_be64(cmd + 12);
2824 ei_lba = get_unaligned_be32(cmd + 20);
2825 num = get_unaligned_be32(cmd + 28);
2826 check_prot = false;
2827 break;
2828 }
2829 if (check_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002830 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002831 (cmd[1] & 0xe0)) {
2832 mk_sense_invalid_opcode(scp);
2833 return check_condition_result;
2834 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002835 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2836 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002837 (cmd[1] & 0xe0) == 0)
2838 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2839 "to DIF device\n");
2840 }
2841
2842 /* inline check_device_access_params() */
2843 if (lba + num > sdebug_capacity) {
2844 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2845 return check_condition_result;
2846 }
2847 /* transfer length excessive (tie in to block limits VPD page) */
2848 if (num > sdebug_store_sectors) {
2849 /* needs work to find which cdb byte 'num' comes from */
2850 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2851 return check_condition_result;
2852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002854 write_lock_irqsave(&atomic_rw, iflags);
2855
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002856 /* DIX + T10 DIF */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002857 if (sdebug_dix && scsi_prot_sg_count(scp)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002858 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002859
2860 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002861 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002862 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002863 return illegal_condition_result;
2864 }
2865 }
2866
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002867 ret = do_device_access(scp, lba, num, true);
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002868 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002869 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002871 if (-1 == ret)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002872 return DID_ERROR << 16;
2873 else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002874 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002875 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002876 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002877
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002878 if (sdebug_any_injecting_opt) {
2879 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2880
2881 if (ep->inj_recovered) {
2882 mk_sense_buffer(scp, RECOVERED_ERROR,
2883 THRESHOLD_EXCEEDED, 0);
2884 return check_condition_result;
2885 } else if (ep->inj_dif) {
2886 /* Logical block guard check failed */
2887 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2888 return illegal_condition_result;
2889 } else if (ep->inj_dix) {
2890 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2891 return illegal_condition_result;
2892 }
2893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 return 0;
2895}
2896
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002897static int
2898resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba,
2899 bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002900{
2901 unsigned long iflags;
2902 unsigned long long i;
2903 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002904 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002905
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002906 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002907 if (ret)
2908 return ret;
2909
2910 write_lock_irqsave(&atomic_rw, iflags);
2911
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002912 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002913 unmap_region(lba, num);
2914 goto out;
2915 }
2916
Douglas Gilbert773642d2016-04-25 12:16:28 -04002917 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002918 /* if ndob then zero 1 logical block, else fetch 1 logical block */
2919 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002920 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002921 ret = 0;
2922 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04002923 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2924 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002925
2926 if (-1 == ret) {
2927 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002928 return DID_ERROR << 16;
2929 } else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002930 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002931 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2932 my_name, "write same",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002933 num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002934
2935 /* Copy first sector to remaining blocks */
2936 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002937 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2938 fake_storep + lba_off,
2939 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002940
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002941 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002942 map_region(lba, num);
2943out:
2944 write_unlock_irqrestore(&atomic_rw, iflags);
2945
2946 return 0;
2947}
2948
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002949static int
2950resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2951{
2952 u8 *cmd = scp->cmnd;
2953 u32 lba;
2954 u16 num;
2955 u32 ei_lba = 0;
2956 bool unmap = false;
2957
2958 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002959 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002960 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2961 return check_condition_result;
2962 } else
2963 unmap = true;
2964 }
2965 lba = get_unaligned_be32(cmd + 2);
2966 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002967 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002968 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2969 return check_condition_result;
2970 }
2971 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2972}
2973
2974static int
2975resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2976{
2977 u8 *cmd = scp->cmnd;
2978 u64 lba;
2979 u32 num;
2980 u32 ei_lba = 0;
2981 bool unmap = false;
2982 bool ndob = false;
2983
2984 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002985 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002986 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2987 return check_condition_result;
2988 } else
2989 unmap = true;
2990 }
2991 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
2992 ndob = true;
2993 lba = get_unaligned_be64(cmd + 2);
2994 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002995 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002996 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
2997 return check_condition_result;
2998 }
2999 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3000}
3001
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003002/* Note the mode field is in the same position as the (lower) service action
3003 * field. For the Report supported operation codes command, SPC-4 suggests
3004 * each mode of this command should be reported separately; for future. */
3005static int
3006resp_write_buffer(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3007{
3008 u8 *cmd = scp->cmnd;
3009 struct scsi_device *sdp = scp->device;
3010 struct sdebug_dev_info *dp;
3011 u8 mode;
3012
3013 mode = cmd[1] & 0x1f;
3014 switch (mode) {
3015 case 0x4: /* download microcode (MC) and activate (ACT) */
3016 /* set UAs on this device only */
3017 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3018 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3019 break;
3020 case 0x5: /* download MC, save and ACT */
3021 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3022 break;
3023 case 0x6: /* download MC with offsets and ACT */
3024 /* set UAs on most devices (LUs) in this target */
3025 list_for_each_entry(dp,
3026 &devip->sdbg_host->dev_info_list,
3027 dev_list)
3028 if (dp->target == sdp->id) {
3029 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3030 if (devip != dp)
3031 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3032 dp->uas_bm);
3033 }
3034 break;
3035 case 0x7: /* download MC with offsets, save, and ACT */
3036 /* set UA on all devices (LUs) in this target */
3037 list_for_each_entry(dp,
3038 &devip->sdbg_host->dev_info_list,
3039 dev_list)
3040 if (dp->target == sdp->id)
3041 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3042 dp->uas_bm);
3043 break;
3044 default:
3045 /* do nothing for this command for other mode values */
3046 break;
3047 }
3048 return 0;
3049}
3050
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003051static int
3052resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3053{
3054 u8 *cmd = scp->cmnd;
3055 u8 *arr;
3056 u8 *fake_storep_hold;
3057 u64 lba;
3058 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003059 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003060 u8 num;
3061 unsigned long iflags;
3062 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003063 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003064
Douglas Gilbertd467d312014-11-26 12:33:48 -05003065 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003066 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3067 if (0 == num)
3068 return 0; /* degenerate case, not an error */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003069 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003070 (cmd[1] & 0xe0)) {
3071 mk_sense_invalid_opcode(scp);
3072 return check_condition_result;
3073 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003074 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3075 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003076 (cmd[1] & 0xe0) == 0)
3077 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3078 "to DIF device\n");
3079
3080 /* inline check_device_access_params() */
3081 if (lba + num > sdebug_capacity) {
3082 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3083 return check_condition_result;
3084 }
3085 /* transfer length excessive (tie in to block limits VPD page) */
3086 if (num > sdebug_store_sectors) {
3087 /* needs work to find which cdb byte 'num' comes from */
3088 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3089 return check_condition_result;
3090 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003091 dnum = 2 * num;
3092 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3093 if (NULL == arr) {
3094 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3095 INSUFF_RES_ASCQ);
3096 return check_condition_result;
3097 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003098
3099 write_lock_irqsave(&atomic_rw, iflags);
3100
3101 /* trick do_device_access() to fetch both compare and write buffers
3102 * from data-in into arr. Safe (atomic) since write_lock held. */
3103 fake_storep_hold = fake_storep;
3104 fake_storep = arr;
3105 ret = do_device_access(scp, 0, dnum, true);
3106 fake_storep = fake_storep_hold;
3107 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003108 retval = DID_ERROR << 16;
3109 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003110 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003111 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3112 "indicated=%u, IO sent=%d bytes\n", my_name,
3113 dnum * lb_size, ret);
3114 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003115 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003116 retval = check_condition_result;
3117 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003118 }
3119 if (scsi_debug_lbp())
3120 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003121cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003122 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003123 kfree(arr);
3124 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003125}
3126
Martin K. Petersen44d92692009-10-15 14:45:27 -04003127struct unmap_block_desc {
3128 __be64 lba;
3129 __be32 blocks;
3130 __be32 __reserved;
3131};
3132
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003133static int
3134resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003135{
3136 unsigned char *buf;
3137 struct unmap_block_desc *desc;
3138 unsigned int i, payload_len, descriptors;
3139 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003140 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003141
Martin K. Petersen44d92692009-10-15 14:45:27 -04003142
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003143 if (!scsi_debug_lbp())
3144 return 0; /* fib and say its done */
3145 payload_len = get_unaligned_be16(scp->cmnd + 7);
3146 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003147
3148 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003149 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003150 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003151 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003152 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003153
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003154 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
3155 if (!buf) {
3156 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3157 INSUFF_RES_ASCQ);
3158 return check_condition_result;
3159 }
3160
3161 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003162
3163 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3164 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3165
3166 desc = (void *)&buf[8];
3167
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003168 write_lock_irqsave(&atomic_rw, iflags);
3169
Martin K. Petersen44d92692009-10-15 14:45:27 -04003170 for (i = 0 ; i < descriptors ; i++) {
3171 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3172 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3173
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003174 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003175 if (ret)
3176 goto out;
3177
3178 unmap_region(lba, num);
3179 }
3180
3181 ret = 0;
3182
3183out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003184 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003185 kfree(buf);
3186
3187 return ret;
3188}
3189
3190#define SDEBUG_GET_LBA_STATUS_LEN 32
3191
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003192static int
3193resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003194{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003195 u8 *cmd = scp->cmnd;
3196 u64 lba;
3197 u32 alloc_len, mapped, num;
3198 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003199 int ret;
3200
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003201 lba = get_unaligned_be64(cmd + 2);
3202 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003203
3204 if (alloc_len < 24)
3205 return 0;
3206
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003207 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003208 if (ret)
3209 return ret;
3210
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003211 if (scsi_debug_lbp())
3212 mapped = map_state(lba, &num);
3213 else {
3214 mapped = 1;
3215 /* following just in case virtual_gb changed */
3216 sdebug_capacity = get_sdebug_capacity();
3217 if (sdebug_capacity - lba <= 0xffffffff)
3218 num = sdebug_capacity - lba;
3219 else
3220 num = 0xffffffff;
3221 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003222
3223 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003224 put_unaligned_be32(20, arr); /* Parameter Data Length */
3225 put_unaligned_be64(lba, arr + 8); /* LBA */
3226 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3227 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003228
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003229 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003230}
3231
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003232#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
3234static int resp_report_luns(struct scsi_cmnd * scp,
3235 struct sdebug_dev_info * devip)
3236{
3237 unsigned int alloc_len;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003238 int lun_cnt, i, upper, num, n, want_wlun, shortish;
3239 u64 lun;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003240 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 int select_report = (int)cmd[2];
3242 struct scsi_lun *one_lun;
3243 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003244 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003246 clear_luns_changed_on_target(devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003248 shortish = (alloc_len < 4);
3249 if (shortish || (select_report > 2)) {
3250 mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 return check_condition_result;
3252 }
3253 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
3254 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003255 lun_cnt = sdebug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003256 if (1 == select_report)
3257 lun_cnt = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003258 else if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003259 --lun_cnt;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003260 want_wlun = (select_report > 0) ? 1 : 0;
3261 num = lun_cnt + want_wlun;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003262 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3263 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3264 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3265 sizeof(struct scsi_lun)), num);
3266 if (n < num) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003267 want_wlun = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003268 lun_cnt = n;
3269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003271 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003272 for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003273 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3274 i++, lun++) {
3275 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 if (upper)
3277 one_lun[i].scsi_lun[0] =
3278 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003279 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003281 if (want_wlun) {
Tomas Winkler34d55432015-07-28 16:54:21 +03003282 one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
3283 one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003284 i++;
3285 }
3286 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 return fill_from_dev_buffer(scp, arr,
3288 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
3289}
3290
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003291static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3292 unsigned int num, struct sdebug_dev_info *devip)
3293{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003294 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003295 unsigned char *kaddr, *buf;
3296 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003297 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003298 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003299
3300 /* better not to use temporary buffer. */
3301 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003302 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003303 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3304 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003305 return check_condition_result;
3306 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003307
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003308 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003309
3310 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003311 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3312 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003313
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003314 while (sg_miter_next(&miter)) {
3315 kaddr = miter.addr;
3316 for (j = 0; j < miter.length; j++)
3317 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003318
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003319 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003320 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003321 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003322 kfree(buf);
3323
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003324 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003325}
3326
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003327static int
3328resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3329{
3330 u8 *cmd = scp->cmnd;
3331 u64 lba;
3332 u32 num;
3333 int errsts;
3334
3335 if (!scsi_bidi_cmnd(scp)) {
3336 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3337 INSUFF_RES_ASCQ);
3338 return check_condition_result;
3339 }
3340 errsts = resp_read_dt0(scp, devip);
3341 if (errsts)
3342 return errsts;
3343 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3344 errsts = resp_write_dt0(scp, devip);
3345 if (errsts)
3346 return errsts;
3347 }
3348 lba = get_unaligned_be32(cmd + 2);
3349 num = get_unaligned_be16(cmd + 7);
3350 return resp_xdwriteread(scp, lba, num, devip);
3351}
3352
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003353/* When timer or tasklet goes off this function is called. */
3354static void sdebug_q_cmd_complete(unsigned long indx)
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);
3364 qa_indx = indx;
3365 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{
3415 int qa_indx;
3416 int retiring = 0;
3417 unsigned long iflags;
3418 struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer;
3419 struct sdebug_queued_cmd *sqcp;
3420 struct scsi_cmnd *scp;
3421 struct sdebug_dev_info *devip;
3422
3423 atomic_inc(&sdebug_completions);
3424 qa_indx = sd_hrtp->qa_indx;
3425 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003426 pr_err("wild qa_indx=%d\n", qa_indx);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003427 goto the_end;
3428 }
3429 spin_lock_irqsave(&queued_arr_lock, iflags);
3430 sqcp = &queued_arr[qa_indx];
3431 scp = sqcp->a_cmnd;
3432 if (NULL == scp) {
3433 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003434 pr_err("scp is NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003435 goto the_end;
3436 }
3437 devip = (struct sdebug_dev_info *)scp->device->hostdata;
3438 if (devip)
3439 atomic_dec(&devip->num_in_q);
3440 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003441 pr_err("devip=NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003442 if (atomic_read(&retired_max_queue) > 0)
3443 retiring = 1;
3444
3445 sqcp->a_cmnd = NULL;
3446 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3447 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003448 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003449 goto the_end;
3450 }
3451
3452 if (unlikely(retiring)) { /* user has reduced max_queue */
3453 int k, retval;
3454
3455 retval = atomic_read(&retired_max_queue);
3456 if (qa_indx >= retval) {
3457 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003458 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003459 goto the_end;
3460 }
3461 k = find_last_bit(queued_in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003462 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003463 atomic_set(&retired_max_queue, 0);
3464 else
3465 atomic_set(&retired_max_queue, k + 1);
3466 }
3467 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3468 scp->scsi_done(scp); /* callback to mid level */
3469the_end:
3470 return HRTIMER_NORESTART;
3471}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003473static struct sdebug_dev_info *
3474sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003475{
3476 struct sdebug_dev_info *devip;
3477
3478 devip = kzalloc(sizeof(*devip), flags);
3479 if (devip) {
3480 devip->sdbg_host = sdbg_host;
3481 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3482 }
3483 return devip;
3484}
3485
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
3487{
3488 struct sdebug_host_info * sdbg_host;
3489 struct sdebug_dev_info * open_devip = NULL;
3490 struct sdebug_dev_info * devip =
3491 (struct sdebug_dev_info *)sdev->hostdata;
3492
3493 if (devip)
3494 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003495 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3496 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003497 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 return NULL;
3499 }
3500 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3501 if ((devip->used) && (devip->channel == sdev->channel) &&
3502 (devip->target == sdev->id) &&
3503 (devip->lun == sdev->lun))
3504 return devip;
3505 else {
3506 if ((!devip->used) && (!open_devip))
3507 open_devip = devip;
3508 }
3509 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003510 if (!open_devip) { /* try and make a new one */
3511 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3512 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003513 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 return NULL;
3515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003517
3518 open_devip->channel = sdev->channel;
3519 open_devip->target = sdev->id;
3520 open_devip->lun = sdev->lun;
3521 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003522 atomic_set(&open_devip->num_in_q, 0);
3523 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003524 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003525 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526}
3527
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003528static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003530 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003531 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003532 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003533 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003534 return 0;
3535}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003537static int scsi_debug_slave_configure(struct scsi_device *sdp)
3538{
3539 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003540
Douglas Gilbert773642d2016-04-25 12:16:28 -04003541 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003542 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003543 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3544 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
3545 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
3546 devip = devInfoReg(sdp);
3547 if (NULL == devip)
3548 return 1; /* no resources, will be marked offline */
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003549 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003550 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003551 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003552 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003553 return 0;
3554}
3555
3556static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3557{
3558 struct sdebug_dev_info *devip =
3559 (struct sdebug_dev_info *)sdp->hostdata;
3560
Douglas Gilbert773642d2016-04-25 12:16:28 -04003561 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003562 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003563 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3564 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003565 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003566 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003567 sdp->hostdata = NULL;
3568 }
3569}
3570
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003571/* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003572static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
3573{
3574 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003575 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003576 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003577 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003578
3579 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003580 qmax = sdebug_max_queue;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003581 r_qmax = atomic_read(&retired_max_queue);
3582 if (r_qmax > qmax)
3583 qmax = r_qmax;
3584 for (k = 0; k < qmax; ++k) {
3585 if (test_bit(k, queued_in_use_bm)) {
3586 sqcp = &queued_arr[k];
3587 if (cmnd == sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003588 devip = (struct sdebug_dev_info *)
3589 cmnd->device->hostdata;
3590 if (devip)
3591 atomic_dec(&devip->num_in_q);
3592 sqcp->a_cmnd = NULL;
3593 spin_unlock_irqrestore(&queued_arr_lock,
3594 iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003595 if (sdebug_ndelay > 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003596 if (sqcp->sd_hrtp)
3597 hrtimer_cancel(
3598 &sqcp->sd_hrtp->hrt);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003599 } else if (sdebug_delay > 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003600 if (sqcp->cmnd_timerp)
3601 del_timer_sync(
3602 sqcp->cmnd_timerp);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003603 } else if (sdebug_delay < 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003604 if (sqcp->tletp)
3605 tasklet_kill(sqcp->tletp);
3606 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003607 clear_bit(k, queued_in_use_bm);
3608 return 1;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003609 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003610 }
3611 }
3612 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003613 return 0;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003614}
3615
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003616/* Deletes (stops) timers or tasklets of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003617static void stop_all_queued(void)
3618{
3619 unsigned long iflags;
3620 int k;
3621 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003622 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003623
3624 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003625 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3626 if (test_bit(k, queued_in_use_bm)) {
3627 sqcp = &queued_arr[k];
3628 if (sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003629 devip = (struct sdebug_dev_info *)
3630 sqcp->a_cmnd->device->hostdata;
3631 if (devip)
3632 atomic_dec(&devip->num_in_q);
3633 sqcp->a_cmnd = NULL;
3634 spin_unlock_irqrestore(&queued_arr_lock,
3635 iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003636 if (sdebug_ndelay > 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003637 if (sqcp->sd_hrtp)
3638 hrtimer_cancel(
3639 &sqcp->sd_hrtp->hrt);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003640 } else if (sdebug_delay > 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003641 if (sqcp->cmnd_timerp)
3642 del_timer_sync(
3643 sqcp->cmnd_timerp);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003644 } else if (sdebug_delay < 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003645 if (sqcp->tletp)
3646 tasklet_kill(sqcp->tletp);
3647 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003648 clear_bit(k, queued_in_use_bm);
3649 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003650 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003651 }
3652 }
3653 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654}
3655
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003656/* Free queued command memory on heap */
3657static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003659 unsigned long iflags;
3660 int k;
3661 struct sdebug_queued_cmd *sqcp;
3662
3663 spin_lock_irqsave(&queued_arr_lock, iflags);
3664 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3665 sqcp = &queued_arr[k];
3666 kfree(sqcp->cmnd_timerp);
3667 sqcp->cmnd_timerp = NULL;
3668 kfree(sqcp->tletp);
3669 sqcp->tletp = NULL;
3670 kfree(sqcp->sd_hrtp);
3671 sqcp->sd_hrtp = NULL;
3672 }
3673 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674}
3675
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003676static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003678 ++num_aborts;
3679 if (SCpnt) {
3680 if (SCpnt->device &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04003681 (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003682 sdev_printk(KERN_INFO, SCpnt->device, "%s\n",
3683 __func__);
3684 stop_queued_cmnd(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003686 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687}
3688
3689static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3690{
3691 struct sdebug_dev_info * devip;
3692
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003694 if (SCpnt && SCpnt->device) {
3695 struct scsi_device *sdp = SCpnt->device;
3696
Douglas Gilbert773642d2016-04-25 12:16:28 -04003697 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003698 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3699 devip = devInfoReg(sdp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003701 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 }
3703 return SUCCESS;
3704}
3705
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003706static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3707{
3708 struct sdebug_host_info *sdbg_host;
3709 struct sdebug_dev_info *devip;
3710 struct scsi_device *sdp;
3711 struct Scsi_Host *hp;
3712 int k = 0;
3713
3714 ++num_target_resets;
3715 if (!SCpnt)
3716 goto lie;
3717 sdp = SCpnt->device;
3718 if (!sdp)
3719 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003720 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003721 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3722 hp = sdp->host;
3723 if (!hp)
3724 goto lie;
3725 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3726 if (sdbg_host) {
3727 list_for_each_entry(devip,
3728 &sdbg_host->dev_info_list,
3729 dev_list)
3730 if (devip->target == sdp->id) {
3731 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3732 ++k;
3733 }
3734 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003735 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003736 sdev_printk(KERN_INFO, sdp,
3737 "%s: %d device(s) found in target\n", __func__, k);
3738lie:
3739 return SUCCESS;
3740}
3741
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3743{
3744 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003745 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 struct scsi_device * sdp;
3747 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003748 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003751 if (!(SCpnt && SCpnt->device))
3752 goto lie;
3753 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003754 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003755 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3756 hp = sdp->host;
3757 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003758 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003760 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003762 dev_list) {
3763 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3764 ++k;
3765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 }
3767 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003768 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003769 sdev_printk(KERN_INFO, sdp,
3770 "%s: %d device(s) found in host\n", __func__, k);
3771lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 return SUCCESS;
3773}
3774
3775static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3776{
3777 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003778 struct sdebug_dev_info *devip;
3779 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003782 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003783 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 spin_lock(&sdebug_host_list_lock);
3785 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003786 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3787 dev_list) {
3788 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3789 ++k;
3790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 }
3792 spin_unlock(&sdebug_host_list_lock);
3793 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003794 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003795 sdev_printk(KERN_INFO, SCpnt->device,
3796 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 return SUCCESS;
3798}
3799
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003800static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003801 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802{
3803 struct partition * pp;
3804 int starts[SDEBUG_MAX_PARTS + 2];
3805 int sectors_per_part, num_sectors, k;
3806 int heads_by_sects, start_sec, end_sec;
3807
3808 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003809 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003811 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3812 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003813 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003815 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003817 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3819 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003820 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3822 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003823 starts[sdebug_num_parts] = num_sectors;
3824 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825
3826 ramp[510] = 0x55; /* magic partition markings */
3827 ramp[511] = 0xAA;
3828 pp = (struct partition *)(ramp + 0x1be);
3829 for (k = 0; starts[k + 1]; ++k, ++pp) {
3830 start_sec = starts[k];
3831 end_sec = starts[k + 1] - 1;
3832 pp->boot_ind = 0;
3833
3834 pp->cyl = start_sec / heads_by_sects;
3835 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3836 / sdebug_sectors_per;
3837 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3838
3839 pp->end_cyl = end_sec / heads_by_sects;
3840 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3841 / sdebug_sectors_per;
3842 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3843
Akinobu Mita150c3542013-08-26 22:08:40 +09003844 pp->start_sect = cpu_to_le32(start_sec);
3845 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 pp->sys_ind = 0x83; /* plain Linux partition */
3847 }
3848}
3849
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003850static int
3851schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3852 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003854 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003855 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003856 struct sdebug_queued_cmd *sqcp = NULL;
Tomas Winkler299b6c02015-07-28 16:54:24 +03003857 struct scsi_device *sdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858
Tomas Winkler299b6c02015-07-28 16:54:24 +03003859 /* this should never happen */
3860 if (WARN_ON(!cmnd))
3861 return SCSI_MLQUEUE_HOST_BUSY;
3862
3863 if (NULL == devip) {
3864 pr_warn("called devip == NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003865 /* no particularly good error to report back */
3866 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03003868
3869 sdp = cmnd->device;
3870
Douglas Gilbert773642d2016-04-25 12:16:28 -04003871 if (sdebug_verbose && scsi_result)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003872 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3873 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003874 if (delta_jiff == 0)
3875 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003877 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003878 spin_lock_irqsave(&queued_arr_lock, iflags);
3879 num_in_q = atomic_read(&devip->num_in_q);
3880 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003881 inject = 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003882 if ((qdepth > 0) && (num_in_q >= qdepth)) {
3883 if (scsi_result) {
3884 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3885 goto respond_in_thread;
3886 } else
3887 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003888 } else if ((sdebug_every_nth != 0) &&
3889 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003890 (scsi_result == 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003891 if ((num_in_q == (qdepth - 1)) &&
3892 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04003893 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003894 atomic_set(&sdebug_a_tsf, 0);
3895 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003896 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003898 }
3899
Douglas Gilbert773642d2016-04-25 12:16:28 -04003900 k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
3901 if (k >= sdebug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003903 if (scsi_result)
3904 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003905 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003906 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003907 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003908 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003909 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003910 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003911 (scsi_result ? "status: TASK SET FULL" :
3912 "report: host busy"));
3913 if (scsi_result)
3914 goto respond_in_thread;
3915 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003916 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003918 __set_bit(k, queued_in_use_bm);
3919 atomic_inc(&devip->num_in_q);
3920 sqcp = &queued_arr[k];
3921 sqcp->a_cmnd = cmnd;
3922 cmnd->result = scsi_result;
3923 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3924 if (delta_jiff > 0) {
3925 if (NULL == sqcp->cmnd_timerp) {
3926 sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list),
3927 GFP_ATOMIC);
3928 if (NULL == sqcp->cmnd_timerp)
3929 return SCSI_MLQUEUE_HOST_BUSY;
3930 init_timer(sqcp->cmnd_timerp);
3931 }
3932 sqcp->cmnd_timerp->function = sdebug_q_cmd_complete;
3933 sqcp->cmnd_timerp->data = k;
3934 sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff;
3935 add_timer(sqcp->cmnd_timerp);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003936 } else if (sdebug_ndelay > 0) {
3937 ktime_t kt = ktime_set(0, sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003938 struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp;
3939
3940 if (NULL == sd_hp) {
3941 sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC);
3942 if (NULL == sd_hp)
3943 return SCSI_MLQUEUE_HOST_BUSY;
3944 sqcp->sd_hrtp = sd_hp;
3945 hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC,
3946 HRTIMER_MODE_REL);
3947 sd_hp->hrt.function = sdebug_q_cmd_hrt_complete;
3948 sd_hp->qa_indx = k;
3949 }
3950 hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL);
3951 } else { /* delay < 0 */
3952 if (NULL == sqcp->tletp) {
3953 sqcp->tletp = kmalloc(sizeof(*sqcp->tletp),
3954 GFP_ATOMIC);
3955 if (NULL == sqcp->tletp)
3956 return SCSI_MLQUEUE_HOST_BUSY;
3957 tasklet_init(sqcp->tletp,
3958 sdebug_q_cmd_complete, k);
3959 }
3960 if (-1 == delta_jiff)
3961 tasklet_hi_schedule(sqcp->tletp);
3962 else
3963 tasklet_schedule(sqcp->tletp);
3964 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003965 if ((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003966 (scsi_result == device_qfull_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003967 sdev_printk(KERN_INFO, sdp,
3968 "%s: num_in_q=%d +1, %s%s\n", __func__,
3969 num_in_q, (inject ? "<inject> " : ""),
3970 "status: TASK SET FULL");
3971 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003972
3973respond_in_thread: /* call back to mid-layer using invocation thread */
3974 cmnd->result = scsi_result;
3975 cmnd->scsi_done(cmnd);
3976 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003978
Douglas Gilbert23183912006-09-16 20:30:47 -04003979/* Note: The following macros create attribute files in the
3980 /sys/module/scsi_debug/parameters directory. Unfortunately this
3981 driver is unaware of a change and cannot trigger auxiliary actions
3982 as it can when the corresponding attribute in the
3983 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3984 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003985module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
3986module_param_named(ato, sdebug_ato, int, S_IRUGO);
3987module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
3988module_param_named(delay, sdebug_delay, int, S_IRUGO | S_IWUSR);
3989module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
3990module_param_named(dif, sdebug_dif, int, S_IRUGO);
3991module_param_named(dix, sdebug_dix, int, S_IRUGO);
3992module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
3993module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
3994module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
3995module_param_named(guard, sdebug_guard, uint, S_IRUGO);
3996module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
3997module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
3998module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
3999module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4000module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4001module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4002module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4003module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4004module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4005module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4006module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4007module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4008module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4009module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4010module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4011module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
4012module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4013module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4014module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4015module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4016module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4017module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4018module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4019module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4020module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4021module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
4022module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004023 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004024module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004025 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026
4027MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4028MODULE_DESCRIPTION("SCSI debug adapter driver");
4029MODULE_LICENSE("GPL");
4030MODULE_VERSION(SCSI_DEBUG_VERSION);
4031
4032MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004033MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004034MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004035MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004036MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004037MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4038MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004039MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004040MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004041MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004042MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004043MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004044MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4045MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4046MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06004047MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004048MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004049MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004050MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4051MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004052MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004053MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004055MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004056MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004057MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004058MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004060MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02004061MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004062MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004063MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004064MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4065MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004066MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4067MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004068MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004069MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4070MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071
4072static char sdebug_info[256];
4073
4074static const char * scsi_debug_info(struct Scsi_Host * shp)
4075{
4076 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
4077 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004078 sdebug_version_date, sdebug_dev_size_mb, sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 return sdebug_info;
4080}
4081
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004082/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Al Viroc8ed5552013-03-31 01:46:06 -04004083static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084{
Al Viroc8ed5552013-03-31 01:46:06 -04004085 char arr[16];
4086 int opts;
4087 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088
Al Viroc8ed5552013-03-31 01:46:06 -04004089 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4090 return -EACCES;
4091 memcpy(arr, buffer, minLen);
4092 arr[minLen] = '\0';
4093 if (1 != sscanf(arr, "%d", &opts))
4094 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004095 sdebug_opts = opts;
4096 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4097 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4098 if (sdebug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004099 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04004100 return length;
4101}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004103/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4104 * same for each scsi_debug host (if more than one). Some of the counters
4105 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004106static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4107{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004108 int f, l;
4109 char b[32];
4110
Douglas Gilbert773642d2016-04-25 12:16:28 -04004111 if (sdebug_every_nth > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004112 snprintf(b, sizeof(b), " (curr:%d)",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004113 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004114 atomic_read(&sdebug_a_tsf) :
4115 atomic_read(&sdebug_cmnd_count)));
4116 else
4117 b[0] = '\0';
4118
4119 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
4120 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4121 "every_nth=%d%s\n"
4122 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
4123 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4124 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4125 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4126 "usec_in_jiffy=%lu\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004127 SCSI_DEBUG_VERSION, sdebug_version_date,
4128 sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
4129 sdebug_every_nth, b, sdebug_delay, sdebug_ndelay,
4130 sdebug_max_luns, atomic_read(&sdebug_completions),
4131 sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004132 sdebug_sectors_per, num_aborts, num_dev_resets,
4133 num_target_resets, num_bus_resets, num_host_resets,
4134 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4135
Douglas Gilbert773642d2016-04-25 12:16:28 -04004136 f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4137 if (f != sdebug_max_queue) {
4138 l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004139 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
4140 "queued_in_use_bm", f, l);
4141 }
Al Viroc8ed5552013-03-31 01:46:06 -04004142 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143}
4144
Akinobu Mita82069372013-10-14 22:48:04 +09004145static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004147 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004149/* Returns -EBUSY if delay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09004150static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4151 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004153 int delay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004155 if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) {
4156 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004157 if (sdebug_delay != delay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004158 unsigned long iflags;
4159 int k;
4160
4161 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004162 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4163 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004164 res = -EBUSY; /* have queued commands */
4165 else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004166 sdebug_delay = delay;
4167 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004168 }
4169 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004171 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 }
4173 return -EINVAL;
4174}
Akinobu Mita82069372013-10-14 22:48:04 +09004175static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004177static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4178{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004179 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004180}
4181/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004182/* If > 0 and accepted then sdebug_delay is set to DELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004183static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4184 size_t count)
4185{
4186 unsigned long iflags;
4187 int ndelay, res, k;
4188
4189 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4190 (ndelay >= 0) && (ndelay < 1000000000)) {
4191 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004192 if (sdebug_ndelay != ndelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004193 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004194 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4195 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004196 res = -EBUSY; /* have queued commands */
4197 else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004198 sdebug_ndelay = ndelay;
4199 sdebug_delay = ndelay ? DELAY_OVERRIDDEN
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004200 : DEF_DELAY;
4201 }
4202 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4203 }
4204 return res;
4205 }
4206 return -EINVAL;
4207}
4208static DRIVER_ATTR_RW(ndelay);
4209
Akinobu Mita82069372013-10-14 22:48:04 +09004210static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004212 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213}
4214
Akinobu Mita82069372013-10-14 22:48:04 +09004215static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4216 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217{
4218 int opts;
4219 char work[20];
4220
4221 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07004222 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 if (1 == sscanf(&work[2], "%x", &opts))
4224 goto opts_done;
4225 } else {
4226 if (1 == sscanf(work, "%d", &opts))
4227 goto opts_done;
4228 }
4229 }
4230 return -EINVAL;
4231opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004232 sdebug_opts = opts;
4233 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4234 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004235 atomic_set(&sdebug_cmnd_count, 0);
4236 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 return count;
4238}
Akinobu Mita82069372013-10-14 22:48:04 +09004239static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240
Akinobu Mita82069372013-10-14 22:48:04 +09004241static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004243 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244}
Akinobu Mita82069372013-10-14 22:48:04 +09004245static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4246 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247{
4248 int n;
4249
4250 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004251 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 return count;
4253 }
4254 return -EINVAL;
4255}
Akinobu Mita82069372013-10-14 22:48:04 +09004256static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257
Akinobu Mita82069372013-10-14 22:48:04 +09004258static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004260 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261}
Akinobu Mita82069372013-10-14 22:48:04 +09004262static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4263 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264{
4265 int n;
4266
4267 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004268 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 return count;
4270 }
4271 return -EINVAL;
4272}
Akinobu Mita82069372013-10-14 22:48:04 +09004273static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274
Akinobu Mita82069372013-10-14 22:48:04 +09004275static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004276{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004277 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004278}
Akinobu Mita82069372013-10-14 22:48:04 +09004279static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4280 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004281{
4282 int n;
4283
4284 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004285 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004286 sdebug_fake_rw = (sdebug_fake_rw > 0);
4287 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004288 if ((0 == n) && (NULL == fake_storep)) {
4289 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004290 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004291 1048576;
4292
4293 fake_storep = vmalloc(sz);
4294 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004295 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004296 return -ENOMEM;
4297 }
4298 memset(fake_storep, 0, sz);
4299 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004300 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004301 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004302 return count;
4303 }
4304 return -EINVAL;
4305}
Akinobu Mita82069372013-10-14 22:48:04 +09004306static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004307
Akinobu Mita82069372013-10-14 22:48:04 +09004308static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004309{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004310 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004311}
Akinobu Mita82069372013-10-14 22:48:04 +09004312static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4313 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004314{
4315 int n;
4316
4317 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004318 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004319 return count;
4320 }
4321 return -EINVAL;
4322}
Akinobu Mita82069372013-10-14 22:48:04 +09004323static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004324
Akinobu Mita82069372013-10-14 22:48:04 +09004325static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004327 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328}
Akinobu Mita82069372013-10-14 22:48:04 +09004329static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4330 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331{
4332 int n;
4333
4334 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004335 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 sdebug_max_tgts_luns();
4337 return count;
4338 }
4339 return -EINVAL;
4340}
Akinobu Mita82069372013-10-14 22:48:04 +09004341static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342
Akinobu Mita82069372013-10-14 22:48:04 +09004343static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004345 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346}
Akinobu Mita82069372013-10-14 22:48:04 +09004347static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348
Akinobu Mita82069372013-10-14 22:48:04 +09004349static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004351 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352}
Akinobu Mita82069372013-10-14 22:48:04 +09004353static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354
Akinobu Mita82069372013-10-14 22:48:04 +09004355static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004357 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358}
Akinobu Mita82069372013-10-14 22:48:04 +09004359static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4360 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361{
4362 int nth;
4363
4364 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004365 sdebug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004366 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 return count;
4368 }
4369 return -EINVAL;
4370}
Akinobu Mita82069372013-10-14 22:48:04 +09004371static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372
Akinobu Mita82069372013-10-14 22:48:04 +09004373static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004375 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376}
Akinobu Mita82069372013-10-14 22:48:04 +09004377static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4378 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379{
4380 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004381 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382
4383 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004384 changed = (sdebug_max_luns != n);
4385 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004387 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004388 struct sdebug_host_info *sdhp;
4389 struct sdebug_dev_info *dp;
4390
4391 spin_lock(&sdebug_host_list_lock);
4392 list_for_each_entry(sdhp, &sdebug_host_list,
4393 host_list) {
4394 list_for_each_entry(dp, &sdhp->dev_info_list,
4395 dev_list) {
4396 set_bit(SDEBUG_UA_LUNS_CHANGED,
4397 dp->uas_bm);
4398 }
4399 }
4400 spin_unlock(&sdebug_host_list_lock);
4401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 return count;
4403 }
4404 return -EINVAL;
4405}
Akinobu Mita82069372013-10-14 22:48:04 +09004406static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407
Akinobu Mita82069372013-10-14 22:48:04 +09004408static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004409{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004410 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004411}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004412/* N.B. max_queue can be changed while there are queued commands. In flight
4413 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004414static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4415 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004416{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004417 unsigned long iflags;
4418 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004419
4420 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4421 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004422 spin_lock_irqsave(&queued_arr_lock, iflags);
4423 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004424 sdebug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004425 if (SCSI_DEBUG_CANQUEUE == k)
4426 atomic_set(&retired_max_queue, 0);
4427 else if (k >= n)
4428 atomic_set(&retired_max_queue, k + 1);
4429 else
4430 atomic_set(&retired_max_queue, 0);
4431 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004432 return count;
4433 }
4434 return -EINVAL;
4435}
Akinobu Mita82069372013-10-14 22:48:04 +09004436static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004437
Akinobu Mita82069372013-10-14 22:48:04 +09004438static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004439{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004440 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004441}
Akinobu Mita82069372013-10-14 22:48:04 +09004442static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004443
Akinobu Mita82069372013-10-14 22:48:04 +09004444static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004446 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447}
Akinobu Mita82069372013-10-14 22:48:04 +09004448static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449
Akinobu Mita82069372013-10-14 22:48:04 +09004450static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004451{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004452 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004453}
Akinobu Mita82069372013-10-14 22:48:04 +09004454static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4455 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004456{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004457 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004458 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004459
4460 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004461 changed = (sdebug_virtual_gb != n);
4462 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004463 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004464 if (changed) {
4465 struct sdebug_host_info *sdhp;
4466 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004467
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004468 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004469 list_for_each_entry(sdhp, &sdebug_host_list,
4470 host_list) {
4471 list_for_each_entry(dp, &sdhp->dev_info_list,
4472 dev_list) {
4473 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4474 dp->uas_bm);
4475 }
4476 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004477 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004478 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004479 return count;
4480 }
4481 return -EINVAL;
4482}
Akinobu Mita82069372013-10-14 22:48:04 +09004483static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004484
Akinobu Mita82069372013-10-14 22:48:04 +09004485static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004487 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488}
4489
Akinobu Mita82069372013-10-14 22:48:04 +09004490static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4491 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004493 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004495 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 if (delta_hosts > 0) {
4498 do {
4499 sdebug_add_adapter();
4500 } while (--delta_hosts);
4501 } else if (delta_hosts < 0) {
4502 do {
4503 sdebug_remove_adapter();
4504 } while (++delta_hosts);
4505 }
4506 return count;
4507}
Akinobu Mita82069372013-10-14 22:48:04 +09004508static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509
Akinobu Mita82069372013-10-14 22:48:04 +09004510static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004511{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004512 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004513}
Akinobu Mita82069372013-10-14 22:48:04 +09004514static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4515 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004516{
4517 int n;
4518
4519 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004520 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004521 return count;
4522 }
4523 return -EINVAL;
4524}
Akinobu Mita82069372013-10-14 22:48:04 +09004525static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004526
Akinobu Mita82069372013-10-14 22:48:04 +09004527static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004528{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004529 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004530}
Akinobu Mita82069372013-10-14 22:48:04 +09004531static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004532
Akinobu Mita82069372013-10-14 22:48:04 +09004533static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004534{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004535 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004536}
Akinobu Mita82069372013-10-14 22:48:04 +09004537static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004538
Akinobu Mita82069372013-10-14 22:48:04 +09004539static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004540{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004541 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004542}
Akinobu Mita82069372013-10-14 22:48:04 +09004543static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004544
Akinobu Mita82069372013-10-14 22:48:04 +09004545static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004546{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004547 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004548}
Akinobu Mita82069372013-10-14 22:48:04 +09004549static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004550
Akinobu Mita82069372013-10-14 22:48:04 +09004551static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004552{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004553 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004554}
Akinobu Mita82069372013-10-14 22:48:04 +09004555static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004556
Akinobu Mita82069372013-10-14 22:48:04 +09004557static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004558{
4559 ssize_t count;
4560
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004561 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004562 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4563 sdebug_store_sectors);
4564
Tejun Heoc7badc92015-02-13 14:37:51 -08004565 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4566 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004567 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004568 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004569
4570 return count;
4571}
Akinobu Mita82069372013-10-14 22:48:04 +09004572static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004573
Akinobu Mita82069372013-10-14 22:48:04 +09004574static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004575{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004576 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004577}
Akinobu Mita82069372013-10-14 22:48:04 +09004578static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4579 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004580{
4581 int n;
4582
4583 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004584 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004585 return count;
4586 }
4587 return -EINVAL;
4588}
Akinobu Mita82069372013-10-14 22:48:04 +09004589static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004590
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004591static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4592{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004593 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004594}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004595/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004596static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4597 size_t count)
4598{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004599 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004600
4601 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004602 sdebug_host_lock = (n > 0);
4603 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004604 }
4605 return -EINVAL;
4606}
4607static DRIVER_ATTR_RW(host_lock);
4608
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004609static ssize_t strict_show(struct device_driver *ddp, char *buf)
4610{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004611 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004612}
4613static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4614 size_t count)
4615{
4616 int n;
4617
4618 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004619 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004620 return count;
4621 }
4622 return -EINVAL;
4623}
4624static DRIVER_ATTR_RW(strict);
4625
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004626
Akinobu Mita82069372013-10-14 22:48:04 +09004627/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004628 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4629 files (over those found in the /sys/module/scsi_debug/parameters
4630 directory) is that auxiliary actions can be triggered when an attribute
4631 is changed. For example see: sdebug_add_host_store() above.
4632 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004633
Akinobu Mita82069372013-10-14 22:48:04 +09004634static struct attribute *sdebug_drv_attrs[] = {
4635 &driver_attr_delay.attr,
4636 &driver_attr_opts.attr,
4637 &driver_attr_ptype.attr,
4638 &driver_attr_dsense.attr,
4639 &driver_attr_fake_rw.attr,
4640 &driver_attr_no_lun_0.attr,
4641 &driver_attr_num_tgts.attr,
4642 &driver_attr_dev_size_mb.attr,
4643 &driver_attr_num_parts.attr,
4644 &driver_attr_every_nth.attr,
4645 &driver_attr_max_luns.attr,
4646 &driver_attr_max_queue.attr,
4647 &driver_attr_no_uld.attr,
4648 &driver_attr_scsi_level.attr,
4649 &driver_attr_virtual_gb.attr,
4650 &driver_attr_add_host.attr,
4651 &driver_attr_vpd_use_hostno.attr,
4652 &driver_attr_sector_size.attr,
4653 &driver_attr_dix.attr,
4654 &driver_attr_dif.attr,
4655 &driver_attr_guard.attr,
4656 &driver_attr_ato.attr,
4657 &driver_attr_map.attr,
4658 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004659 &driver_attr_host_lock.attr,
4660 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004661 &driver_attr_strict.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004662 NULL,
4663};
4664ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004666static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004667
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668static int __init scsi_debug_init(void)
4669{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004670 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 int host_to_add;
4672 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004673 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004675 atomic_set(&sdebug_cmnd_count, 0);
4676 atomic_set(&sdebug_completions, 0);
4677 atomic_set(&retired_max_queue, 0);
4678
Douglas Gilbert773642d2016-04-25 12:16:28 -04004679 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004680 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04004681 sdebug_ndelay = 0;
4682 } else if (sdebug_ndelay > 0)
4683 sdebug_delay = DELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004684
Douglas Gilbert773642d2016-04-25 12:16:28 -04004685 switch (sdebug_sector_size) {
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004686 case 512:
4687 case 1024:
4688 case 2048:
4689 case 4096:
4690 break;
4691 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004692 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004693 return -EINVAL;
4694 }
4695
Douglas Gilbert773642d2016-04-25 12:16:28 -04004696 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004697
4698 case SD_DIF_TYPE0_PROTECTION:
4699 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004700 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004701 case SD_DIF_TYPE3_PROTECTION:
4702 break;
4703
4704 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03004705 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004706 return -EINVAL;
4707 }
4708
Douglas Gilbert773642d2016-04-25 12:16:28 -04004709 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004710 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004711 return -EINVAL;
4712 }
4713
Douglas Gilbert773642d2016-04-25 12:16:28 -04004714 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004715 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004716 return -EINVAL;
4717 }
4718
Douglas Gilbert773642d2016-04-25 12:16:28 -04004719 if (sdebug_physblk_exp > 15) {
4720 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004721 return -EINVAL;
4722 }
4723
Douglas Gilbert773642d2016-04-25 12:16:28 -04004724 if (sdebug_lowest_aligned > 0x3fff) {
4725 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004726 return -EINVAL;
4727 }
4728
Douglas Gilbert773642d2016-04-25 12:16:28 -04004729 if (sdebug_dev_size_mb < 1)
4730 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
4731 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4732 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004733 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734
4735 /* play around with geometry, don't waste too much on track 0 */
4736 sdebug_heads = 8;
4737 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004738 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004740 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02004741 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4743 (sdebug_sectors_per * sdebug_heads);
4744 if (sdebug_cylinders_per >= 1024) {
4745 /* other LLDs do this; implies >= 1GB ram disk ... */
4746 sdebug_heads = 255;
4747 sdebug_sectors_per = 63;
4748 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4749 (sdebug_sectors_per * sdebug_heads);
4750 }
4751
Douglas Gilbert773642d2016-04-25 12:16:28 -04004752 if (0 == sdebug_fake_rw) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004753 fake_storep = vmalloc(sz);
4754 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004755 pr_err("out of memory, 1\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004756 return -ENOMEM;
4757 }
4758 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004759 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004760 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
Douglas Gilbert773642d2016-04-25 12:16:28 -04004763 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004764 int dif_size;
4765
4766 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4767 dif_storep = vmalloc(dif_size);
4768
Tomas Winklerc12879702015-07-28 16:54:20 +03004769 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004770
4771 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004772 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004773 ret = -ENOMEM;
4774 goto free_vm;
4775 }
4776
4777 memset(dif_storep, 0xff, dif_size);
4778 }
4779
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004780 /* Logical Block Provisioning */
4781 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004782 sdebug_unmap_max_blocks =
4783 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004784
Douglas Gilbert773642d2016-04-25 12:16:28 -04004785 sdebug_unmap_max_desc =
4786 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04004787
Douglas Gilbert773642d2016-04-25 12:16:28 -04004788 sdebug_unmap_granularity =
4789 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004790
Douglas Gilbert773642d2016-04-25 12:16:28 -04004791 if (sdebug_unmap_alignment &&
4792 sdebug_unmap_granularity <=
4793 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004794 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004795 return -EINVAL;
4796 }
4797
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004798 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4799 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04004800
Tomas Winklerc12879702015-07-28 16:54:20 +03004801 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004802
4803 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004804 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004805 ret = -ENOMEM;
4806 goto free_vm;
4807 }
4808
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004809 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004810
4811 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004812 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004813 map_region(0, 2);
4814 }
4815
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004816 pseudo_primary = root_device_register("pseudo_0");
4817 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004818 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004819 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004820 goto free_vm;
4821 }
4822 ret = bus_register(&pseudo_lld_bus);
4823 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004824 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004825 goto dev_unreg;
4826 }
4827 ret = driver_register(&sdebug_driverfs_driver);
4828 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004829 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004830 goto bus_unreg;
4831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832
Douglas Gilbert773642d2016-04-25 12:16:28 -04004833 host_to_add = sdebug_add_host;
4834 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835
4836 for (k = 0; k < host_to_add; k++) {
4837 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004838 pr_err("sdebug_add_adapter failed k=%d\n", k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 break;
4840 }
4841 }
4842
Douglas Gilbert773642d2016-04-25 12:16:28 -04004843 if (sdebug_verbose)
4844 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03004845
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004847
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004848bus_unreg:
4849 bus_unregister(&pseudo_lld_bus);
4850dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004851 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004852free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03004853 vfree(map_storep);
4854 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004855 vfree(fake_storep);
4856
4857 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858}
4859
4860static void __exit scsi_debug_exit(void)
4861{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004862 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863
4864 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004865 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 for (; k; k--)
4867 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 driver_unregister(&sdebug_driverfs_driver);
4869 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004870 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871
Tomas Winklerde232af2015-07-28 16:54:22 +03004872 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 vfree(fake_storep);
4874}
4875
4876device_initcall(scsi_debug_init);
4877module_exit(scsi_debug_exit);
4878
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879static void sdebug_release_adapter(struct device * dev)
4880{
4881 struct sdebug_host_info *sdbg_host;
4882
4883 sdbg_host = to_sdebug_host(dev);
4884 kfree(sdbg_host);
4885}
4886
4887static int sdebug_add_adapter(void)
4888{
4889 int k, devs_per_host;
4890 int error = 0;
4891 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004892 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004894 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895 if (NULL == sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004896 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 return -ENOMEM;
4898 }
4899
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4901
Douglas Gilbert773642d2016-04-25 12:16:28 -04004902 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004904 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4905 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004906 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 error = -ENOMEM;
4908 goto clean;
4909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 }
4911
4912 spin_lock(&sdebug_host_list_lock);
4913 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4914 spin_unlock(&sdebug_host_list_lock);
4915
4916 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004917 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004919 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920
4921 error = device_register(&sdbg_host->dev);
4922
4923 if (error)
4924 goto clean;
4925
Douglas Gilbert773642d2016-04-25 12:16:28 -04004926 ++sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 return error;
4928
4929clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004930 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4931 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 list_del(&sdbg_devinfo->dev_list);
4933 kfree(sdbg_devinfo);
4934 }
4935
4936 kfree(sdbg_host);
4937 return error;
4938}
4939
4940static void sdebug_remove_adapter(void)
4941{
4942 struct sdebug_host_info * sdbg_host = NULL;
4943
4944 spin_lock(&sdebug_host_list_lock);
4945 if (!list_empty(&sdebug_host_list)) {
4946 sdbg_host = list_entry(sdebug_host_list.prev,
4947 struct sdebug_host_info, host_list);
4948 list_del(&sdbg_host->host_list);
4949 }
4950 spin_unlock(&sdebug_host_list_lock);
4951
4952 if (!sdbg_host)
4953 return;
4954
Douglas Gilbert773642d2016-04-25 12:16:28 -04004955 device_unregister(&sdbg_host->dev);
4956 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957}
4958
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004959static int
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004960sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004961{
4962 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004963 unsigned long iflags;
4964 struct sdebug_dev_info *devip;
4965
4966 spin_lock_irqsave(&queued_arr_lock, iflags);
4967 devip = (struct sdebug_dev_info *)sdev->hostdata;
4968 if (NULL == devip) {
4969 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4970 return -ENODEV;
4971 }
4972 num_in_q = atomic_read(&devip->num_in_q);
4973 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004974
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004975 if (qdepth < 1)
4976 qdepth = 1;
4977 /* allow to exceed max host queued_arr elements for testing */
4978 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4979 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004980 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004981
Douglas Gilbert773642d2016-04-25 12:16:28 -04004982 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004983 sdev_printk(KERN_INFO, sdev,
4984 "%s: qdepth=%d, num_in_q=%d\n",
4985 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004986 }
4987 return sdev->queue_depth;
4988}
4989
4990static int
Douglas Gilbert817fd662014-11-24 20:18:02 -05004991check_inject(struct scsi_cmnd *scp)
4992{
4993 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4994
4995 memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4996
Douglas Gilbert773642d2016-04-25 12:16:28 -04004997 if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
Douglas Gilbert817fd662014-11-24 20:18:02 -05004998 atomic_set(&sdebug_cmnd_count, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004999 if (sdebug_every_nth < -1)
5000 sdebug_every_nth = -1;
5001 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005002 return 1; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005003 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005004 scsi_medium_access_command(scp))
5005 return 1; /* time out reads and writes */
5006 if (sdebug_any_injecting_opt) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005007 if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005008 ep->inj_recovered = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005009 if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005010 ep->inj_transport = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005011 if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005012 ep->inj_dif = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005013 if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005014 ep->inj_dix = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005015 if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005016 ep->inj_short = true;
5017 }
5018 }
5019 return 0;
5020}
5021
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005022static int
Douglas Gilbert185dd232016-04-25 12:16:29 -04005023scsi_debug_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005024{
5025 u8 sdeb_i;
5026 struct scsi_device *sdp = scp->device;
5027 const struct opcode_info_t *oip;
5028 const struct opcode_info_t *r_oip;
5029 struct sdebug_dev_info *devip;
5030 u8 *cmd = scp->cmnd;
5031 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5032 int k, na;
5033 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005034 u32 flags;
5035 u16 sa;
5036 u8 opcode = cmd[0];
5037 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005038
5039 scsi_set_resid(scp, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005040 if (sdebug_verbose && !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005041 char b[120];
5042 int n, len, sb;
5043
5044 len = scp->cmd_len;
5045 sb = (int)sizeof(b);
5046 if (len > 32)
5047 strcpy(b, "too long, over 32 bytes");
5048 else {
5049 for (k = 0, n = 0; k < len && n < sb; ++k)
5050 n += scnprintf(b + n, sb - n, "%02x ",
5051 (u32)cmd[k]);
5052 }
5053 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
5054 }
Tomas Winkler34d55432015-07-28 16:54:21 +03005055 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005056 if ((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)
5057 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005058
5059 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5060 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5061 devip = (struct sdebug_dev_info *)sdp->hostdata;
5062 if (!devip) {
5063 devip = devInfoReg(sdp);
5064 if (NULL == devip)
Douglas Gilbert773642d2016-04-25 12:16:28 -04005065 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16,
5066 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005067 }
5068 na = oip->num_attached;
5069 r_pfp = oip->pfp;
5070 if (na) { /* multiple commands with this opcode */
5071 r_oip = oip;
5072 if (FF_SA & r_oip->flags) {
5073 if (F_SA_LOW & oip->flags)
5074 sa = 0x1f & cmd[1];
5075 else
5076 sa = get_unaligned_be16(cmd + 8);
5077 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5078 if (opcode == oip->opcode && sa == oip->sa)
5079 break;
5080 }
5081 } else { /* since no service action only check opcode */
5082 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5083 if (opcode == oip->opcode)
5084 break;
5085 }
5086 }
5087 if (k > na) {
5088 if (F_SA_LOW & r_oip->flags)
5089 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5090 else if (F_SA_HIGH & r_oip->flags)
5091 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5092 else
5093 mk_sense_invalid_opcode(scp);
5094 goto check_cond;
5095 }
5096 } /* else (when na==0) we assume the oip is a match */
5097 flags = oip->flags;
5098 if (F_INV_OP & flags) {
5099 mk_sense_invalid_opcode(scp);
5100 goto check_cond;
5101 }
5102 if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005103 if (sdebug_verbose)
5104 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5105 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005106 mk_sense_invalid_opcode(scp);
5107 goto check_cond;
5108 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005109 if (sdebug_strict) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005110 u8 rem;
5111 int j;
5112
5113 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5114 rem = ~oip->len_mask[k] & cmd[k];
5115 if (rem) {
5116 for (j = 7; j >= 0; --j, rem <<= 1) {
5117 if (0x80 & rem)
5118 break;
5119 }
5120 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5121 goto check_cond;
5122 }
5123 }
5124 }
5125 if (!(F_SKIP_UA & flags) &&
5126 SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) {
5127 errsts = check_readiness(scp, UAS_ONLY, devip);
5128 if (errsts)
5129 goto check_cond;
5130 }
5131 if ((F_M_ACCESS & flags) && devip->stopped) {
5132 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005133 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005134 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5135 "%s\n", my_name, "initializing command "
5136 "required");
5137 errsts = check_condition_result;
5138 goto fini;
5139 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005140 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005141 goto fini;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005142 if (sdebug_every_nth) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005143 if (check_inject(scp))
5144 return 0; /* ignore command: make trouble */
5145 }
5146 if (oip->pfp) /* if this command has a resp_* function, call it */
5147 errsts = oip->pfp(scp, devip);
5148 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5149 errsts = r_pfp(scp, devip);
5150
5151fini:
5152 return schedule_resp(scp, devip, errsts,
Douglas Gilbert773642d2016-04-25 12:16:28 -04005153 ((F_DELAY_OVERR & flags) ? 0 : sdebug_delay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005154check_cond:
5155 return schedule_resp(scp, devip, check_condition_result, 0);
5156}
5157
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005158static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005159 .show_info = scsi_debug_show_info,
5160 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005161 .proc_name = sdebug_proc_name,
5162 .name = "SCSI DEBUG",
5163 .info = scsi_debug_info,
5164 .slave_alloc = scsi_debug_slave_alloc,
5165 .slave_configure = scsi_debug_slave_configure,
5166 .slave_destroy = scsi_debug_slave_destroy,
5167 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005168 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005169 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005170 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005171 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005172 .eh_target_reset_handler = scsi_debug_target_reset,
5173 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005174 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005175 .can_queue = SCSI_DEBUG_CANQUEUE,
5176 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005177 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005178 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005179 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005180 .use_clustering = DISABLE_CLUSTERING,
5181 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005182 .track_queue_depth = 1,
Douglas Gilbert817fd662014-11-24 20:18:02 -05005183 .cmd_size = sizeof(struct sdebug_scmd_extra_t),
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005184};
5185
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186static int sdebug_driver_probe(struct device * dev)
5187{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005188 int error = 0;
5189 struct sdebug_host_info *sdbg_host;
5190 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005191 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192
5193 sdbg_host = to_sdebug_host(dev);
5194
Douglas Gilbert773642d2016-04-25 12:16:28 -04005195 sdebug_driver_template.can_queue = sdebug_max_queue;
5196 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005197 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005198 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5199 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005200 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005201 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204
5205 sdbg_host->shost = hpnt;
5206 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005207 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5208 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005210 hpnt->max_id = sdebug_num_tgts;
5211 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005212 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005214 host_prot = 0;
5215
Douglas Gilbert773642d2016-04-25 12:16:28 -04005216 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005217
5218 case SD_DIF_TYPE1_PROTECTION:
5219 host_prot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005220 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005221 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
5222 break;
5223
5224 case SD_DIF_TYPE2_PROTECTION:
5225 host_prot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005226 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005227 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
5228 break;
5229
5230 case SD_DIF_TYPE3_PROTECTION:
5231 host_prot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005232 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005233 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
5234 break;
5235
5236 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005237 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005238 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
5239 break;
5240 }
5241
5242 scsi_host_set_prot(hpnt, host_prot);
5243
Tomas Winklerc12879702015-07-28 16:54:20 +03005244 pr_info("host protection%s%s%s%s%s%s%s\n",
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005245 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5246 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5247 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5248 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5249 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5250 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5251 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5252
Douglas Gilbert773642d2016-04-25 12:16:28 -04005253 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005254 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5255 else
5256 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5257
Douglas Gilbert773642d2016-04-25 12:16:28 -04005258 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5259 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 error = scsi_add_host(hpnt, &sdbg_host->dev);
5261 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005262 pr_err("scsi_add_host failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 error = -ENODEV;
5264 scsi_host_put(hpnt);
5265 } else
5266 scsi_scan_host(hpnt);
5267
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005268 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269}
5270
5271static int sdebug_driver_remove(struct device * dev)
5272{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005274 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275
5276 sdbg_host = to_sdebug_host(dev);
5277
5278 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005279 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 return -ENODEV;
5281 }
5282
5283 scsi_remove_host(sdbg_host->shost);
5284
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005285 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5286 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 list_del(&sdbg_devinfo->dev_list);
5288 kfree(sdbg_devinfo);
5289 }
5290
5291 scsi_host_put(sdbg_host->shost);
5292 return 0;
5293}
5294
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005295static int pseudo_lld_bus_match(struct device *dev,
5296 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005298 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005300
5301static struct bus_type pseudo_lld_bus = {
5302 .name = "pseudo",
5303 .match = pseudo_lld_bus_match,
5304 .probe = sdebug_driver_probe,
5305 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005306 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005307};