blob: 90cd62e03337b15cb82fdd08ec64a288ec63ae01 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
Douglas Gilbert773642d2016-04-25 12:16:28 -04009 * Copyright (C) 2001 - 2016 Douglas Gilbert
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Douglas Gilbert773642d2016-04-25 12:16:28 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040016 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
19
Tomas Winklerc12879702015-07-28 16:54:20 +030020
21#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/errno.h>
Douglas Gilbertb333a812016-04-25 12:16:30 -040027#include <linux/jiffies.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/types.h>
30#include <linux/string.h>
31#include <linux/genhd.h>
32#include <linux/fs.h>
33#include <linux/init.h>
34#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/vmalloc.h>
36#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020037#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050039#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040040#include <linux/spinlock.h>
41#include <linux/interrupt.h>
42#include <linux/atomic.h>
43#include <linux/hrtimer.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050044
45#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090046
Martin K. Petersen44d92692009-10-15 14:45:27 -040047#include <asm/unaligned.h>
48
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090049#include <scsi/scsi.h>
50#include <scsi/scsi_cmnd.h>
51#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <scsi/scsi_host.h>
53#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090054#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040055#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040056#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Martin K. Petersenc6a44282009-01-04 03:08:19 -050058#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Douglas Gilbert773642d2016-04-25 12:16:28 -040061/* make sure inq_product_rev string corresponds to this version */
62#define SCSI_DEBUG_VERSION "1.86"
63static const char *sdebug_version_date = "20160422";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040064
65#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050067/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040068#define NO_ADDITIONAL_SENSE 0x0
69#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050070#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040072#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050074#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040076#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040077#define UA_RESET_ASC 0x29
78#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050079#define TARGET_CHANGED_ASC 0x3f
80#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050081#define INSUFF_RES_ASC 0x55
82#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040083#define POWER_ON_RESET_ASCQ 0x0
84#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
85#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050086#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070087#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050088#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040089#define THRESHOLD_EXCEEDED 0x5d
90#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050091#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050092#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
93#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050095/* Additional Sense Code Qualifier (ASCQ) */
96#define ACK_NAK_TO 0x3
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99/* Default values for driver parameters */
100#define DEF_NUM_HOST 1
101#define DEF_NUM_TGTS 1
102#define DEF_MAX_LUNS 1
103/* With these defaults, this driver will make 1 host with 1 target
104 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
105 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500106#define DEF_ATO 1
Douglas 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;
Douglas Gilbertb333a812016-04-25 12:16:30 -0400521static int sdebug_delay = DEF_DELAY; /* in jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400522static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
523static int sdebug_dif = DEF_DIF;
524static int sdebug_dix = DEF_DIX;
525static int sdebug_dsense = DEF_D_SENSE;
526static int sdebug_every_nth = DEF_EVERY_NTH;
527static int sdebug_fake_rw = DEF_FAKE_RW;
528static unsigned int sdebug_guard = DEF_GUARD;
529static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
530static int sdebug_max_luns = DEF_MAX_LUNS;
531static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400532static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertb333a812016-04-25 12:16:30 -0400533static int sdebug_ndelay = DEF_NDELAY; /* in nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400534static int sdebug_no_lun_0 = DEF_NO_LUN_0;
535static int sdebug_no_uld;
536static int sdebug_num_parts = DEF_NUM_PARTS;
537static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
538static int sdebug_opt_blks = DEF_OPT_BLKS;
539static int sdebug_opts = DEF_OPTS;
540static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
541static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
542static int sdebug_scsi_level = DEF_SCSI_LEVEL;
543static int sdebug_sector_size = DEF_SECTOR_SIZE;
544static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
545static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
546static unsigned int sdebug_lbpu = DEF_LBPU;
547static unsigned int sdebug_lbpws = DEF_LBPWS;
548static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
549static unsigned int sdebug_lbprz = DEF_LBPRZ;
550static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
551static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
552static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
553static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
554static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
555static bool sdebug_removable = DEF_REMOVABLE;
556static bool sdebug_clustering;
557static bool sdebug_host_lock = DEF_HOST_LOCK;
558static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500559static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400560static bool sdebug_verbose;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400562static atomic_t sdebug_cmnd_count;
563static atomic_t sdebug_completions;
564static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566#define DEV_READONLY(TGT) (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400568static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569static sector_t sdebug_capacity; /* in sectors */
570
571/* old BIOS stuff, kernel may get rid of them but some mode sense pages
572 may still need them */
573static int sdebug_heads; /* heads per disk */
574static int sdebug_cylinders_per; /* cylinders per surface */
575static int sdebug_sectors_per; /* sectors per cylinder */
576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577#define SDEBUG_MAX_PARTS 4
578
Martin K. Petersen395cef02009-09-18 17:33:03 -0400579#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900580
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500581static unsigned int scsi_debug_lbp(void)
582{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400583 return 0 == sdebug_fake_rw &&
584 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500585}
586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587struct sdebug_dev_info {
588 struct list_head dev_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 unsigned int channel;
590 unsigned int target;
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200591 u64 lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400593 unsigned long uas_bm[1];
594 atomic_t num_in_q;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500595 char stopped; /* TODO: should be atomic */
596 bool used;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597};
598
599struct sdebug_host_info {
600 struct list_head host_list;
601 struct Scsi_Host *shost;
602 struct device dev;
603 struct list_head dev_info_list;
604};
605
606#define to_sdebug_host(d) \
607 container_of(d, struct sdebug_host_info, dev)
608
609static LIST_HEAD(sdebug_host_list);
610static DEFINE_SPINLOCK(sdebug_host_list_lock);
611
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400612
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[] */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400620 struct tasklet_struct *tletp;
621 struct sdebug_hrtimer *sd_hrtp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 struct scsi_cmnd * a_cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623};
624static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400625static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628static unsigned char * fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900629static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400630static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Martin K. Petersen44d92692009-10-15 14:45:27 -0400632static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400633static int num_aborts;
634static int num_dev_resets;
635static int num_target_resets;
636static int num_bus_resets;
637static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500638static int dix_writes;
639static int dix_reads;
640static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642static DEFINE_SPINLOCK(queued_arr_lock);
643static DEFINE_RWLOCK(atomic_rw);
644
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400645static char sdebug_proc_name[] = MY_NAME;
646static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648static struct bus_type pseudo_lld_bus;
649
650static struct device_driver sdebug_driverfs_driver = {
651 .name = sdebug_proc_name,
652 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653};
654
655static const int check_condition_result =
656 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
657
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500658static const int illegal_condition_result =
659 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
660
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400661static const int device_qfull_result =
662 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
663
664static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
665 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
666 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400667static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
668 0, 0, 0x2, 0x4b};
669static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
670 0, 0, 0x0, 0x0};
671
Akinobu Mita14faa942013-09-18 21:27:24 +0900672static void *fake_store(unsigned long long lba)
673{
674 lba = do_div(lba, sdebug_store_sectors);
675
Douglas Gilbert773642d2016-04-25 12:16:28 -0400676 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900677}
678
679static struct sd_dif_tuple *dif_store(sector_t sector)
680{
Arnd Bergmann49413112015-11-20 17:38:28 +0100681 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900682
683 return dif_storep + sector;
684}
685
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686static int sdebug_add_adapter(void);
687static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900689static void sdebug_max_tgts_luns(void)
690{
691 struct sdebug_host_info *sdbg_host;
692 struct Scsi_Host *hpnt;
693
694 spin_lock(&sdebug_host_list_lock);
695 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
696 hpnt = sdbg_host->shost;
697 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400698 (sdebug_num_tgts > hpnt->this_id))
699 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900700 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400701 hpnt->max_id = sdebug_num_tgts;
702 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300703 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900704 }
705 spin_unlock(&sdebug_host_list_lock);
706}
707
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500708enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
709
710/* Set in_bit to -1 to indicate no bit position of invalid field */
711static void
712mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d,
713 int in_byte, int in_bit)
714{
715 unsigned char *sbuff;
716 u8 sks[4];
717 int sl, asc;
718
719 sbuff = scp->sense_buffer;
720 if (!sbuff) {
721 sdev_printk(KERN_ERR, scp->device,
722 "%s: sense_buffer is NULL\n", __func__);
723 return;
724 }
725 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
726 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400727 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500728 memset(sks, 0, sizeof(sks));
729 sks[0] = 0x80;
730 if (c_d)
731 sks[0] |= 0x40;
732 if (in_bit >= 0) {
733 sks[0] |= 0x8;
734 sks[0] |= 0x7 & in_bit;
735 }
736 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400737 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500738 sl = sbuff[7] + 8;
739 sbuff[7] = sl;
740 sbuff[sl] = 0x2;
741 sbuff[sl + 1] = 0x6;
742 memcpy(sbuff + sl + 4, sks, 3);
743 } else
744 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400745 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500746 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
747 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
748 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
749}
750
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400751static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900752{
753 unsigned char *sbuff;
754
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400755 sbuff = scp->sense_buffer;
756 if (!sbuff) {
757 sdev_printk(KERN_ERR, scp->device,
758 "%s: sense_buffer is NULL\n", __func__);
759 return;
760 }
761 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900762
Douglas Gilbert773642d2016-04-25 12:16:28 -0400763 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900764
Douglas Gilbert773642d2016-04-25 12:16:28 -0400765 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400766 sdev_printk(KERN_INFO, scp->device,
767 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
768 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900769}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500771static void
772mk_sense_invalid_opcode(struct scsi_cmnd *scp)
773{
774 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
775}
776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
778{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400779 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400780 if (0x1261 == cmd)
781 sdev_printk(KERN_INFO, dev,
782 "%s: BLKFLSBUF [0x1261]\n", __func__);
783 else if (0x5331 == cmd)
784 sdev_printk(KERN_INFO, dev,
785 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
786 __func__);
787 else
788 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
789 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791 return -EINVAL;
792 /* return -ENOTTY; // correct return but upsets fdisk */
793}
794
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500795static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
796{
797 struct sdebug_host_info *sdhp;
798 struct sdebug_dev_info *dp;
799
800 spin_lock(&sdebug_host_list_lock);
801 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
802 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
803 if ((devip->sdbg_host == dp->sdbg_host) &&
804 (devip->target == dp->target))
805 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
806 }
807 }
808 spin_unlock(&sdebug_host_list_lock);
809}
810
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400811static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400812 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400814 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400815
816 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
817 if (k != SDEBUG_NUM_UAS) {
818 const char *cp = NULL;
819
820 switch (k) {
821 case SDEBUG_UA_POR:
822 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
823 UA_RESET_ASC, POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400824 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400825 cp = "power on reset";
826 break;
827 case SDEBUG_UA_BUS_RESET:
828 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
829 UA_RESET_ASC, BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400830 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400831 cp = "bus reset";
832 break;
833 case SDEBUG_UA_MODE_CHANGED:
834 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
835 UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400836 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400837 cp = "mode parameters changed";
838 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500839 case SDEBUG_UA_CAPACITY_CHANGED:
840 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
841 UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400842 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500843 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500844 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500845 case SDEBUG_UA_MICROCODE_CHANGED:
846 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
847 TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400848 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500849 cp = "microcode has been changed";
850 break;
851 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
852 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
853 TARGET_CHANGED_ASC,
854 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400855 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500856 cp = "microcode has been changed without reset";
857 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500858 case SDEBUG_UA_LUNS_CHANGED:
859 /*
860 * SPC-3 behavior is to report a UNIT ATTENTION with
861 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
862 * on the target, until a REPORT LUNS command is
863 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400864 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500865 * values as struct scsi_device->scsi_level.
866 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400867 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500868 clear_luns_changed_on_target(devip);
869 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
870 TARGET_CHANGED_ASC,
871 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400872 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500873 cp = "reported luns data has changed";
874 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400875 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400876 pr_warn("unexpected unit attention code=%d\n", k);
877 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400878 cp = "unknown";
879 break;
880 }
881 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400882 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400883 sdev_printk(KERN_INFO, SCpnt->device,
884 "%s reports: Unit attention: %s\n",
885 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return check_condition_result;
887 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400888 if ((UAS_TUR == uas_only) && devip->stopped) {
889 mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400890 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400891 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400892 sdev_printk(KERN_INFO, SCpnt->device,
893 "%s reports: Not ready: %s\n", my_name,
894 "initializing command required");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400895 return check_condition_result;
896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return 0;
898}
899
900/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900901static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 int arr_len)
903{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900904 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900905 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900907 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900909 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400910 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900911
912 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
913 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700914 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 return 0;
917}
918
919/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900920static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
921 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900923 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900925 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900927
928 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929}
930
931
932static const char * inq_vendor_id = "Linux ";
933static const char * inq_product_id = "scsi_debug ";
Douglas Gilbert773642d2016-04-25 12:16:28 -0400934static const char *inq_product_rev = "0186"; /* version less '.' */
935static const u64 naa5_comp_a = 0x5222222000000000ULL;
936static const u64 naa5_comp_b = 0x5333333000000000ULL;
937static const u64 naa5_comp_c = 0x5111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400939/* Device identification VPD page. Returns number of bytes placed in arr */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200940static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
941 int target_dev_id, int dev_id_num,
942 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400943 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400945 int num, port_a;
946 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400948 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 /* T10 vendor identifier field format (faked) */
950 arr[0] = 0x2; /* ASCII */
951 arr[1] = 0x1;
952 arr[2] = 0x0;
953 memcpy(&arr[4], inq_vendor_id, 8);
954 memcpy(&arr[12], inq_product_id, 16);
955 memcpy(&arr[28], dev_id_str, dev_id_str_len);
956 num = 8 + 16 + dev_id_str_len;
957 arr[3] = num;
958 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400959 if (dev_id_num >= 0) {
960 /* NAA-5, Logical unit identifier (binary) */
961 arr[num++] = 0x1; /* binary (not necessarily sas) */
962 arr[num++] = 0x3; /* PIV=0, lu, naa */
963 arr[num++] = 0x0;
964 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400965 put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
966 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400967 /* Target relative port number */
968 arr[num++] = 0x61; /* proto=sas, binary */
969 arr[num++] = 0x94; /* PIV=1, target port, rel port */
970 arr[num++] = 0x0; /* reserved */
971 arr[num++] = 0x4; /* length */
972 arr[num++] = 0x0; /* reserved */
973 arr[num++] = 0x0; /* reserved */
974 arr[num++] = 0x0;
975 arr[num++] = 0x1; /* relative port A */
976 }
977 /* NAA-5, Target port identifier */
978 arr[num++] = 0x61; /* proto=sas, binary */
979 arr[num++] = 0x93; /* piv=1, target port, naa */
980 arr[num++] = 0x0;
981 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400982 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
983 num += 8;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200984 /* NAA-5, Target port group identifier */
985 arr[num++] = 0x61; /* proto=sas, binary */
986 arr[num++] = 0x95; /* piv=1, target port group id */
987 arr[num++] = 0x0;
988 arr[num++] = 0x4;
989 arr[num++] = 0;
990 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400991 put_unaligned_be16(port_group_id, arr + num);
992 num += 2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400993 /* NAA-5, Target device identifier */
994 arr[num++] = 0x61; /* proto=sas, binary */
995 arr[num++] = 0xa3; /* piv=1, target device, naa */
996 arr[num++] = 0x0;
997 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400998 put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
999 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001000 /* SCSI name string: Target device identifier */
1001 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1002 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1003 arr[num++] = 0x0;
1004 arr[num++] = 24;
1005 memcpy(arr + num, "naa.52222220", 12);
1006 num += 12;
1007 snprintf(b, sizeof(b), "%08X", target_dev_id);
1008 memcpy(arr + num, b, 8);
1009 num += 8;
1010 memset(arr + num, 0, 4);
1011 num += 4;
1012 return num;
1013}
1014
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001015static unsigned char vpd84_data[] = {
1016/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1017 0x22,0x22,0x22,0x0,0xbb,0x1,
1018 0x22,0x22,0x22,0x0,0xbb,0x2,
1019};
1020
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001021/* Software interface identification VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001022static int inquiry_evpd_84(unsigned char * arr)
1023{
1024 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1025 return sizeof(vpd84_data);
1026}
1027
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001028/* Management network addresses VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001029static int inquiry_evpd_85(unsigned char * arr)
1030{
1031 int num = 0;
1032 const char * na1 = "https://www.kernel.org/config";
1033 const char * na2 = "http://www.kernel.org/log";
1034 int plen, olen;
1035
1036 arr[num++] = 0x1; /* lu, storage config */
1037 arr[num++] = 0x0; /* reserved */
1038 arr[num++] = 0x0;
1039 olen = strlen(na1);
1040 plen = olen + 1;
1041 if (plen % 4)
1042 plen = ((plen / 4) + 1) * 4;
1043 arr[num++] = plen; /* length, null termianted, padded */
1044 memcpy(arr + num, na1, olen);
1045 memset(arr + num + olen, 0, plen - olen);
1046 num += plen;
1047
1048 arr[num++] = 0x4; /* lu, logging */
1049 arr[num++] = 0x0; /* reserved */
1050 arr[num++] = 0x0;
1051 olen = strlen(na2);
1052 plen = olen + 1;
1053 if (plen % 4)
1054 plen = ((plen / 4) + 1) * 4;
1055 arr[num++] = plen; /* length, null terminated, padded */
1056 memcpy(arr + num, na2, olen);
1057 memset(arr + num + olen, 0, plen - olen);
1058 num += plen;
1059
1060 return num;
1061}
1062
1063/* SCSI ports VPD page */
1064static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1065{
1066 int num = 0;
1067 int port_a, port_b;
1068
1069 port_a = target_dev_id + 1;
1070 port_b = port_a + 1;
1071 arr[num++] = 0x0; /* reserved */
1072 arr[num++] = 0x0; /* reserved */
1073 arr[num++] = 0x0;
1074 arr[num++] = 0x1; /* relative port 1 (primary) */
1075 memset(arr + num, 0, 6);
1076 num += 6;
1077 arr[num++] = 0x0;
1078 arr[num++] = 12; /* length tp descriptor */
1079 /* naa-5 target port identifier (A) */
1080 arr[num++] = 0x61; /* proto=sas, binary */
1081 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1082 arr[num++] = 0x0; /* reserved */
1083 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001084 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1085 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001086 arr[num++] = 0x0; /* reserved */
1087 arr[num++] = 0x0; /* reserved */
1088 arr[num++] = 0x0;
1089 arr[num++] = 0x2; /* relative port 2 (secondary) */
1090 memset(arr + num, 0, 6);
1091 num += 6;
1092 arr[num++] = 0x0;
1093 arr[num++] = 12; /* length tp descriptor */
1094 /* naa-5 target port identifier (B) */
1095 arr[num++] = 0x61; /* proto=sas, binary */
1096 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1097 arr[num++] = 0x0; /* reserved */
1098 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001099 put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1100 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001101
1102 return num;
1103}
1104
1105
1106static unsigned char vpd89_data[] = {
1107/* from 4th byte */ 0,0,0,0,
1108'l','i','n','u','x',' ',' ',' ',
1109'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1110'1','2','3','4',
11110x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
11120xec,0,0,0,
11130x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
11140,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
11150x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
11160x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
11170x53,0x41,
11180x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11190x20,0x20,
11200x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11210x10,0x80,
11220,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
11230x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
11240x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
11250,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
11260x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
11270x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
11280,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
11290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11320x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
11330,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
11340xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
11350,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
11360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11370,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11380,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11420,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11450,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11470,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1148};
1149
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001150/* ATA Information VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001151static int inquiry_evpd_89(unsigned char * arr)
1152{
1153 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1154 return sizeof(vpd89_data);
1155}
1156
1157
1158static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001159 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1160 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1161 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1162 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001163};
1164
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001165/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001166static int inquiry_evpd_b0(unsigned char * arr)
1167{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001168 unsigned int gran;
1169
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001170 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001171
1172 /* Optimal transfer length granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001173 gran = 1 << sdebug_physblk_exp;
1174 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001175
1176 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001177 if (sdebug_store_sectors > 0x400)
1178 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001179
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001180 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001181 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001182
Douglas Gilbert773642d2016-04-25 12:16:28 -04001183 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001184 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001185 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001186
1187 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001188 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001189 }
1190
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001191 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001192 if (sdebug_unmap_alignment) {
1193 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001194 arr[28] |= 0x80; /* UGAVALID */
1195 }
1196
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001197 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001198 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001199
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001200 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001201 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001202
1203 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001204
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001205 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206}
1207
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001208/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001209static int inquiry_evpd_b1(unsigned char *arr)
1210{
1211 memset(arr, 0, 0x3c);
1212 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001213 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1214 arr[2] = 0;
1215 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001216
1217 return 0x3c;
1218}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001220/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001221static int inquiry_evpd_b2(unsigned char *arr)
1222{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001223 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001224 arr[0] = 0; /* threshold exponent */
1225
Douglas Gilbert773642d2016-04-25 12:16:28 -04001226 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001227 arr[1] = 1 << 7;
1228
Douglas Gilbert773642d2016-04-25 12:16:28 -04001229 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001230 arr[1] |= 1 << 6;
1231
Douglas Gilbert773642d2016-04-25 12:16:28 -04001232 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001233 arr[1] |= 1 << 5;
1234
Douglas Gilbert773642d2016-04-25 12:16:28 -04001235 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001236 arr[1] |= 1 << 2;
1237
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001238 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001239}
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001242#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001244static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245{
1246 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001247 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001248 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001249 int alloc_len, n, ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001250 bool have_wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Douglas Gilbert773642d2016-04-25 12:16:28 -04001252 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001253 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1254 if (! arr)
1255 return DID_REQUEUE << 16;
Tomas Winkler34d55432015-07-28 16:54:21 +03001256 have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001257 if (have_wlun)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001258 pq_pdt = 0x1e; /* present, wlun */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001259 else if (sdebug_no_lun_0 && (0 == devip->lun))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001260 pq_pdt = 0x7f; /* not present, no device type */
1261 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001262 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 arr[0] = pq_pdt;
1264 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001265 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001266 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 return check_condition_result;
1268 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001269 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001270 char lu_id_str[6];
1271 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001273 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1274 (devip->channel & 0x7f);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001275 if (0 == sdebug_vpd_use_hostno)
Douglas Gilbert23183912006-09-16 20:30:47 -04001276 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001277 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001278 (devip->target * 1000) + devip->lun);
1279 target_dev_id = ((host_no + 1) * 2000) +
1280 (devip->target * 1000) - 3;
1281 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001283 arr[1] = cmd[2]; /*sanity */
1284 n = 4;
1285 arr[n++] = 0x0; /* this page */
1286 arr[n++] = 0x80; /* unit serial number */
1287 arr[n++] = 0x83; /* device identification */
1288 arr[n++] = 0x84; /* software interface ident. */
1289 arr[n++] = 0x85; /* management network addresses */
1290 arr[n++] = 0x86; /* extended inquiry */
1291 arr[n++] = 0x87; /* mode page policy */
1292 arr[n++] = 0x88; /* SCSI ports */
1293 arr[n++] = 0x89; /* ATA information */
1294 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001295 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001296 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
1297 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001298 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001300 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001302 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001304 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001305 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1306 target_dev_id, lu_id_num,
1307 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001308 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1309 arr[1] = cmd[2]; /*sanity */
1310 arr[3] = inquiry_evpd_84(&arr[4]);
1311 } else if (0x85 == cmd[2]) { /* Management network addresses */
1312 arr[1] = cmd[2]; /*sanity */
1313 arr[3] = inquiry_evpd_85(&arr[4]);
1314 } else if (0x86 == cmd[2]) { /* extended inquiry */
1315 arr[1] = cmd[2]; /*sanity */
1316 arr[3] = 0x3c; /* number of following entries */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001317 if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001318 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001319 else if (sdebug_dif)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001320 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1321 else
1322 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001323 arr[5] = 0x7; /* head of q, ordered + simple q's */
1324 } else if (0x87 == cmd[2]) { /* mode page policy */
1325 arr[1] = cmd[2]; /*sanity */
1326 arr[3] = 0x8; /* number of following entries */
1327 arr[4] = 0x2; /* disconnect-reconnect mp */
1328 arr[6] = 0x80; /* mlus, shared */
1329 arr[8] = 0x18; /* protocol specific lu */
1330 arr[10] = 0x82; /* mlus, per initiator port */
1331 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1332 arr[1] = cmd[2]; /*sanity */
1333 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1334 } else if (0x89 == cmd[2]) { /* ATA information */
1335 arr[1] = cmd[2]; /*sanity */
1336 n = inquiry_evpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001337 put_unaligned_be16(n, arr + 2);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001338 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1339 arr[1] = cmd[2]; /*sanity */
1340 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001341 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1342 arr[1] = cmd[2]; /*sanity */
1343 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001344 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001345 arr[1] = cmd[2]; /*sanity */
1346 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001348 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001349 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 return check_condition_result;
1351 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001352 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001353 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001354 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001355 kfree(arr);
1356 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 }
1358 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001359 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1360 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 arr[3] = 2; /* response_data_format==2 */
1362 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001363 arr[5] = sdebug_dif ? 1 : 0; /* PROTECT bit */
1364 if (0 == sdebug_vpd_use_hostno)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001365 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001366 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001368 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 memcpy(&arr[8], inq_vendor_id, 8);
1370 memcpy(&arr[16], inq_product_id, 16);
1371 memcpy(&arr[32], inq_product_rev, 4);
1372 /* version descriptors (2 bytes each) follow */
Douglas Gilberte46b0342014-08-05 12:21:53 +02001373 arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */
1374 arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001375 n = 62;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001376 if (sdebug_ptype == 0) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001377 arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001378 } else if (sdebug_ptype == 1) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001379 arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
Douglas Gilberte46b0342014-08-05 12:21:53 +02001381 arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001382 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001384 kfree(arr);
1385 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386}
1387
1388static int resp_requests(struct scsi_cmnd * scp,
1389 struct sdebug_dev_info * devip)
1390{
1391 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001392 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001393 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001394 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 int len = 18;
1396
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001397 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001398 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001399 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001400 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001401 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001402 arr[0] = 0x72;
1403 arr[1] = 0x0; /* NO_SENSE in sense_key */
1404 arr[2] = THRESHOLD_EXCEEDED;
1405 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001406 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001407 } else {
1408 arr[0] = 0x70;
1409 arr[2] = 0x0; /* NO_SENSE in sense_key */
1410 arr[7] = 0xa; /* 18 byte sense buffer */
1411 arr[12] = THRESHOLD_EXCEEDED;
1412 arr[13] = 0xff; /* TEST set and MRIE==6 */
1413 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001414 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001415 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001416 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001417 ; /* have sense and formats match */
1418 else if (arr[0] <= 0x70) {
1419 if (dsense) {
1420 memset(arr, 0, 8);
1421 arr[0] = 0x72;
1422 len = 8;
1423 } else {
1424 memset(arr, 0, 18);
1425 arr[0] = 0x70;
1426 arr[7] = 0xa;
1427 }
1428 } else if (dsense) {
1429 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001430 arr[0] = 0x72;
1431 arr[1] = sbuff[2]; /* sense key */
1432 arr[2] = sbuff[12]; /* asc */
1433 arr[3] = sbuff[13]; /* ascq */
1434 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001435 } else {
1436 memset(arr, 0, 18);
1437 arr[0] = 0x70;
1438 arr[2] = sbuff[1];
1439 arr[7] = 0xa;
1440 arr[12] = sbuff[1];
1441 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001442 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001443
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001444 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001445 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 return fill_from_dev_buffer(scp, arr, len);
1447}
1448
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001449static int resp_start_stop(struct scsi_cmnd * scp,
1450 struct sdebug_dev_info * devip)
1451{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001452 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001453 int power_cond, start;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001454
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001455 power_cond = (cmd[4] & 0xf0) >> 4;
1456 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001457 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001458 return check_condition_result;
1459 }
1460 start = cmd[4] & 1;
1461 if (start == devip->stopped)
1462 devip->stopped = !start;
1463 return 0;
1464}
1465
FUJITA Tomonori28898872008-03-30 00:59:55 +09001466static sector_t get_sdebug_capacity(void)
1467{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001468 static const unsigned int gibibyte = 1073741824;
1469
1470 if (sdebug_virtual_gb > 0)
1471 return (sector_t)sdebug_virtual_gb *
1472 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001473 else
1474 return sdebug_store_sectors;
1475}
1476
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477#define SDEBUG_READCAP_ARR_SZ 8
1478static int resp_readcap(struct scsi_cmnd * scp,
1479 struct sdebug_dev_info * devip)
1480{
1481 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001482 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001485 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001487 if (sdebug_capacity < 0xffffffff) {
1488 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001489 put_unaligned_be32(capac, arr + 0);
1490 } else
1491 put_unaligned_be32(0xffffffff, arr + 0);
1492 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1494}
1495
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496#define SDEBUG_READCAP16_ARR_SZ 32
1497static int resp_readcap16(struct scsi_cmnd * scp,
1498 struct sdebug_dev_info * devip)
1499{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001500 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001501 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001502 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001503
Douglas Gilbert773642d2016-04-25 12:16:28 -04001504 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001505 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001506 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001507 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001508 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1509 put_unaligned_be32(sdebug_sector_size, arr + 8);
1510 arr[13] = sdebug_physblk_exp & 0xf;
1511 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001512
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001513 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001514 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001515 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001516 arr[14] |= 0x40; /* LBPRZ */
1517 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001518
Douglas Gilbert773642d2016-04-25 12:16:28 -04001519 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001520
Douglas Gilbert773642d2016-04-25 12:16:28 -04001521 if (sdebug_dif) {
1522 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001523 arr[12] |= 1; /* PROT_EN */
1524 }
1525
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001526 return fill_from_dev_buffer(scp, arr,
1527 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1528}
1529
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001530#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1531
1532static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1533 struct sdebug_dev_info * devip)
1534{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001535 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001536 unsigned char * arr;
1537 int host_no = devip->sdbg_host->shost->host_no;
1538 int n, ret, alen, rlen;
1539 int port_group_a, port_group_b, port_a, port_b;
1540
Douglas Gilbert773642d2016-04-25 12:16:28 -04001541 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001542 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1543 if (! arr)
1544 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001545 /*
1546 * EVPD page 0x88 states we have two ports, one
1547 * real and a fake port with no device connected.
1548 * So we create two port groups with one port each
1549 * and set the group with port B to unavailable.
1550 */
1551 port_a = 0x1; /* relative port A */
1552 port_b = 0x2; /* relative port B */
1553 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001554 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001555 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001556 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001557
1558 /*
1559 * The asymmetric access state is cycled according to the host_id.
1560 */
1561 n = 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001562 if (0 == sdebug_vpd_use_hostno) {
1563 arr[n++] = host_no % 3; /* Asymm access state */
1564 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001565 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001566 arr[n++] = 0x0; /* Active/Optimized path */
1567 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001568 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001569 put_unaligned_be16(port_group_a, arr + n);
1570 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001571 arr[n++] = 0; /* Reserved */
1572 arr[n++] = 0; /* Status code */
1573 arr[n++] = 0; /* Vendor unique */
1574 arr[n++] = 0x1; /* One port per group */
1575 arr[n++] = 0; /* Reserved */
1576 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001577 put_unaligned_be16(port_a, arr + n);
1578 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001579 arr[n++] = 3; /* Port unavailable */
1580 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001581 put_unaligned_be16(port_group_b, arr + n);
1582 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001583 arr[n++] = 0; /* Reserved */
1584 arr[n++] = 0; /* Status code */
1585 arr[n++] = 0; /* Vendor unique */
1586 arr[n++] = 0x1; /* One port per group */
1587 arr[n++] = 0; /* Reserved */
1588 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001589 put_unaligned_be16(port_b, arr + n);
1590 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001591
1592 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001593 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001594
1595 /*
1596 * Return the smallest value of either
1597 * - The allocated length
1598 * - The constructed command length
1599 * - The maximum array size
1600 */
1601 rlen = min(alen,n);
1602 ret = fill_from_dev_buffer(scp, arr,
1603 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1604 kfree(arr);
1605 return ret;
1606}
1607
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001608static int
1609resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1610{
1611 bool rctd;
1612 u8 reporting_opts, req_opcode, sdeb_i, supp;
1613 u16 req_sa, u;
1614 u32 alloc_len, a_len;
1615 int k, offset, len, errsts, count, bump, na;
1616 const struct opcode_info_t *oip;
1617 const struct opcode_info_t *r_oip;
1618 u8 *arr;
1619 u8 *cmd = scp->cmnd;
1620
1621 rctd = !!(cmd[2] & 0x80);
1622 reporting_opts = cmd[2] & 0x7;
1623 req_opcode = cmd[3];
1624 req_sa = get_unaligned_be16(cmd + 4);
1625 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001626 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001627 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1628 return check_condition_result;
1629 }
1630 if (alloc_len > 8192)
1631 a_len = 8192;
1632 else
1633 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001634 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001635 if (NULL == arr) {
1636 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1637 INSUFF_RES_ASCQ);
1638 return check_condition_result;
1639 }
1640 switch (reporting_opts) {
1641 case 0: /* all commands */
1642 /* count number of commands */
1643 for (count = 0, oip = opcode_info_arr;
1644 oip->num_attached != 0xff; ++oip) {
1645 if (F_INV_OP & oip->flags)
1646 continue;
1647 count += (oip->num_attached + 1);
1648 }
1649 bump = rctd ? 20 : 8;
1650 put_unaligned_be32(count * bump, arr);
1651 for (offset = 4, oip = opcode_info_arr;
1652 oip->num_attached != 0xff && offset < a_len; ++oip) {
1653 if (F_INV_OP & oip->flags)
1654 continue;
1655 na = oip->num_attached;
1656 arr[offset] = oip->opcode;
1657 put_unaligned_be16(oip->sa, arr + offset + 2);
1658 if (rctd)
1659 arr[offset + 5] |= 0x2;
1660 if (FF_SA & oip->flags)
1661 arr[offset + 5] |= 0x1;
1662 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1663 if (rctd)
1664 put_unaligned_be16(0xa, arr + offset + 8);
1665 r_oip = oip;
1666 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1667 if (F_INV_OP & oip->flags)
1668 continue;
1669 offset += bump;
1670 arr[offset] = oip->opcode;
1671 put_unaligned_be16(oip->sa, arr + offset + 2);
1672 if (rctd)
1673 arr[offset + 5] |= 0x2;
1674 if (FF_SA & oip->flags)
1675 arr[offset + 5] |= 0x1;
1676 put_unaligned_be16(oip->len_mask[0],
1677 arr + offset + 6);
1678 if (rctd)
1679 put_unaligned_be16(0xa,
1680 arr + offset + 8);
1681 }
1682 oip = r_oip;
1683 offset += bump;
1684 }
1685 break;
1686 case 1: /* one command: opcode only */
1687 case 2: /* one command: opcode plus service action */
1688 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1689 sdeb_i = opcode_ind_arr[req_opcode];
1690 oip = &opcode_info_arr[sdeb_i];
1691 if (F_INV_OP & oip->flags) {
1692 supp = 1;
1693 offset = 4;
1694 } else {
1695 if (1 == reporting_opts) {
1696 if (FF_SA & oip->flags) {
1697 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1698 2, 2);
1699 kfree(arr);
1700 return check_condition_result;
1701 }
1702 req_sa = 0;
1703 } else if (2 == reporting_opts &&
1704 0 == (FF_SA & oip->flags)) {
1705 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1706 kfree(arr); /* point at requested sa */
1707 return check_condition_result;
1708 }
1709 if (0 == (FF_SA & oip->flags) &&
1710 req_opcode == oip->opcode)
1711 supp = 3;
1712 else if (0 == (FF_SA & oip->flags)) {
1713 na = oip->num_attached;
1714 for (k = 0, oip = oip->arrp; k < na;
1715 ++k, ++oip) {
1716 if (req_opcode == oip->opcode)
1717 break;
1718 }
1719 supp = (k >= na) ? 1 : 3;
1720 } else if (req_sa != oip->sa) {
1721 na = oip->num_attached;
1722 for (k = 0, oip = oip->arrp; k < na;
1723 ++k, ++oip) {
1724 if (req_sa == oip->sa)
1725 break;
1726 }
1727 supp = (k >= na) ? 1 : 3;
1728 } else
1729 supp = 3;
1730 if (3 == supp) {
1731 u = oip->len_mask[0];
1732 put_unaligned_be16(u, arr + 2);
1733 arr[4] = oip->opcode;
1734 for (k = 1; k < u; ++k)
1735 arr[4 + k] = (k < 16) ?
1736 oip->len_mask[k] : 0xff;
1737 offset = 4 + u;
1738 } else
1739 offset = 4;
1740 }
1741 arr[1] = (rctd ? 0x80 : 0) | supp;
1742 if (rctd) {
1743 put_unaligned_be16(0xa, arr + offset);
1744 offset += 12;
1745 }
1746 break;
1747 default:
1748 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1749 kfree(arr);
1750 return check_condition_result;
1751 }
1752 offset = (offset < a_len) ? offset : a_len;
1753 len = (offset < alloc_len) ? offset : alloc_len;
1754 errsts = fill_from_dev_buffer(scp, arr, len);
1755 kfree(arr);
1756 return errsts;
1757}
1758
1759static int
1760resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
1761{
1762 bool repd;
1763 u32 alloc_len, len;
1764 u8 arr[16];
1765 u8 *cmd = scp->cmnd;
1766
1767 memset(arr, 0, sizeof(arr));
1768 repd = !!(cmd[2] & 0x80);
1769 alloc_len = get_unaligned_be32(cmd + 6);
1770 if (alloc_len < 4) {
1771 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1772 return check_condition_result;
1773 }
1774 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1775 arr[1] = 0x1; /* ITNRS */
1776 if (repd) {
1777 arr[3] = 0xc;
1778 len = 16;
1779 } else
1780 len = 4;
1781
1782 len = (len < alloc_len) ? len : alloc_len;
1783 return fill_from_dev_buffer(scp, arr, len);
1784}
1785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786/* <<Following mode page info copied from ST318451LW>> */
1787
1788static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1789{ /* Read-Write Error Recovery page for mode_sense */
1790 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1791 5, 0, 0xff, 0xff};
1792
1793 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1794 if (1 == pcontrol)
1795 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1796 return sizeof(err_recov_pg);
1797}
1798
1799static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1800{ /* Disconnect-Reconnect page for mode_sense */
1801 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1802 0, 0, 0, 0, 0, 0, 0, 0};
1803
1804 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1805 if (1 == pcontrol)
1806 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1807 return sizeof(disconnect_pg);
1808}
1809
1810static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1811{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001812 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1813 0, 0, 0, 0, 0, 0, 0, 0,
1814 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
Martin K. Petersen597136a2008-06-05 00:12:59 -04001816 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001817 put_unaligned_be16(sdebug_sectors_per, p + 10);
1818 put_unaligned_be16(sdebug_sector_size, p + 12);
1819 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001820 p[20] |= 0x20; /* should agree with INQUIRY */
1821 if (1 == pcontrol)
1822 memset(p + 2, 0, sizeof(format_pg) - 2);
1823 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824}
1825
1826static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1827{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001828 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1829 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1830 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1832
Douglas Gilbert773642d2016-04-25 12:16:28 -04001833 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001834 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 memcpy(p, caching_pg, sizeof(caching_pg));
1836 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001837 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1838 else if (2 == pcontrol)
1839 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 return sizeof(caching_pg);
1841}
1842
1843static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1844{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001845 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1846 0, 0, 0, 0};
1847 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 0, 0, 0x2, 0x4b};
1849
Douglas Gilbert773642d2016-04-25 12:16:28 -04001850 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001852 else
1853 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001854
Douglas Gilbert773642d2016-04-25 12:16:28 -04001855 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001856 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1859 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001860 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1861 else if (2 == pcontrol)
1862 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 return sizeof(ctrl_m_pg);
1864}
1865
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001866
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1868{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001869 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1870 0, 0, 0x0, 0x0};
1871 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1872 0, 0, 0x0, 0x0};
1873
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1875 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001876 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1877 else if (2 == pcontrol)
1878 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 return sizeof(iec_m_pg);
1880}
1881
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001882static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1883{ /* SAS SSP mode page - short format for mode_sense */
1884 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1885 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1886
1887 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1888 if (1 == pcontrol)
1889 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1890 return sizeof(sas_sf_m_pg);
1891}
1892
1893
1894static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1895 int target_dev_id)
1896{ /* SAS phy control and discover mode page for mode_sense */
1897 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1898 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001899 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1900 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001901 0x2, 0, 0, 0, 0, 0, 0, 0,
1902 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1903 0, 0, 0, 0, 0, 0, 0, 0,
1904 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001905 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1906 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001907 0x3, 0, 0, 0, 0, 0, 0, 0,
1908 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1909 0, 0, 0, 0, 0, 0, 0, 0,
1910 };
1911 int port_a, port_b;
1912
Douglas Gilbert773642d2016-04-25 12:16:28 -04001913 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1914 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1915 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1916 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001917 port_a = target_dev_id + 1;
1918 port_b = port_a + 1;
1919 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001920 put_unaligned_be32(port_a, p + 20);
1921 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001922 if (1 == pcontrol)
1923 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1924 return sizeof(sas_pcd_m_pg);
1925}
1926
1927static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1928{ /* SAS SSP shared protocol specific port mode subpage */
1929 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1930 0, 0, 0, 0, 0, 0, 0, 0,
1931 };
1932
1933 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1934 if (1 == pcontrol)
1935 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1936 return sizeof(sas_sha_m_pg);
1937}
1938
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939#define SDEBUG_MAX_MSENSE_SZ 256
1940
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001941static int
1942resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
Douglas Gilbert23183912006-09-16 20:30:47 -04001944 unsigned char dbd, llbaa;
1945 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 unsigned char dev_spec;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001947 int alloc_len, msense_6, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001948 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 unsigned char * ap;
1950 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001951 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Douglas Gilbert23183912006-09-16 20:30:47 -04001953 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 pcontrol = (cmd[2] & 0xc0) >> 6;
1955 pcode = cmd[2] & 0x3f;
1956 subpcode = cmd[3];
1957 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001958 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001959 if ((0 == sdebug_ptype) && (0 == dbd))
Douglas Gilbert23183912006-09-16 20:30:47 -04001960 bd_len = llbaa ? 16 : 8;
1961 else
1962 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001963 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1965 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001966 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 return check_condition_result;
1968 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001969 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1970 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001971 /* set DPOFUA bit for disks */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001972 if (0 == sdebug_ptype)
Douglas Gilbert23183912006-09-16 20:30:47 -04001973 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1974 else
1975 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 if (msense_6) {
1977 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001978 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 offset = 4;
1980 } else {
1981 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001982 if (16 == bd_len)
1983 arr[4] = 0x1; /* set LONGLBA bit */
1984 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 offset = 8;
1986 }
1987 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001988 if ((bd_len > 0) && (!sdebug_capacity))
1989 sdebug_capacity = get_sdebug_capacity();
1990
Douglas Gilbert23183912006-09-16 20:30:47 -04001991 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001992 if (sdebug_capacity > 0xfffffffe)
1993 put_unaligned_be32(0xffffffff, ap + 0);
1994 else
1995 put_unaligned_be32(sdebug_capacity, ap + 0);
1996 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04001997 offset += bd_len;
1998 ap = arr + offset;
1999 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002000 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2001 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002002 offset += bd_len;
2003 ap = arr + offset;
2004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002006 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2007 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002008 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 return check_condition_result;
2010 }
2011 switch (pcode) {
2012 case 0x1: /* Read-Write error recovery page, direct access */
2013 len = resp_err_recov_pg(ap, pcontrol, target);
2014 offset += len;
2015 break;
2016 case 0x2: /* Disconnect-Reconnect page, all devices */
2017 len = resp_disconnect_pg(ap, pcontrol, target);
2018 offset += len;
2019 break;
2020 case 0x3: /* Format device page, direct access */
2021 len = resp_format_pg(ap, pcontrol, target);
2022 offset += len;
2023 break;
2024 case 0x8: /* Caching page, direct access */
2025 len = resp_caching_pg(ap, pcontrol, target);
2026 offset += len;
2027 break;
2028 case 0xa: /* Control Mode page, all devices */
2029 len = resp_ctrl_m_pg(ap, pcontrol, target);
2030 offset += len;
2031 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002032 case 0x19: /* if spc==1 then sas phy, control+discover */
2033 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002034 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002035 return check_condition_result;
2036 }
2037 len = 0;
2038 if ((0x0 == subpcode) || (0xff == subpcode))
2039 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2040 if ((0x1 == subpcode) || (0xff == subpcode))
2041 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2042 target_dev_id);
2043 if ((0x2 == subpcode) || (0xff == subpcode))
2044 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2045 offset += len;
2046 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 case 0x1c: /* Informational Exceptions Mode page, all devices */
2048 len = resp_iec_m_pg(ap, pcontrol, target);
2049 offset += len;
2050 break;
2051 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002052 if ((0 == subpcode) || (0xff == subpcode)) {
2053 len = resp_err_recov_pg(ap, pcontrol, target);
2054 len += resp_disconnect_pg(ap + len, pcontrol, target);
2055 len += resp_format_pg(ap + len, pcontrol, target);
2056 len += resp_caching_pg(ap + len, pcontrol, target);
2057 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2058 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2059 if (0xff == subpcode) {
2060 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2061 target, target_dev_id);
2062 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2063 }
2064 len += resp_iec_m_pg(ap + len, pcontrol, target);
2065 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002066 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002067 return check_condition_result;
2068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 offset += len;
2070 break;
2071 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002072 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 return check_condition_result;
2074 }
2075 if (msense_6)
2076 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002077 else
2078 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2080}
2081
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002082#define SDEBUG_MAX_MSELECT_SZ 512
2083
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002084static int
2085resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002086{
2087 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002088 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002089 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002090 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002091 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002092
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002093 memset(arr, 0, sizeof(arr));
2094 pf = cmd[1] & 0x10;
2095 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002096 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002097 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002098 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002099 return check_condition_result;
2100 }
2101 res = fetch_to_dev_buffer(scp, arr, param_len);
2102 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002103 return DID_ERROR << 16;
2104 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002105 sdev_printk(KERN_INFO, scp->device,
2106 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2107 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002108 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2109 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002110 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002111 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002112 return check_condition_result;
2113 }
2114 off = bd_len + (mselect6 ? 4 : 8);
2115 mpage = arr[off] & 0x3f;
2116 ps = !!(arr[off] & 0x80);
2117 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002118 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002119 return check_condition_result;
2120 }
2121 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002122 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002123 (arr[off + 1] + 2);
2124 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002125 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002126 PARAMETER_LIST_LENGTH_ERR, 0);
2127 return check_condition_result;
2128 }
2129 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002130 case 0x8: /* Caching Mode page */
2131 if (caching_pg[1] == arr[off + 1]) {
2132 memcpy(caching_pg + 2, arr + off + 2,
2133 sizeof(caching_pg) - 2);
2134 goto set_mode_changed_ua;
2135 }
2136 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002137 case 0xa: /* Control Mode page */
2138 if (ctrl_m_pg[1] == arr[off + 1]) {
2139 memcpy(ctrl_m_pg + 2, arr + off + 2,
2140 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002141 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002142 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002143 }
2144 break;
2145 case 0x1c: /* Informational Exceptions Mode page */
2146 if (iec_m_pg[1] == arr[off + 1]) {
2147 memcpy(iec_m_pg + 2, arr + off + 2,
2148 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002149 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002150 }
2151 break;
2152 default:
2153 break;
2154 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002155 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002156 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002157set_mode_changed_ua:
2158 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2159 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002160}
2161
2162static int resp_temp_l_pg(unsigned char * arr)
2163{
2164 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2165 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2166 };
2167
2168 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2169 return sizeof(temp_l_pg);
2170}
2171
2172static int resp_ie_l_pg(unsigned char * arr)
2173{
2174 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2175 };
2176
2177 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2178 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2179 arr[4] = THRESHOLD_EXCEEDED;
2180 arr[5] = 0xff;
2181 }
2182 return sizeof(ie_l_pg);
2183}
2184
2185#define SDEBUG_MAX_LSENSE_SZ 512
2186
2187static int resp_log_sense(struct scsi_cmnd * scp,
2188 struct sdebug_dev_info * devip)
2189{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002190 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002191 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002192 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002193
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002194 memset(arr, 0, sizeof(arr));
2195 ppc = cmd[1] & 0x2;
2196 sp = cmd[1] & 0x1;
2197 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002198 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002199 return check_condition_result;
2200 }
2201 pcontrol = (cmd[2] & 0xc0) >> 6;
2202 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002203 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002204 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002205 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002206 if (0 == subpcode) {
2207 switch (pcode) {
2208 case 0x0: /* Supported log pages log page */
2209 n = 4;
2210 arr[n++] = 0x0; /* this page */
2211 arr[n++] = 0xd; /* Temperature */
2212 arr[n++] = 0x2f; /* Informational exceptions */
2213 arr[3] = n - 4;
2214 break;
2215 case 0xd: /* Temperature log page */
2216 arr[3] = resp_temp_l_pg(arr + 4);
2217 break;
2218 case 0x2f: /* Informational exceptions log page */
2219 arr[3] = resp_ie_l_pg(arr + 4);
2220 break;
2221 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002222 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002223 return check_condition_result;
2224 }
2225 } else if (0xff == subpcode) {
2226 arr[0] |= 0x40;
2227 arr[1] = subpcode;
2228 switch (pcode) {
2229 case 0x0: /* Supported log pages and subpages log page */
2230 n = 4;
2231 arr[n++] = 0x0;
2232 arr[n++] = 0x0; /* 0,0 page */
2233 arr[n++] = 0x0;
2234 arr[n++] = 0xff; /* this page */
2235 arr[n++] = 0xd;
2236 arr[n++] = 0x0; /* Temperature */
2237 arr[n++] = 0x2f;
2238 arr[n++] = 0x0; /* Informational exceptions */
2239 arr[3] = n - 4;
2240 break;
2241 case 0xd: /* Temperature subpages */
2242 n = 4;
2243 arr[n++] = 0xd;
2244 arr[n++] = 0x0; /* Temperature */
2245 arr[3] = n - 4;
2246 break;
2247 case 0x2f: /* Informational exceptions subpages */
2248 n = 4;
2249 arr[n++] = 0x2f;
2250 arr[n++] = 0x0; /* Informational exceptions */
2251 arr[3] = n - 4;
2252 break;
2253 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002254 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002255 return check_condition_result;
2256 }
2257 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002258 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002259 return check_condition_result;
2260 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002261 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002262 return fill_from_dev_buffer(scp, arr,
2263 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2264}
2265
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002266static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002267 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002269 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002270 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 return check_condition_result;
2272 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002273 /* transfer length excessive (tie in to block limits VPD page) */
2274 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002275 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002276 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002277 return check_condition_result;
2278 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002279 return 0;
2280}
2281
Akinobu Mitaa4517512013-07-08 16:01:57 -07002282/* Returns number of bytes copied or -1 if error. */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002283static int
2284do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002285{
2286 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002287 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002288 struct scsi_data_buffer *sdb;
2289 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002290
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002291 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002292 sdb = scsi_out(scmd);
2293 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002294 } else {
2295 sdb = scsi_in(scmd);
2296 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002297 }
2298
2299 if (!sdb->length)
2300 return 0;
2301 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2302 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002303
2304 block = do_div(lba, sdebug_store_sectors);
2305 if (block + num > sdebug_store_sectors)
2306 rest = block + num - sdebug_store_sectors;
2307
Dave Gordon386ecb12015-06-30 14:58:57 -07002308 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002309 fake_storep + (block * sdebug_sector_size),
2310 (num - rest) * sdebug_sector_size, 0, do_write);
2311 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002312 return ret;
2313
2314 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002315 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002316 fake_storep, rest * sdebug_sector_size,
2317 (num - rest) * sdebug_sector_size, do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002318 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002319
2320 return ret;
2321}
2322
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002323/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2324 * arr into fake_store(lba,num) and return true. If comparison fails then
2325 * return false. */
2326static bool
2327comp_write_worker(u64 lba, u32 num, const u8 *arr)
2328{
2329 bool res;
2330 u64 block, rest = 0;
2331 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002332 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002333
2334 block = do_div(lba, store_blks);
2335 if (block + num > store_blks)
2336 rest = block + num - store_blks;
2337
2338 res = !memcmp(fake_storep + (block * lb_size), arr,
2339 (num - rest) * lb_size);
2340 if (!res)
2341 return res;
2342 if (rest)
2343 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2344 rest * lb_size);
2345 if (!res)
2346 return res;
2347 arr += num * lb_size;
2348 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2349 if (rest)
2350 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2351 rest * lb_size);
2352 return res;
2353}
2354
Akinobu Mita51d648a2013-09-18 21:27:28 +09002355static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002356{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002357 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002358
Douglas Gilbert773642d2016-04-25 12:16:28 -04002359 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002360 csum = (__force __be16)ip_compute_csum(buf, len);
2361 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002362 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002363
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002364 return csum;
2365}
2366
2367static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2368 sector_t sector, u32 ei_lba)
2369{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002370 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002371
2372 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002373 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002374 (unsigned long)sector,
2375 be16_to_cpu(sdt->guard_tag),
2376 be16_to_cpu(csum));
2377 return 0x01;
2378 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002379 if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002380 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002381 pr_err("REF check failed on sector %lu\n",
2382 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002383 return 0x03;
2384 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002385 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002386 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002387 pr_err("REF check failed on sector %lu\n",
2388 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002389 return 0x03;
2390 }
2391 return 0;
2392}
2393
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002394static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002395 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002396{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002397 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002398 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002399 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002400 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002401
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002402 /* Bytes of protection data to copy into sgl */
2403 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002404
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002405 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2406 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2407 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2408
2409 while (sg_miter_next(&miter) && resid > 0) {
2410 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002411 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002412 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002413
2414 if (dif_store_end < start + len)
2415 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002416
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002417 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002418
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002419 if (read)
2420 memcpy(paddr, start, len - rest);
2421 else
2422 memcpy(start, paddr, len - rest);
2423
2424 if (rest) {
2425 if (read)
2426 memcpy(paddr + len - rest, dif_storep, rest);
2427 else
2428 memcpy(dif_storep, paddr + len - rest, rest);
2429 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002430
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002431 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002432 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002433 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002434 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002435}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002436
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002437static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2438 unsigned int sectors, u32 ei_lba)
2439{
2440 unsigned int i;
2441 struct sd_dif_tuple *sdt;
2442 sector_t sector;
2443
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002444 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002445 int ret;
2446
2447 sector = start_sec + i;
2448 sdt = dif_store(sector);
2449
Akinobu Mita51d648a2013-09-18 21:27:28 +09002450 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002451 continue;
2452
2453 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2454 if (ret) {
2455 dif_errors++;
2456 return ret;
2457 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002458 }
2459
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002460 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002461 dix_reads++;
2462
2463 return 0;
2464}
2465
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002466static int
2467resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002468{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002469 u8 *cmd = scp->cmnd;
2470 u64 lba;
2471 u32 num;
2472 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002473 unsigned long iflags;
2474 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002475 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002476
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002477 switch (cmd[0]) {
2478 case READ_16:
2479 ei_lba = 0;
2480 lba = get_unaligned_be64(cmd + 2);
2481 num = get_unaligned_be32(cmd + 10);
2482 check_prot = true;
2483 break;
2484 case READ_10:
2485 ei_lba = 0;
2486 lba = get_unaligned_be32(cmd + 2);
2487 num = get_unaligned_be16(cmd + 7);
2488 check_prot = true;
2489 break;
2490 case READ_6:
2491 ei_lba = 0;
2492 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2493 (u32)(cmd[1] & 0x1f) << 16;
2494 num = (0 == cmd[4]) ? 256 : cmd[4];
2495 check_prot = true;
2496 break;
2497 case READ_12:
2498 ei_lba = 0;
2499 lba = get_unaligned_be32(cmd + 2);
2500 num = get_unaligned_be32(cmd + 6);
2501 check_prot = true;
2502 break;
2503 case XDWRITEREAD_10:
2504 ei_lba = 0;
2505 lba = get_unaligned_be32(cmd + 2);
2506 num = get_unaligned_be16(cmd + 7);
2507 check_prot = false;
2508 break;
2509 default: /* assume READ(32) */
2510 lba = get_unaligned_be64(cmd + 12);
2511 ei_lba = get_unaligned_be32(cmd + 20);
2512 num = get_unaligned_be32(cmd + 28);
2513 check_prot = false;
2514 break;
2515 }
2516 if (check_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002517 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002518 (cmd[1] & 0xe0)) {
2519 mk_sense_invalid_opcode(scp);
2520 return check_condition_result;
2521 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002522 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2523 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002524 (cmd[1] & 0xe0) == 0)
2525 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2526 "to DIF device\n");
2527 }
2528 if (sdebug_any_injecting_opt) {
2529 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2530
2531 if (ep->inj_short)
2532 num /= 2;
2533 }
2534
2535 /* inline check_device_access_params() */
2536 if (lba + num > sdebug_capacity) {
2537 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2538 return check_condition_result;
2539 }
2540 /* transfer length excessive (tie in to block limits VPD page) */
2541 if (num > sdebug_store_sectors) {
2542 /* needs work to find which cdb byte 'num' comes from */
2543 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2544 return check_condition_result;
2545 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002546
Douglas Gilbert773642d2016-04-25 12:16:28 -04002547 if ((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002548 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002549 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2550 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002551 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002552 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002553 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2554 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002555 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2556 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002557 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002558 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002559 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 return check_condition_result;
2561 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002562
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002563 read_lock_irqsave(&atomic_rw, iflags);
2564
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002565 /* DIX + T10 DIF */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002566 if (sdebug_dix && scsi_prot_sg_count(scp)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002567 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002568
2569 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002570 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002571 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002572 return illegal_condition_result;
2573 }
2574 }
2575
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002576 ret = do_device_access(scp, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 read_unlock_irqrestore(&atomic_rw, iflags);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002578 if (ret == -1)
2579 return DID_ERROR << 16;
2580
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002581 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002582
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002583 if (sdebug_any_injecting_opt) {
2584 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2585
2586 if (ep->inj_recovered) {
2587 mk_sense_buffer(scp, RECOVERED_ERROR,
2588 THRESHOLD_EXCEEDED, 0);
2589 return check_condition_result;
2590 } else if (ep->inj_transport) {
2591 mk_sense_buffer(scp, ABORTED_COMMAND,
2592 TRANSPORT_PROBLEM, ACK_NAK_TO);
2593 return check_condition_result;
2594 } else if (ep->inj_dif) {
2595 /* Logical block guard check failed */
2596 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2597 return illegal_condition_result;
2598 } else if (ep->inj_dix) {
2599 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2600 return illegal_condition_result;
2601 }
2602 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002603 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604}
2605
Tomas Winkler58a86352015-07-28 16:54:23 +03002606static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002607{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002608 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002609
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002610 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002611 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002612 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002613
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002614 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002615 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002616
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002617 if (c >= 0x20 && c < 0x7e)
2618 n += scnprintf(b + n, sizeof(b) - n,
2619 " %c ", buf[i+j]);
2620 else
2621 n += scnprintf(b + n, sizeof(b) - n,
2622 "%02x ", buf[i+j]);
2623 }
2624 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002625 }
2626}
2627
2628static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002629 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002630{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002631 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002632 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002633 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002634 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002635 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002636 int dpage_offset;
2637 struct sg_mapping_iter diter;
2638 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002639
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002640 BUG_ON(scsi_sg_count(SCpnt) == 0);
2641 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2642
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002643 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2644 scsi_prot_sg_count(SCpnt),
2645 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2646 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2647 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002648
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002649 /* For each protection page */
2650 while (sg_miter_next(&piter)) {
2651 dpage_offset = 0;
2652 if (WARN_ON(!sg_miter_next(&diter))) {
2653 ret = 0x01;
2654 goto out;
2655 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002656
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002657 for (ppage_offset = 0; ppage_offset < piter.length;
2658 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002659 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002660 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002661 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002662 if (dpage_offset >= diter.length) {
2663 if (WARN_ON(!sg_miter_next(&diter))) {
2664 ret = 0x01;
2665 goto out;
2666 }
2667 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002668 }
2669
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002670 sdt = piter.addr + ppage_offset;
2671 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002672
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002673 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002674 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002675 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002676 goto out;
2677 }
2678
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002679 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002680 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002681 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002682 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002683 diter.consumed = dpage_offset;
2684 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002685 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002686 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002687
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002688 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002689 dix_writes++;
2690
2691 return 0;
2692
2693out:
2694 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002695 sg_miter_stop(&diter);
2696 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002697 return ret;
2698}
2699
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002700static unsigned long lba_to_map_index(sector_t lba)
2701{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002702 if (sdebug_unmap_alignment)
2703 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2704 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002705 return lba;
2706}
2707
2708static sector_t map_index_to_lba(unsigned long index)
2709{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002710 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002711
Douglas Gilbert773642d2016-04-25 12:16:28 -04002712 if (sdebug_unmap_alignment)
2713 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002714 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002715}
2716
Martin K. Petersen44d92692009-10-15 14:45:27 -04002717static unsigned int map_state(sector_t lba, unsigned int *num)
2718{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002719 sector_t end;
2720 unsigned int mapped;
2721 unsigned long index;
2722 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002723
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002724 index = lba_to_map_index(lba);
2725 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002726
2727 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002728 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002729 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002730 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002731
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002732 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002733 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002734 return mapped;
2735}
2736
2737static void map_region(sector_t lba, unsigned int len)
2738{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002739 sector_t end = lba + len;
2740
Martin K. Petersen44d92692009-10-15 14:45:27 -04002741 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002742 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002743
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002744 if (index < map_size)
2745 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002746
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002747 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002748 }
2749}
2750
2751static void unmap_region(sector_t lba, unsigned int len)
2752{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002753 sector_t end = lba + len;
2754
Martin K. Petersen44d92692009-10-15 14:45:27 -04002755 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002756 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002757
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002758 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002759 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002760 index < map_size) {
2761 clear_bit(index, map_storep);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002762 if (sdebug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002763 memset(fake_storep +
Douglas Gilbert773642d2016-04-25 12:16:28 -04002764 lba * sdebug_sector_size, 0,
2765 sdebug_sector_size *
2766 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002767 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002768 if (dif_storep) {
2769 memset(dif_storep + lba, 0xff,
2770 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002771 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002772 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002773 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002774 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002775 }
2776}
2777
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002778static int
2779resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002781 u8 *cmd = scp->cmnd;
2782 u64 lba;
2783 u32 num;
2784 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002786 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002787 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002789 switch (cmd[0]) {
2790 case WRITE_16:
2791 ei_lba = 0;
2792 lba = get_unaligned_be64(cmd + 2);
2793 num = get_unaligned_be32(cmd + 10);
2794 check_prot = true;
2795 break;
2796 case WRITE_10:
2797 ei_lba = 0;
2798 lba = get_unaligned_be32(cmd + 2);
2799 num = get_unaligned_be16(cmd + 7);
2800 check_prot = true;
2801 break;
2802 case WRITE_6:
2803 ei_lba = 0;
2804 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2805 (u32)(cmd[1] & 0x1f) << 16;
2806 num = (0 == cmd[4]) ? 256 : cmd[4];
2807 check_prot = true;
2808 break;
2809 case WRITE_12:
2810 ei_lba = 0;
2811 lba = get_unaligned_be32(cmd + 2);
2812 num = get_unaligned_be32(cmd + 6);
2813 check_prot = true;
2814 break;
2815 case 0x53: /* XDWRITEREAD(10) */
2816 ei_lba = 0;
2817 lba = get_unaligned_be32(cmd + 2);
2818 num = get_unaligned_be16(cmd + 7);
2819 check_prot = false;
2820 break;
2821 default: /* assume WRITE(32) */
2822 lba = get_unaligned_be64(cmd + 12);
2823 ei_lba = get_unaligned_be32(cmd + 20);
2824 num = get_unaligned_be32(cmd + 28);
2825 check_prot = false;
2826 break;
2827 }
2828 if (check_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002829 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002830 (cmd[1] & 0xe0)) {
2831 mk_sense_invalid_opcode(scp);
2832 return check_condition_result;
2833 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002834 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2835 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002836 (cmd[1] & 0xe0) == 0)
2837 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2838 "to DIF device\n");
2839 }
2840
2841 /* inline check_device_access_params() */
2842 if (lba + num > sdebug_capacity) {
2843 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2844 return check_condition_result;
2845 }
2846 /* transfer length excessive (tie in to block limits VPD page) */
2847 if (num > sdebug_store_sectors) {
2848 /* needs work to find which cdb byte 'num' comes from */
2849 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2850 return check_condition_result;
2851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002853 write_lock_irqsave(&atomic_rw, iflags);
2854
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002855 /* DIX + T10 DIF */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002856 if (sdebug_dix && scsi_prot_sg_count(scp)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002857 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002858
2859 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002860 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002861 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002862 return illegal_condition_result;
2863 }
2864 }
2865
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002866 ret = do_device_access(scp, lba, num, true);
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002867 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002868 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002870 if (-1 == ret)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002871 return DID_ERROR << 16;
2872 else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002873 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002874 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002875 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002876
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002877 if (sdebug_any_injecting_opt) {
2878 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2879
2880 if (ep->inj_recovered) {
2881 mk_sense_buffer(scp, RECOVERED_ERROR,
2882 THRESHOLD_EXCEEDED, 0);
2883 return check_condition_result;
2884 } else if (ep->inj_dif) {
2885 /* Logical block guard check failed */
2886 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2887 return illegal_condition_result;
2888 } else if (ep->inj_dix) {
2889 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2890 return illegal_condition_result;
2891 }
2892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 return 0;
2894}
2895
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002896static int
2897resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba,
2898 bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002899{
2900 unsigned long iflags;
2901 unsigned long long i;
2902 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002903 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002904
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002905 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002906 if (ret)
2907 return ret;
2908
2909 write_lock_irqsave(&atomic_rw, iflags);
2910
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002911 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002912 unmap_region(lba, num);
2913 goto out;
2914 }
2915
Douglas Gilbert773642d2016-04-25 12:16:28 -04002916 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002917 /* if ndob then zero 1 logical block, else fetch 1 logical block */
2918 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002919 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002920 ret = 0;
2921 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04002922 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2923 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002924
2925 if (-1 == ret) {
2926 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002927 return DID_ERROR << 16;
2928 } else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002929 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002930 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2931 my_name, "write same",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002932 num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002933
2934 /* Copy first sector to remaining blocks */
2935 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002936 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2937 fake_storep + lba_off,
2938 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002939
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002940 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002941 map_region(lba, num);
2942out:
2943 write_unlock_irqrestore(&atomic_rw, iflags);
2944
2945 return 0;
2946}
2947
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002948static int
2949resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2950{
2951 u8 *cmd = scp->cmnd;
2952 u32 lba;
2953 u16 num;
2954 u32 ei_lba = 0;
2955 bool unmap = false;
2956
2957 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002958 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002959 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2960 return check_condition_result;
2961 } else
2962 unmap = true;
2963 }
2964 lba = get_unaligned_be32(cmd + 2);
2965 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002966 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002967 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2968 return check_condition_result;
2969 }
2970 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2971}
2972
2973static int
2974resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2975{
2976 u8 *cmd = scp->cmnd;
2977 u64 lba;
2978 u32 num;
2979 u32 ei_lba = 0;
2980 bool unmap = false;
2981 bool ndob = false;
2982
2983 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002984 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002985 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2986 return check_condition_result;
2987 } else
2988 unmap = true;
2989 }
2990 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
2991 ndob = true;
2992 lba = get_unaligned_be64(cmd + 2);
2993 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002994 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002995 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
2996 return check_condition_result;
2997 }
2998 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
2999}
3000
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003001/* Note the mode field is in the same position as the (lower) service action
3002 * field. For the Report supported operation codes command, SPC-4 suggests
3003 * each mode of this command should be reported separately; for future. */
3004static int
3005resp_write_buffer(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3006{
3007 u8 *cmd = scp->cmnd;
3008 struct scsi_device *sdp = scp->device;
3009 struct sdebug_dev_info *dp;
3010 u8 mode;
3011
3012 mode = cmd[1] & 0x1f;
3013 switch (mode) {
3014 case 0x4: /* download microcode (MC) and activate (ACT) */
3015 /* set UAs on this device only */
3016 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3017 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3018 break;
3019 case 0x5: /* download MC, save and ACT */
3020 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3021 break;
3022 case 0x6: /* download MC with offsets and ACT */
3023 /* set UAs on most devices (LUs) in this target */
3024 list_for_each_entry(dp,
3025 &devip->sdbg_host->dev_info_list,
3026 dev_list)
3027 if (dp->target == sdp->id) {
3028 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3029 if (devip != dp)
3030 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3031 dp->uas_bm);
3032 }
3033 break;
3034 case 0x7: /* download MC with offsets, save, and ACT */
3035 /* set UA on all devices (LUs) in this target */
3036 list_for_each_entry(dp,
3037 &devip->sdbg_host->dev_info_list,
3038 dev_list)
3039 if (dp->target == sdp->id)
3040 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3041 dp->uas_bm);
3042 break;
3043 default:
3044 /* do nothing for this command for other mode values */
3045 break;
3046 }
3047 return 0;
3048}
3049
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003050static int
3051resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3052{
3053 u8 *cmd = scp->cmnd;
3054 u8 *arr;
3055 u8 *fake_storep_hold;
3056 u64 lba;
3057 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003058 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003059 u8 num;
3060 unsigned long iflags;
3061 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003062 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003063
Douglas Gilbertd467d312014-11-26 12:33:48 -05003064 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003065 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3066 if (0 == num)
3067 return 0; /* degenerate case, not an error */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003068 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003069 (cmd[1] & 0xe0)) {
3070 mk_sense_invalid_opcode(scp);
3071 return check_condition_result;
3072 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003073 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3074 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003075 (cmd[1] & 0xe0) == 0)
3076 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3077 "to DIF device\n");
3078
3079 /* inline check_device_access_params() */
3080 if (lba + num > sdebug_capacity) {
3081 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3082 return check_condition_result;
3083 }
3084 /* transfer length excessive (tie in to block limits VPD page) */
3085 if (num > sdebug_store_sectors) {
3086 /* needs work to find which cdb byte 'num' comes from */
3087 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3088 return check_condition_result;
3089 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003090 dnum = 2 * num;
3091 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3092 if (NULL == arr) {
3093 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3094 INSUFF_RES_ASCQ);
3095 return check_condition_result;
3096 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003097
3098 write_lock_irqsave(&atomic_rw, iflags);
3099
3100 /* trick do_device_access() to fetch both compare and write buffers
3101 * from data-in into arr. Safe (atomic) since write_lock held. */
3102 fake_storep_hold = fake_storep;
3103 fake_storep = arr;
3104 ret = do_device_access(scp, 0, dnum, true);
3105 fake_storep = fake_storep_hold;
3106 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003107 retval = DID_ERROR << 16;
3108 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003109 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003110 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3111 "indicated=%u, IO sent=%d bytes\n", my_name,
3112 dnum * lb_size, ret);
3113 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003114 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003115 retval = check_condition_result;
3116 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003117 }
3118 if (scsi_debug_lbp())
3119 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003120cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003121 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003122 kfree(arr);
3123 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003124}
3125
Martin K. Petersen44d92692009-10-15 14:45:27 -04003126struct unmap_block_desc {
3127 __be64 lba;
3128 __be32 blocks;
3129 __be32 __reserved;
3130};
3131
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003132static int
3133resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003134{
3135 unsigned char *buf;
3136 struct unmap_block_desc *desc;
3137 unsigned int i, payload_len, descriptors;
3138 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003139 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003140
Martin K. Petersen44d92692009-10-15 14:45:27 -04003141
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003142 if (!scsi_debug_lbp())
3143 return 0; /* fib and say its done */
3144 payload_len = get_unaligned_be16(scp->cmnd + 7);
3145 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003146
3147 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003148 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003149 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003150 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003151 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003152
Douglas Gilbertb333a812016-04-25 12:16:30 -04003153 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003154 if (!buf) {
3155 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3156 INSUFF_RES_ASCQ);
3157 return check_condition_result;
3158 }
3159
3160 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003161
3162 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3163 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3164
3165 desc = (void *)&buf[8];
3166
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003167 write_lock_irqsave(&atomic_rw, iflags);
3168
Martin K. Petersen44d92692009-10-15 14:45:27 -04003169 for (i = 0 ; i < descriptors ; i++) {
3170 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3171 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3172
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003173 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003174 if (ret)
3175 goto out;
3176
3177 unmap_region(lba, num);
3178 }
3179
3180 ret = 0;
3181
3182out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003183 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003184 kfree(buf);
3185
3186 return ret;
3187}
3188
3189#define SDEBUG_GET_LBA_STATUS_LEN 32
3190
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003191static int
3192resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003193{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003194 u8 *cmd = scp->cmnd;
3195 u64 lba;
3196 u32 alloc_len, mapped, num;
3197 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003198 int ret;
3199
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003200 lba = get_unaligned_be64(cmd + 2);
3201 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003202
3203 if (alloc_len < 24)
3204 return 0;
3205
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003206 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003207 if (ret)
3208 return ret;
3209
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003210 if (scsi_debug_lbp())
3211 mapped = map_state(lba, &num);
3212 else {
3213 mapped = 1;
3214 /* following just in case virtual_gb changed */
3215 sdebug_capacity = get_sdebug_capacity();
3216 if (sdebug_capacity - lba <= 0xffffffff)
3217 num = sdebug_capacity - lba;
3218 else
3219 num = 0xffffffff;
3220 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003221
3222 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003223 put_unaligned_be32(20, arr); /* Parameter Data Length */
3224 put_unaligned_be64(lba, arr + 8); /* LBA */
3225 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3226 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003227
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003228 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003229}
3230
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003231#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232
3233static int resp_report_luns(struct scsi_cmnd * scp,
3234 struct sdebug_dev_info * devip)
3235{
3236 unsigned int alloc_len;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003237 int lun_cnt, i, upper, num, n, want_wlun, shortish;
3238 u64 lun;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003239 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 int select_report = (int)cmd[2];
3241 struct scsi_lun *one_lun;
3242 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003243 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003245 clear_luns_changed_on_target(devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003247 shortish = (alloc_len < 4);
3248 if (shortish || (select_report > 2)) {
3249 mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 return check_condition_result;
3251 }
3252 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
3253 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003254 lun_cnt = sdebug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003255 if (1 == select_report)
3256 lun_cnt = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003257 else if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003258 --lun_cnt;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003259 want_wlun = (select_report > 0) ? 1 : 0;
3260 num = lun_cnt + want_wlun;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003261 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3262 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3263 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3264 sizeof(struct scsi_lun)), num);
3265 if (n < num) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003266 want_wlun = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003267 lun_cnt = n;
3268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003270 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003271 for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003272 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3273 i++, lun++) {
3274 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 if (upper)
3276 one_lun[i].scsi_lun[0] =
3277 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003278 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003280 if (want_wlun) {
Tomas Winkler34d55432015-07-28 16:54:21 +03003281 one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
3282 one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003283 i++;
3284 }
3285 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 return fill_from_dev_buffer(scp, arr,
3287 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
3288}
3289
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003290static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3291 unsigned int num, struct sdebug_dev_info *devip)
3292{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003293 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003294 unsigned char *kaddr, *buf;
3295 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003296 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003297 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003298
3299 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003300 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003301 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003302 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3303 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003304 return check_condition_result;
3305 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003306
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003307 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003308
3309 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003310 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3311 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003312
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003313 while (sg_miter_next(&miter)) {
3314 kaddr = miter.addr;
3315 for (j = 0; j < miter.length; j++)
3316 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003317
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003318 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003319 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003320 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003321 kfree(buf);
3322
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003323 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003324}
3325
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003326static int
3327resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3328{
3329 u8 *cmd = scp->cmnd;
3330 u64 lba;
3331 u32 num;
3332 int errsts;
3333
3334 if (!scsi_bidi_cmnd(scp)) {
3335 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3336 INSUFF_RES_ASCQ);
3337 return check_condition_result;
3338 }
3339 errsts = resp_read_dt0(scp, devip);
3340 if (errsts)
3341 return errsts;
3342 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3343 errsts = resp_write_dt0(scp, devip);
3344 if (errsts)
3345 return errsts;
3346 }
3347 lba = get_unaligned_be32(cmd + 2);
3348 num = get_unaligned_be16(cmd + 7);
3349 return resp_xdwriteread(scp, lba, num, devip);
3350}
3351
Douglas Gilbertb333a812016-04-25 12:16:30 -04003352/* When tasklet goes off this function is called. */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003353static void sdebug_q_cmd_complete(unsigned long indx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003355 int qa_indx;
3356 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003358 struct sdebug_queued_cmd *sqcp;
3359 struct scsi_cmnd *scp;
3360 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003362 atomic_inc(&sdebug_completions);
3363 qa_indx = indx;
3364 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003365 pr_err("wild qa_indx=%d\n", qa_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 return;
3367 }
3368 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003369 sqcp = &queued_arr[qa_indx];
3370 scp = sqcp->a_cmnd;
3371 if (NULL == scp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003373 pr_err("scp is NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 return;
3375 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003376 devip = (struct sdebug_dev_info *)scp->device->hostdata;
3377 if (devip)
3378 atomic_dec(&devip->num_in_q);
3379 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003380 pr_err("devip=NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003381 if (atomic_read(&retired_max_queue) > 0)
3382 retiring = 1;
3383
3384 sqcp->a_cmnd = NULL;
3385 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3386 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003387 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003388 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003390
3391 if (unlikely(retiring)) { /* user has reduced max_queue */
3392 int k, retval;
3393
3394 retval = atomic_read(&retired_max_queue);
3395 if (qa_indx >= retval) {
3396 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003397 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003398 return;
3399 }
3400 k = find_last_bit(queued_in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003401 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003402 atomic_set(&retired_max_queue, 0);
3403 else
3404 atomic_set(&retired_max_queue, k + 1);
3405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003407 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408}
3409
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003410/* When high resolution timer goes off this function is called. */
3411static enum hrtimer_restart
3412sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3413{
3414 int qa_indx;
3415 int retiring = 0;
3416 unsigned long iflags;
3417 struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer;
3418 struct sdebug_queued_cmd *sqcp;
3419 struct scsi_cmnd *scp;
3420 struct sdebug_dev_info *devip;
3421
3422 atomic_inc(&sdebug_completions);
3423 qa_indx = sd_hrtp->qa_indx;
3424 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003425 pr_err("wild qa_indx=%d\n", qa_indx);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003426 goto the_end;
3427 }
3428 spin_lock_irqsave(&queued_arr_lock, iflags);
3429 sqcp = &queued_arr[qa_indx];
3430 scp = sqcp->a_cmnd;
3431 if (NULL == scp) {
3432 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003433 pr_err("scp is NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003434 goto the_end;
3435 }
3436 devip = (struct sdebug_dev_info *)scp->device->hostdata;
3437 if (devip)
3438 atomic_dec(&devip->num_in_q);
3439 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003440 pr_err("devip=NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003441 if (atomic_read(&retired_max_queue) > 0)
3442 retiring = 1;
3443
3444 sqcp->a_cmnd = NULL;
3445 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3446 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003447 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003448 goto the_end;
3449 }
3450
3451 if (unlikely(retiring)) { /* user has reduced max_queue */
3452 int k, retval;
3453
3454 retval = atomic_read(&retired_max_queue);
3455 if (qa_indx >= retval) {
3456 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003457 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003458 goto the_end;
3459 }
3460 k = find_last_bit(queued_in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003461 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003462 atomic_set(&retired_max_queue, 0);
3463 else
3464 atomic_set(&retired_max_queue, k + 1);
3465 }
3466 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3467 scp->scsi_done(scp); /* callback to mid level */
3468the_end:
3469 return HRTIMER_NORESTART;
3470}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003472static struct sdebug_dev_info *
3473sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003474{
3475 struct sdebug_dev_info *devip;
3476
3477 devip = kzalloc(sizeof(*devip), flags);
3478 if (devip) {
3479 devip->sdbg_host = sdbg_host;
3480 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3481 }
3482 return devip;
3483}
3484
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
3486{
3487 struct sdebug_host_info * sdbg_host;
3488 struct sdebug_dev_info * open_devip = NULL;
3489 struct sdebug_dev_info * devip =
3490 (struct sdebug_dev_info *)sdev->hostdata;
3491
3492 if (devip)
3493 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003494 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3495 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003496 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 return NULL;
3498 }
3499 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3500 if ((devip->used) && (devip->channel == sdev->channel) &&
3501 (devip->target == sdev->id) &&
3502 (devip->lun == sdev->lun))
3503 return devip;
3504 else {
3505 if ((!devip->used) && (!open_devip))
3506 open_devip = devip;
3507 }
3508 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003509 if (!open_devip) { /* try and make a new one */
3510 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3511 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003512 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 return NULL;
3514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003516
3517 open_devip->channel = sdev->channel;
3518 open_devip->target = sdev->id;
3519 open_devip->lun = sdev->lun;
3520 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003521 atomic_set(&open_devip->num_in_q, 0);
3522 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003523 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003524 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525}
3526
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003527static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003529 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003530 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003531 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003532 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003533 return 0;
3534}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003536static int scsi_debug_slave_configure(struct scsi_device *sdp)
3537{
3538 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003539
Douglas Gilbert773642d2016-04-25 12:16:28 -04003540 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003541 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003542 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3543 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
3544 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
3545 devip = devInfoReg(sdp);
3546 if (NULL == devip)
3547 return 1; /* no resources, will be marked offline */
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003548 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003549 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003550 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003551 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003552 return 0;
3553}
3554
3555static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3556{
3557 struct sdebug_dev_info *devip =
3558 (struct sdebug_dev_info *)sdp->hostdata;
3559
Douglas Gilbert773642d2016-04-25 12:16:28 -04003560 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003561 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003562 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3563 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003564 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003565 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003566 sdp->hostdata = NULL;
3567 }
3568}
3569
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003570/* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003571static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
3572{
3573 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003574 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003575 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003576 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003577
3578 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003579 qmax = sdebug_max_queue;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003580 r_qmax = atomic_read(&retired_max_queue);
3581 if (r_qmax > qmax)
3582 qmax = r_qmax;
3583 for (k = 0; k < qmax; ++k) {
3584 if (test_bit(k, queued_in_use_bm)) {
3585 sqcp = &queued_arr[k];
3586 if (cmnd == sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003587 devip = (struct sdebug_dev_info *)
3588 cmnd->device->hostdata;
3589 if (devip)
3590 atomic_dec(&devip->num_in_q);
3591 sqcp->a_cmnd = NULL;
3592 spin_unlock_irqrestore(&queued_arr_lock,
3593 iflags);
Douglas Gilbertb333a812016-04-25 12:16:30 -04003594 if ((sdebug_delay > 0) ||
3595 (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->tletp)
3601 tasklet_kill(sqcp->tletp);
3602 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003603 clear_bit(k, queued_in_use_bm);
3604 return 1;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003605 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003606 }
3607 }
3608 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003609 return 0;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003610}
3611
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003612/* Deletes (stops) timers or tasklets of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003613static void stop_all_queued(void)
3614{
3615 unsigned long iflags;
3616 int k;
3617 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003618 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003619
3620 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003621 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3622 if (test_bit(k, queued_in_use_bm)) {
3623 sqcp = &queued_arr[k];
3624 if (sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003625 devip = (struct sdebug_dev_info *)
3626 sqcp->a_cmnd->device->hostdata;
3627 if (devip)
3628 atomic_dec(&devip->num_in_q);
3629 sqcp->a_cmnd = NULL;
3630 spin_unlock_irqrestore(&queued_arr_lock,
3631 iflags);
Douglas Gilbertb333a812016-04-25 12:16:30 -04003632 if ((sdebug_delay > 0) ||
3633 (sdebug_ndelay > 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003634 if (sqcp->sd_hrtp)
3635 hrtimer_cancel(
3636 &sqcp->sd_hrtp->hrt);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003637 } else if (sdebug_delay < 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003638 if (sqcp->tletp)
3639 tasklet_kill(sqcp->tletp);
3640 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003641 clear_bit(k, queued_in_use_bm);
3642 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003643 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003644 }
3645 }
3646 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647}
3648
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003649/* Free queued command memory on heap */
3650static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003652 unsigned long iflags;
3653 int k;
3654 struct sdebug_queued_cmd *sqcp;
3655
3656 spin_lock_irqsave(&queued_arr_lock, iflags);
3657 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3658 sqcp = &queued_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003659 kfree(sqcp->tletp);
3660 sqcp->tletp = NULL;
3661 kfree(sqcp->sd_hrtp);
3662 sqcp->sd_hrtp = NULL;
3663 }
3664 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665}
3666
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003667static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003669 ++num_aborts;
3670 if (SCpnt) {
3671 if (SCpnt->device &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04003672 (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003673 sdev_printk(KERN_INFO, SCpnt->device, "%s\n",
3674 __func__);
3675 stop_queued_cmnd(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003677 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678}
3679
3680static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3681{
3682 struct sdebug_dev_info * devip;
3683
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003685 if (SCpnt && SCpnt->device) {
3686 struct scsi_device *sdp = SCpnt->device;
3687
Douglas Gilbert773642d2016-04-25 12:16:28 -04003688 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003689 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3690 devip = devInfoReg(sdp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003692 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 }
3694 return SUCCESS;
3695}
3696
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003697static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3698{
3699 struct sdebug_host_info *sdbg_host;
3700 struct sdebug_dev_info *devip;
3701 struct scsi_device *sdp;
3702 struct Scsi_Host *hp;
3703 int k = 0;
3704
3705 ++num_target_resets;
3706 if (!SCpnt)
3707 goto lie;
3708 sdp = SCpnt->device;
3709 if (!sdp)
3710 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003711 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003712 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3713 hp = sdp->host;
3714 if (!hp)
3715 goto lie;
3716 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3717 if (sdbg_host) {
3718 list_for_each_entry(devip,
3719 &sdbg_host->dev_info_list,
3720 dev_list)
3721 if (devip->target == sdp->id) {
3722 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3723 ++k;
3724 }
3725 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003726 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003727 sdev_printk(KERN_INFO, sdp,
3728 "%s: %d device(s) found in target\n", __func__, k);
3729lie:
3730 return SUCCESS;
3731}
3732
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3734{
3735 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003736 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 struct scsi_device * sdp;
3738 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003739 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003742 if (!(SCpnt && SCpnt->device))
3743 goto lie;
3744 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003745 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003746 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3747 hp = sdp->host;
3748 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003749 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003751 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003753 dev_list) {
3754 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3755 ++k;
3756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 }
3758 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003759 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003760 sdev_printk(KERN_INFO, sdp,
3761 "%s: %d device(s) found in host\n", __func__, k);
3762lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 return SUCCESS;
3764}
3765
3766static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3767{
3768 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003769 struct sdebug_dev_info *devip;
3770 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003773 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003774 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 spin_lock(&sdebug_host_list_lock);
3776 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003777 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3778 dev_list) {
3779 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3780 ++k;
3781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 }
3783 spin_unlock(&sdebug_host_list_lock);
3784 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003785 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003786 sdev_printk(KERN_INFO, SCpnt->device,
3787 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 return SUCCESS;
3789}
3790
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003791static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003792 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793{
3794 struct partition * pp;
3795 int starts[SDEBUG_MAX_PARTS + 2];
3796 int sectors_per_part, num_sectors, k;
3797 int heads_by_sects, start_sec, end_sec;
3798
3799 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003800 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003802 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3803 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003804 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003806 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003808 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3810 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003811 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3813 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003814 starts[sdebug_num_parts] = num_sectors;
3815 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816
3817 ramp[510] = 0x55; /* magic partition markings */
3818 ramp[511] = 0xAA;
3819 pp = (struct partition *)(ramp + 0x1be);
3820 for (k = 0; starts[k + 1]; ++k, ++pp) {
3821 start_sec = starts[k];
3822 end_sec = starts[k + 1] - 1;
3823 pp->boot_ind = 0;
3824
3825 pp->cyl = start_sec / heads_by_sects;
3826 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3827 / sdebug_sectors_per;
3828 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3829
3830 pp->end_cyl = end_sec / heads_by_sects;
3831 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3832 / sdebug_sectors_per;
3833 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3834
Akinobu Mita150c3542013-08-26 22:08:40 +09003835 pp->start_sect = cpu_to_le32(start_sec);
3836 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 pp->sys_ind = 0x83; /* plain Linux partition */
3838 }
3839}
3840
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003841static int
3842schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3843 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003845 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003846 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003847 struct sdebug_queued_cmd *sqcp = NULL;
Tomas Winkler299b6c02015-07-28 16:54:24 +03003848 struct scsi_device *sdp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849
Tomas Winkler299b6c02015-07-28 16:54:24 +03003850 /* this should never happen */
3851 if (WARN_ON(!cmnd))
3852 return SCSI_MLQUEUE_HOST_BUSY;
3853
3854 if (NULL == devip) {
3855 pr_warn("called devip == NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003856 /* no particularly good error to report back */
3857 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03003859
3860 sdp = cmnd->device;
3861
Douglas Gilbert773642d2016-04-25 12:16:28 -04003862 if (sdebug_verbose && scsi_result)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003863 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3864 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003865 if (delta_jiff == 0)
3866 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003868 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003869 spin_lock_irqsave(&queued_arr_lock, iflags);
3870 num_in_q = atomic_read(&devip->num_in_q);
3871 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003872 inject = 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003873 if ((qdepth > 0) && (num_in_q >= qdepth)) {
3874 if (scsi_result) {
3875 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3876 goto respond_in_thread;
3877 } else
3878 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003879 } else if ((sdebug_every_nth != 0) &&
3880 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003881 (scsi_result == 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003882 if ((num_in_q == (qdepth - 1)) &&
3883 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04003884 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003885 atomic_set(&sdebug_a_tsf, 0);
3886 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003887 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003889 }
3890
Douglas Gilbert773642d2016-04-25 12:16:28 -04003891 k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
3892 if (k >= sdebug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003894 if (scsi_result)
3895 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003896 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003897 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003898 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003899 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003900 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003901 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003902 (scsi_result ? "status: TASK SET FULL" :
3903 "report: host busy"));
3904 if (scsi_result)
3905 goto respond_in_thread;
3906 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003907 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003909 __set_bit(k, queued_in_use_bm);
3910 atomic_inc(&devip->num_in_q);
3911 sqcp = &queued_arr[k];
3912 sqcp->a_cmnd = cmnd;
3913 cmnd->result = scsi_result;
3914 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertb333a812016-04-25 12:16:30 -04003915 if ((delta_jiff > 0) || (sdebug_ndelay > 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003916 struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp;
Douglas Gilbertb333a812016-04-25 12:16:30 -04003917 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003918
Douglas Gilbertb333a812016-04-25 12:16:30 -04003919 if (delta_jiff > 0) {
3920 struct timespec ts;
3921
3922 jiffies_to_timespec(delta_jiff, &ts);
3923 kt = ktime_set(ts.tv_sec, ts.tv_nsec);
3924 } else
3925 kt = ktime_set(0, sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003926 if (NULL == sd_hp) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04003927 sd_hp = kzalloc(sizeof(*sd_hp), GFP_ATOMIC);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003928 if (NULL == sd_hp)
3929 return SCSI_MLQUEUE_HOST_BUSY;
3930 sqcp->sd_hrtp = sd_hp;
3931 hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC,
3932 HRTIMER_MODE_REL);
3933 sd_hp->hrt.function = sdebug_q_cmd_hrt_complete;
3934 sd_hp->qa_indx = k;
3935 }
3936 hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL);
3937 } else { /* delay < 0 */
3938 if (NULL == sqcp->tletp) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04003939 sqcp->tletp = kzalloc(sizeof(*sqcp->tletp),
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003940 GFP_ATOMIC);
3941 if (NULL == sqcp->tletp)
3942 return SCSI_MLQUEUE_HOST_BUSY;
3943 tasklet_init(sqcp->tletp,
3944 sdebug_q_cmd_complete, k);
3945 }
3946 if (-1 == delta_jiff)
3947 tasklet_hi_schedule(sqcp->tletp);
3948 else
3949 tasklet_schedule(sqcp->tletp);
3950 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003951 if ((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003952 (scsi_result == device_qfull_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003953 sdev_printk(KERN_INFO, sdp,
3954 "%s: num_in_q=%d +1, %s%s\n", __func__,
3955 num_in_q, (inject ? "<inject> " : ""),
3956 "status: TASK SET FULL");
3957 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003958
3959respond_in_thread: /* call back to mid-layer using invocation thread */
3960 cmnd->result = scsi_result;
3961 cmnd->scsi_done(cmnd);
3962 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003964
Douglas Gilbert23183912006-09-16 20:30:47 -04003965/* Note: The following macros create attribute files in the
3966 /sys/module/scsi_debug/parameters directory. Unfortunately this
3967 driver is unaware of a change and cannot trigger auxiliary actions
3968 as it can when the corresponding attribute in the
3969 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3970 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003971module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
3972module_param_named(ato, sdebug_ato, int, S_IRUGO);
3973module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
3974module_param_named(delay, sdebug_delay, int, S_IRUGO | S_IWUSR);
3975module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
3976module_param_named(dif, sdebug_dif, int, S_IRUGO);
3977module_param_named(dix, sdebug_dix, int, S_IRUGO);
3978module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
3979module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
3980module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
3981module_param_named(guard, sdebug_guard, uint, S_IRUGO);
3982module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
3983module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
3984module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
3985module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
3986module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
3987module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
3988module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
3989module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
3990module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
3991module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
3992module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
3993module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
3994module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
3995module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
3996module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
3997module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
3998module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
3999module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4000module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4001module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
4002module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
4003module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4004module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4005module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4006module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4007module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
4008module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004009 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004010module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004011 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012
4013MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4014MODULE_DESCRIPTION("SCSI debug adapter driver");
4015MODULE_LICENSE("GPL");
4016MODULE_VERSION(SCSI_DEBUG_VERSION);
4017
4018MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004019MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004020MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004021MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004022MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004023MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4024MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004025MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004026MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004027MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004028MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004029MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004030MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4031MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4032MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06004033MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004034MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004035MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004036MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4037MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004038MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004039MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004041MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004042MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004043MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004044MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004046MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02004047MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004048MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004049MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004050MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4051MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004052MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4053MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004054MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004055MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4056MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057
4058static char sdebug_info[256];
4059
4060static const char * scsi_debug_info(struct Scsi_Host * shp)
4061{
4062 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
4063 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004064 sdebug_version_date, sdebug_dev_size_mb, sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 return sdebug_info;
4066}
4067
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004068/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Al Viroc8ed5552013-03-31 01:46:06 -04004069static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070{
Al Viroc8ed5552013-03-31 01:46:06 -04004071 char arr[16];
4072 int opts;
4073 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074
Al Viroc8ed5552013-03-31 01:46:06 -04004075 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4076 return -EACCES;
4077 memcpy(arr, buffer, minLen);
4078 arr[minLen] = '\0';
4079 if (1 != sscanf(arr, "%d", &opts))
4080 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004081 sdebug_opts = opts;
4082 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4083 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4084 if (sdebug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004085 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04004086 return length;
4087}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004089/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4090 * same for each scsi_debug host (if more than one). Some of the counters
4091 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004092static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4093{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004094 int f, l;
4095 char b[32];
4096
Douglas Gilbert773642d2016-04-25 12:16:28 -04004097 if (sdebug_every_nth > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004098 snprintf(b, sizeof(b), " (curr:%d)",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004099 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004100 atomic_read(&sdebug_a_tsf) :
4101 atomic_read(&sdebug_cmnd_count)));
4102 else
4103 b[0] = '\0';
4104
4105 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
4106 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4107 "every_nth=%d%s\n"
4108 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
4109 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4110 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4111 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4112 "usec_in_jiffy=%lu\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004113 SCSI_DEBUG_VERSION, sdebug_version_date,
4114 sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
4115 sdebug_every_nth, b, sdebug_delay, sdebug_ndelay,
4116 sdebug_max_luns, atomic_read(&sdebug_completions),
4117 sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004118 sdebug_sectors_per, num_aborts, num_dev_resets,
4119 num_target_resets, num_bus_resets, num_host_resets,
4120 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4121
Douglas Gilbert773642d2016-04-25 12:16:28 -04004122 f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4123 if (f != sdebug_max_queue) {
4124 l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004125 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
4126 "queued_in_use_bm", f, l);
4127 }
Al Viroc8ed5552013-03-31 01:46:06 -04004128 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129}
4130
Akinobu Mita82069372013-10-14 22:48:04 +09004131static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004133 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004135/* Returns -EBUSY if delay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09004136static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4137 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004139 int delay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004141 if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) {
4142 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004143 if (sdebug_delay != delay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004144 unsigned long iflags;
4145 int k;
4146
4147 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004148 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4149 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004150 res = -EBUSY; /* have queued commands */
4151 else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004152 sdebug_delay = delay;
4153 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004154 }
4155 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004157 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 }
4159 return -EINVAL;
4160}
Akinobu Mita82069372013-10-14 22:48:04 +09004161static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004163static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4164{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004165 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004166}
4167/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004168/* If > 0 and accepted then sdebug_delay is set to DELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004169static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
4170 size_t count)
4171{
4172 unsigned long iflags;
4173 int ndelay, res, k;
4174
4175 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4176 (ndelay >= 0) && (ndelay < 1000000000)) {
4177 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004178 if (sdebug_ndelay != ndelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004179 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004180 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4181 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004182 res = -EBUSY; /* have queued commands */
4183 else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004184 sdebug_ndelay = ndelay;
4185 sdebug_delay = ndelay ? DELAY_OVERRIDDEN
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004186 : DEF_DELAY;
4187 }
4188 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4189 }
4190 return res;
4191 }
4192 return -EINVAL;
4193}
4194static DRIVER_ATTR_RW(ndelay);
4195
Akinobu Mita82069372013-10-14 22:48:04 +09004196static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004198 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199}
4200
Akinobu Mita82069372013-10-14 22:48:04 +09004201static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4202 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203{
4204 int opts;
4205 char work[20];
4206
4207 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07004208 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 if (1 == sscanf(&work[2], "%x", &opts))
4210 goto opts_done;
4211 } else {
4212 if (1 == sscanf(work, "%d", &opts))
4213 goto opts_done;
4214 }
4215 }
4216 return -EINVAL;
4217opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004218 sdebug_opts = opts;
4219 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4220 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004221 atomic_set(&sdebug_cmnd_count, 0);
4222 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 return count;
4224}
Akinobu Mita82069372013-10-14 22:48:04 +09004225static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226
Akinobu Mita82069372013-10-14 22:48:04 +09004227static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004229 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230}
Akinobu Mita82069372013-10-14 22:48:04 +09004231static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4232 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233{
4234 int n;
4235
4236 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004237 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 return count;
4239 }
4240 return -EINVAL;
4241}
Akinobu Mita82069372013-10-14 22:48:04 +09004242static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243
Akinobu Mita82069372013-10-14 22:48:04 +09004244static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004246 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247}
Akinobu Mita82069372013-10-14 22:48:04 +09004248static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4249 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250{
4251 int n;
4252
4253 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004254 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 return count;
4256 }
4257 return -EINVAL;
4258}
Akinobu Mita82069372013-10-14 22:48:04 +09004259static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
Akinobu Mita82069372013-10-14 22:48:04 +09004261static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004262{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004263 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004264}
Akinobu Mita82069372013-10-14 22:48:04 +09004265static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4266 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004267{
4268 int n;
4269
4270 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004271 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004272 sdebug_fake_rw = (sdebug_fake_rw > 0);
4273 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004274 if ((0 == n) && (NULL == fake_storep)) {
4275 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004276 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004277 1048576;
4278
4279 fake_storep = vmalloc(sz);
4280 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004281 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004282 return -ENOMEM;
4283 }
4284 memset(fake_storep, 0, sz);
4285 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004286 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004287 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004288 return count;
4289 }
4290 return -EINVAL;
4291}
Akinobu Mita82069372013-10-14 22:48:04 +09004292static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004293
Akinobu Mita82069372013-10-14 22:48:04 +09004294static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004295{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004296 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004297}
Akinobu Mita82069372013-10-14 22:48:04 +09004298static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4299 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004300{
4301 int n;
4302
4303 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004304 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004305 return count;
4306 }
4307 return -EINVAL;
4308}
Akinobu Mita82069372013-10-14 22:48:04 +09004309static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004310
Akinobu Mita82069372013-10-14 22:48:04 +09004311static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004313 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314}
Akinobu Mita82069372013-10-14 22:48:04 +09004315static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4316 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317{
4318 int n;
4319
4320 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004321 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 sdebug_max_tgts_luns();
4323 return count;
4324 }
4325 return -EINVAL;
4326}
Akinobu Mita82069372013-10-14 22:48:04 +09004327static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328
Akinobu Mita82069372013-10-14 22:48:04 +09004329static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004331 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332}
Akinobu Mita82069372013-10-14 22:48:04 +09004333static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Akinobu Mita82069372013-10-14 22:48:04 +09004335static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004337 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338}
Akinobu Mita82069372013-10-14 22:48:04 +09004339static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
Akinobu Mita82069372013-10-14 22:48:04 +09004341static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004343 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344}
Akinobu Mita82069372013-10-14 22:48:04 +09004345static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4346 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347{
4348 int nth;
4349
4350 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004351 sdebug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004352 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 return count;
4354 }
4355 return -EINVAL;
4356}
Akinobu Mita82069372013-10-14 22:48:04 +09004357static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358
Akinobu Mita82069372013-10-14 22:48:04 +09004359static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004361 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362}
Akinobu Mita82069372013-10-14 22:48:04 +09004363static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4364 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365{
4366 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004367 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368
4369 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004370 changed = (sdebug_max_luns != n);
4371 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004373 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004374 struct sdebug_host_info *sdhp;
4375 struct sdebug_dev_info *dp;
4376
4377 spin_lock(&sdebug_host_list_lock);
4378 list_for_each_entry(sdhp, &sdebug_host_list,
4379 host_list) {
4380 list_for_each_entry(dp, &sdhp->dev_info_list,
4381 dev_list) {
4382 set_bit(SDEBUG_UA_LUNS_CHANGED,
4383 dp->uas_bm);
4384 }
4385 }
4386 spin_unlock(&sdebug_host_list_lock);
4387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 return count;
4389 }
4390 return -EINVAL;
4391}
Akinobu Mita82069372013-10-14 22:48:04 +09004392static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393
Akinobu Mita82069372013-10-14 22:48:04 +09004394static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004395{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004396 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004397}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004398/* N.B. max_queue can be changed while there are queued commands. In flight
4399 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004400static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4401 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004402{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004403 unsigned long iflags;
4404 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004405
4406 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4407 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004408 spin_lock_irqsave(&queued_arr_lock, iflags);
4409 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004410 sdebug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004411 if (SCSI_DEBUG_CANQUEUE == k)
4412 atomic_set(&retired_max_queue, 0);
4413 else if (k >= n)
4414 atomic_set(&retired_max_queue, k + 1);
4415 else
4416 atomic_set(&retired_max_queue, 0);
4417 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004418 return count;
4419 }
4420 return -EINVAL;
4421}
Akinobu Mita82069372013-10-14 22:48:04 +09004422static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004423
Akinobu Mita82069372013-10-14 22:48:04 +09004424static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004425{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004426 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004427}
Akinobu Mita82069372013-10-14 22:48:04 +09004428static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004429
Akinobu Mita82069372013-10-14 22:48:04 +09004430static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004432 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433}
Akinobu Mita82069372013-10-14 22:48:04 +09004434static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
Akinobu Mita82069372013-10-14 22:48:04 +09004436static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004437{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004438 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004439}
Akinobu Mita82069372013-10-14 22:48:04 +09004440static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4441 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004442{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004443 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004444 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004445
4446 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004447 changed = (sdebug_virtual_gb != n);
4448 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004449 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004450 if (changed) {
4451 struct sdebug_host_info *sdhp;
4452 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004453
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004454 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004455 list_for_each_entry(sdhp, &sdebug_host_list,
4456 host_list) {
4457 list_for_each_entry(dp, &sdhp->dev_info_list,
4458 dev_list) {
4459 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4460 dp->uas_bm);
4461 }
4462 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004463 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004464 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004465 return count;
4466 }
4467 return -EINVAL;
4468}
Akinobu Mita82069372013-10-14 22:48:04 +09004469static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004470
Akinobu Mita82069372013-10-14 22:48:04 +09004471static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004473 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474}
4475
Akinobu Mita82069372013-10-14 22:48:04 +09004476static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4477 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004479 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004481 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 if (delta_hosts > 0) {
4484 do {
4485 sdebug_add_adapter();
4486 } while (--delta_hosts);
4487 } else if (delta_hosts < 0) {
4488 do {
4489 sdebug_remove_adapter();
4490 } while (++delta_hosts);
4491 }
4492 return count;
4493}
Akinobu Mita82069372013-10-14 22:48:04 +09004494static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
Akinobu Mita82069372013-10-14 22:48:04 +09004496static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004497{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004498 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004499}
Akinobu Mita82069372013-10-14 22:48:04 +09004500static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4501 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004502{
4503 int n;
4504
4505 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004506 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004507 return count;
4508 }
4509 return -EINVAL;
4510}
Akinobu Mita82069372013-10-14 22:48:04 +09004511static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004512
Akinobu Mita82069372013-10-14 22:48:04 +09004513static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04004514{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004515 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004516}
Akinobu Mita82069372013-10-14 22:48:04 +09004517static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004518
Akinobu Mita82069372013-10-14 22:48:04 +09004519static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004520{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004521 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004522}
Akinobu Mita82069372013-10-14 22:48:04 +09004523static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004524
Akinobu Mita82069372013-10-14 22:48:04 +09004525static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004526{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004527 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004528}
Akinobu Mita82069372013-10-14 22:48:04 +09004529static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004530
Akinobu Mita82069372013-10-14 22:48:04 +09004531static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004532{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004533 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004534}
Akinobu Mita82069372013-10-14 22:48:04 +09004535static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004536
Akinobu Mita82069372013-10-14 22:48:04 +09004537static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004538{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004539 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004540}
Akinobu Mita82069372013-10-14 22:48:04 +09004541static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004542
Akinobu Mita82069372013-10-14 22:48:04 +09004543static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004544{
4545 ssize_t count;
4546
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004547 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004548 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4549 sdebug_store_sectors);
4550
Tejun Heoc7badc92015-02-13 14:37:51 -08004551 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4552 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004553 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004554 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004555
4556 return count;
4557}
Akinobu Mita82069372013-10-14 22:48:04 +09004558static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004559
Akinobu Mita82069372013-10-14 22:48:04 +09004560static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004561{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004562 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004563}
Akinobu Mita82069372013-10-14 22:48:04 +09004564static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4565 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004566{
4567 int n;
4568
4569 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004570 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004571 return count;
4572 }
4573 return -EINVAL;
4574}
Akinobu Mita82069372013-10-14 22:48:04 +09004575static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004576
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004577static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4578{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004579 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004580}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004581/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004582static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4583 size_t count)
4584{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004585 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004586
4587 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004588 sdebug_host_lock = (n > 0);
4589 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004590 }
4591 return -EINVAL;
4592}
4593static DRIVER_ATTR_RW(host_lock);
4594
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004595static ssize_t strict_show(struct device_driver *ddp, char *buf)
4596{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004597 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004598}
4599static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4600 size_t count)
4601{
4602 int n;
4603
4604 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004605 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004606 return count;
4607 }
4608 return -EINVAL;
4609}
4610static DRIVER_ATTR_RW(strict);
4611
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004612
Akinobu Mita82069372013-10-14 22:48:04 +09004613/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004614 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4615 files (over those found in the /sys/module/scsi_debug/parameters
4616 directory) is that auxiliary actions can be triggered when an attribute
4617 is changed. For example see: sdebug_add_host_store() above.
4618 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004619
Akinobu Mita82069372013-10-14 22:48:04 +09004620static struct attribute *sdebug_drv_attrs[] = {
4621 &driver_attr_delay.attr,
4622 &driver_attr_opts.attr,
4623 &driver_attr_ptype.attr,
4624 &driver_attr_dsense.attr,
4625 &driver_attr_fake_rw.attr,
4626 &driver_attr_no_lun_0.attr,
4627 &driver_attr_num_tgts.attr,
4628 &driver_attr_dev_size_mb.attr,
4629 &driver_attr_num_parts.attr,
4630 &driver_attr_every_nth.attr,
4631 &driver_attr_max_luns.attr,
4632 &driver_attr_max_queue.attr,
4633 &driver_attr_no_uld.attr,
4634 &driver_attr_scsi_level.attr,
4635 &driver_attr_virtual_gb.attr,
4636 &driver_attr_add_host.attr,
4637 &driver_attr_vpd_use_hostno.attr,
4638 &driver_attr_sector_size.attr,
4639 &driver_attr_dix.attr,
4640 &driver_attr_dif.attr,
4641 &driver_attr_guard.attr,
4642 &driver_attr_ato.attr,
4643 &driver_attr_map.attr,
4644 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004645 &driver_attr_host_lock.attr,
4646 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004647 &driver_attr_strict.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004648 NULL,
4649};
4650ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004652static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004653
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654static int __init scsi_debug_init(void)
4655{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004656 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 int host_to_add;
4658 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004659 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004661 atomic_set(&sdebug_cmnd_count, 0);
4662 atomic_set(&sdebug_completions, 0);
4663 atomic_set(&retired_max_queue, 0);
4664
Douglas Gilbert773642d2016-04-25 12:16:28 -04004665 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004666 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04004667 sdebug_ndelay = 0;
4668 } else if (sdebug_ndelay > 0)
4669 sdebug_delay = DELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004670
Douglas Gilbert773642d2016-04-25 12:16:28 -04004671 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04004672 case 512:
4673 case 1024:
4674 case 2048:
4675 case 4096:
4676 break;
4677 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004678 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004679 return -EINVAL;
4680 }
4681
Douglas Gilbert773642d2016-04-25 12:16:28 -04004682 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004683
4684 case SD_DIF_TYPE0_PROTECTION:
4685 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004686 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004687 case SD_DIF_TYPE3_PROTECTION:
4688 break;
4689
4690 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03004691 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004692 return -EINVAL;
4693 }
4694
Douglas Gilbert773642d2016-04-25 12:16:28 -04004695 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004696 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004697 return -EINVAL;
4698 }
4699
Douglas Gilbert773642d2016-04-25 12:16:28 -04004700 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004701 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004702 return -EINVAL;
4703 }
4704
Douglas Gilbert773642d2016-04-25 12:16:28 -04004705 if (sdebug_physblk_exp > 15) {
4706 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004707 return -EINVAL;
4708 }
4709
Douglas Gilbert773642d2016-04-25 12:16:28 -04004710 if (sdebug_lowest_aligned > 0x3fff) {
4711 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004712 return -EINVAL;
4713 }
4714
Douglas Gilbert773642d2016-04-25 12:16:28 -04004715 if (sdebug_dev_size_mb < 1)
4716 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
4717 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4718 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004719 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720
4721 /* play around with geometry, don't waste too much on track 0 */
4722 sdebug_heads = 8;
4723 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004724 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004726 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02004727 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4729 (sdebug_sectors_per * sdebug_heads);
4730 if (sdebug_cylinders_per >= 1024) {
4731 /* other LLDs do this; implies >= 1GB ram disk ... */
4732 sdebug_heads = 255;
4733 sdebug_sectors_per = 63;
4734 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4735 (sdebug_sectors_per * sdebug_heads);
4736 }
4737
Douglas Gilbert773642d2016-04-25 12:16:28 -04004738 if (0 == sdebug_fake_rw) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004739 fake_storep = vmalloc(sz);
4740 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004741 pr_err("out of memory, 1\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004742 return -ENOMEM;
4743 }
4744 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004745 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004746 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748
Douglas Gilbert773642d2016-04-25 12:16:28 -04004749 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004750 int dif_size;
4751
4752 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4753 dif_storep = vmalloc(dif_size);
4754
Tomas Winklerc12879702015-07-28 16:54:20 +03004755 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004756
4757 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004758 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004759 ret = -ENOMEM;
4760 goto free_vm;
4761 }
4762
4763 memset(dif_storep, 0xff, dif_size);
4764 }
4765
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004766 /* Logical Block Provisioning */
4767 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004768 sdebug_unmap_max_blocks =
4769 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004770
Douglas Gilbert773642d2016-04-25 12:16:28 -04004771 sdebug_unmap_max_desc =
4772 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04004773
Douglas Gilbert773642d2016-04-25 12:16:28 -04004774 sdebug_unmap_granularity =
4775 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004776
Douglas Gilbert773642d2016-04-25 12:16:28 -04004777 if (sdebug_unmap_alignment &&
4778 sdebug_unmap_granularity <=
4779 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004780 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004781 return -EINVAL;
4782 }
4783
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004784 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4785 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04004786
Tomas Winklerc12879702015-07-28 16:54:20 +03004787 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004788
4789 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004790 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004791 ret = -ENOMEM;
4792 goto free_vm;
4793 }
4794
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004795 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004796
4797 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004798 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004799 map_region(0, 2);
4800 }
4801
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004802 pseudo_primary = root_device_register("pseudo_0");
4803 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004804 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004805 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004806 goto free_vm;
4807 }
4808 ret = bus_register(&pseudo_lld_bus);
4809 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004810 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004811 goto dev_unreg;
4812 }
4813 ret = driver_register(&sdebug_driverfs_driver);
4814 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004815 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004816 goto bus_unreg;
4817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818
Douglas Gilbert773642d2016-04-25 12:16:28 -04004819 host_to_add = sdebug_add_host;
4820 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821
4822 for (k = 0; k < host_to_add; k++) {
4823 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004824 pr_err("sdebug_add_adapter failed k=%d\n", k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825 break;
4826 }
4827 }
4828
Douglas Gilbert773642d2016-04-25 12:16:28 -04004829 if (sdebug_verbose)
4830 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03004831
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004833
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004834bus_unreg:
4835 bus_unregister(&pseudo_lld_bus);
4836dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004837 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004838free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03004839 vfree(map_storep);
4840 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004841 vfree(fake_storep);
4842
4843 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844}
4845
4846static void __exit scsi_debug_exit(void)
4847{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004848 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849
4850 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004851 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 for (; k; k--)
4853 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 driver_unregister(&sdebug_driverfs_driver);
4855 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004856 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857
Tomas Winklerde232af2015-07-28 16:54:22 +03004858 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 vfree(fake_storep);
4860}
4861
4862device_initcall(scsi_debug_init);
4863module_exit(scsi_debug_exit);
4864
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865static void sdebug_release_adapter(struct device * dev)
4866{
4867 struct sdebug_host_info *sdbg_host;
4868
4869 sdbg_host = to_sdebug_host(dev);
4870 kfree(sdbg_host);
4871}
4872
4873static int sdebug_add_adapter(void)
4874{
4875 int k, devs_per_host;
4876 int error = 0;
4877 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004878 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004880 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 if (NULL == sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004882 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 return -ENOMEM;
4884 }
4885
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4887
Douglas Gilbert773642d2016-04-25 12:16:28 -04004888 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004890 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4891 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004892 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 error = -ENOMEM;
4894 goto clean;
4895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 }
4897
4898 spin_lock(&sdebug_host_list_lock);
4899 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4900 spin_unlock(&sdebug_host_list_lock);
4901
4902 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004903 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004905 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906
4907 error = device_register(&sdbg_host->dev);
4908
4909 if (error)
4910 goto clean;
4911
Douglas Gilbert773642d2016-04-25 12:16:28 -04004912 ++sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 return error;
4914
4915clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004916 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4917 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 list_del(&sdbg_devinfo->dev_list);
4919 kfree(sdbg_devinfo);
4920 }
4921
4922 kfree(sdbg_host);
4923 return error;
4924}
4925
4926static void sdebug_remove_adapter(void)
4927{
4928 struct sdebug_host_info * sdbg_host = NULL;
4929
4930 spin_lock(&sdebug_host_list_lock);
4931 if (!list_empty(&sdebug_host_list)) {
4932 sdbg_host = list_entry(sdebug_host_list.prev,
4933 struct sdebug_host_info, host_list);
4934 list_del(&sdbg_host->host_list);
4935 }
4936 spin_unlock(&sdebug_host_list_lock);
4937
4938 if (!sdbg_host)
4939 return;
4940
Douglas Gilbert773642d2016-04-25 12:16:28 -04004941 device_unregister(&sdbg_host->dev);
4942 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943}
4944
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004945static int
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004946sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004947{
4948 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004949 unsigned long iflags;
4950 struct sdebug_dev_info *devip;
4951
4952 spin_lock_irqsave(&queued_arr_lock, iflags);
4953 devip = (struct sdebug_dev_info *)sdev->hostdata;
4954 if (NULL == devip) {
4955 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4956 return -ENODEV;
4957 }
4958 num_in_q = atomic_read(&devip->num_in_q);
4959 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004960
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004961 if (qdepth < 1)
4962 qdepth = 1;
4963 /* allow to exceed max host queued_arr elements for testing */
4964 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4965 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004966 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004967
Douglas Gilbert773642d2016-04-25 12:16:28 -04004968 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004969 sdev_printk(KERN_INFO, sdev,
4970 "%s: qdepth=%d, num_in_q=%d\n",
4971 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004972 }
4973 return sdev->queue_depth;
4974}
4975
4976static int
Douglas Gilbert817fd662014-11-24 20:18:02 -05004977check_inject(struct scsi_cmnd *scp)
4978{
4979 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4980
4981 memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4982
Douglas Gilbert773642d2016-04-25 12:16:28 -04004983 if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
Douglas Gilbert817fd662014-11-24 20:18:02 -05004984 atomic_set(&sdebug_cmnd_count, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004985 if (sdebug_every_nth < -1)
4986 sdebug_every_nth = -1;
4987 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004988 return 1; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004989 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05004990 scsi_medium_access_command(scp))
4991 return 1; /* time out reads and writes */
4992 if (sdebug_any_injecting_opt) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004993 if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004994 ep->inj_recovered = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004995 if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004996 ep->inj_transport = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004997 if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004998 ep->inj_dif = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004999 if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005000 ep->inj_dix = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005001 if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005002 ep->inj_short = true;
5003 }
5004 }
5005 return 0;
5006}
5007
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005008static int
Douglas Gilbert185dd232016-04-25 12:16:29 -04005009scsi_debug_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005010{
5011 u8 sdeb_i;
5012 struct scsi_device *sdp = scp->device;
5013 const struct opcode_info_t *oip;
5014 const struct opcode_info_t *r_oip;
5015 struct sdebug_dev_info *devip;
5016 u8 *cmd = scp->cmnd;
5017 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5018 int k, na;
5019 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005020 u32 flags;
5021 u16 sa;
5022 u8 opcode = cmd[0];
5023 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005024
5025 scsi_set_resid(scp, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005026 if (sdebug_verbose && !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005027 char b[120];
5028 int n, len, sb;
5029
5030 len = scp->cmd_len;
5031 sb = (int)sizeof(b);
5032 if (len > 32)
5033 strcpy(b, "too long, over 32 bytes");
5034 else {
5035 for (k = 0, n = 0; k < len && n < sb; ++k)
5036 n += scnprintf(b + n, sb - n, "%02x ",
5037 (u32)cmd[k]);
5038 }
5039 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
5040 }
Tomas Winkler34d55432015-07-28 16:54:21 +03005041 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005042 if ((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)
5043 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005044
5045 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5046 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5047 devip = (struct sdebug_dev_info *)sdp->hostdata;
5048 if (!devip) {
5049 devip = devInfoReg(sdp);
5050 if (NULL == devip)
Douglas Gilbert773642d2016-04-25 12:16:28 -04005051 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16,
5052 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005053 }
5054 na = oip->num_attached;
5055 r_pfp = oip->pfp;
5056 if (na) { /* multiple commands with this opcode */
5057 r_oip = oip;
5058 if (FF_SA & r_oip->flags) {
5059 if (F_SA_LOW & oip->flags)
5060 sa = 0x1f & cmd[1];
5061 else
5062 sa = get_unaligned_be16(cmd + 8);
5063 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5064 if (opcode == oip->opcode && sa == oip->sa)
5065 break;
5066 }
5067 } else { /* since no service action only check opcode */
5068 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5069 if (opcode == oip->opcode)
5070 break;
5071 }
5072 }
5073 if (k > na) {
5074 if (F_SA_LOW & r_oip->flags)
5075 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5076 else if (F_SA_HIGH & r_oip->flags)
5077 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5078 else
5079 mk_sense_invalid_opcode(scp);
5080 goto check_cond;
5081 }
5082 } /* else (when na==0) we assume the oip is a match */
5083 flags = oip->flags;
5084 if (F_INV_OP & flags) {
5085 mk_sense_invalid_opcode(scp);
5086 goto check_cond;
5087 }
5088 if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005089 if (sdebug_verbose)
5090 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5091 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005092 mk_sense_invalid_opcode(scp);
5093 goto check_cond;
5094 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005095 if (sdebug_strict) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005096 u8 rem;
5097 int j;
5098
5099 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5100 rem = ~oip->len_mask[k] & cmd[k];
5101 if (rem) {
5102 for (j = 7; j >= 0; --j, rem <<= 1) {
5103 if (0x80 & rem)
5104 break;
5105 }
5106 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5107 goto check_cond;
5108 }
5109 }
5110 }
5111 if (!(F_SKIP_UA & flags) &&
5112 SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) {
5113 errsts = check_readiness(scp, UAS_ONLY, devip);
5114 if (errsts)
5115 goto check_cond;
5116 }
5117 if ((F_M_ACCESS & flags) && devip->stopped) {
5118 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005119 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005120 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5121 "%s\n", my_name, "initializing command "
5122 "required");
5123 errsts = check_condition_result;
5124 goto fini;
5125 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005126 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005127 goto fini;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005128 if (sdebug_every_nth) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005129 if (check_inject(scp))
5130 return 0; /* ignore command: make trouble */
5131 }
5132 if (oip->pfp) /* if this command has a resp_* function, call it */
5133 errsts = oip->pfp(scp, devip);
5134 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5135 errsts = r_pfp(scp, devip);
5136
5137fini:
5138 return schedule_resp(scp, devip, errsts,
Douglas Gilbert773642d2016-04-25 12:16:28 -04005139 ((F_DELAY_OVERR & flags) ? 0 : sdebug_delay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005140check_cond:
5141 return schedule_resp(scp, devip, check_condition_result, 0);
5142}
5143
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005144static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005145 .show_info = scsi_debug_show_info,
5146 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005147 .proc_name = sdebug_proc_name,
5148 .name = "SCSI DEBUG",
5149 .info = scsi_debug_info,
5150 .slave_alloc = scsi_debug_slave_alloc,
5151 .slave_configure = scsi_debug_slave_configure,
5152 .slave_destroy = scsi_debug_slave_destroy,
5153 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005154 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005155 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005156 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005157 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005158 .eh_target_reset_handler = scsi_debug_target_reset,
5159 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005160 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005161 .can_queue = SCSI_DEBUG_CANQUEUE,
5162 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005163 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005164 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005165 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005166 .use_clustering = DISABLE_CLUSTERING,
5167 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005168 .track_queue_depth = 1,
Douglas Gilbert817fd662014-11-24 20:18:02 -05005169 .cmd_size = sizeof(struct sdebug_scmd_extra_t),
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005170};
5171
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172static int sdebug_driver_probe(struct device * dev)
5173{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005174 int error = 0;
5175 struct sdebug_host_info *sdbg_host;
5176 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005177 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178
5179 sdbg_host = to_sdebug_host(dev);
5180
Douglas Gilbert773642d2016-04-25 12:16:28 -04005181 sdebug_driver_template.can_queue = sdebug_max_queue;
5182 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005183 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005184 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5185 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005186 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005187 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005189 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190
5191 sdbg_host->shost = hpnt;
5192 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005193 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5194 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005196 hpnt->max_id = sdebug_num_tgts;
5197 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005198 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005200 host_prot = 0;
5201
Douglas Gilbert773642d2016-04-25 12:16:28 -04005202 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005203
5204 case SD_DIF_TYPE1_PROTECTION:
5205 host_prot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005206 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005207 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
5208 break;
5209
5210 case SD_DIF_TYPE2_PROTECTION:
5211 host_prot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005212 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005213 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
5214 break;
5215
5216 case SD_DIF_TYPE3_PROTECTION:
5217 host_prot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005218 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005219 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
5220 break;
5221
5222 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005223 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005224 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
5225 break;
5226 }
5227
5228 scsi_host_set_prot(hpnt, host_prot);
5229
Tomas Winklerc12879702015-07-28 16:54:20 +03005230 pr_info("host protection%s%s%s%s%s%s%s\n",
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005231 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5232 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5233 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5234 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5235 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5236 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5237 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5238
Douglas Gilbert773642d2016-04-25 12:16:28 -04005239 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005240 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5241 else
5242 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5243
Douglas Gilbert773642d2016-04-25 12:16:28 -04005244 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5245 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 error = scsi_add_host(hpnt, &sdbg_host->dev);
5247 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005248 pr_err("scsi_add_host failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 error = -ENODEV;
5250 scsi_host_put(hpnt);
5251 } else
5252 scsi_scan_host(hpnt);
5253
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005254 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255}
5256
5257static int sdebug_driver_remove(struct device * dev)
5258{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005260 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261
5262 sdbg_host = to_sdebug_host(dev);
5263
5264 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005265 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 return -ENODEV;
5267 }
5268
5269 scsi_remove_host(sdbg_host->shost);
5270
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005271 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5272 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 list_del(&sdbg_devinfo->dev_list);
5274 kfree(sdbg_devinfo);
5275 }
5276
5277 scsi_host_put(sdbg_host->shost);
5278 return 0;
5279}
5280
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005281static int pseudo_lld_bus_match(struct device *dev,
5282 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005284 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005286
5287static struct bus_type pseudo_lld_bus = {
5288 .name = "pseudo",
5289 .match = pseudo_lld_bus_match,
5290 .probe = sdebug_driver_probe,
5291 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005292 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005293};