diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_spi.c')
| -rw-r--r-- | drivers/scsi/scsi_transport_spi.c | 132 |
1 files changed, 73 insertions, 59 deletions
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index d0219e36080c..fe47850a8258 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Parallel SCSI (SPI) transport specific attributes exported to sysfs. * * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. * Copyright (c) 2004, 2005 James Bottomley <James.Bottomley@SteelEye.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/ctype.h> #include <linux/init.h> @@ -26,6 +13,7 @@ #include <linux/mutex.h> #include <linux/sysfs.h> #include <linux/slab.h> +#include <linux/suspend.h> #include <scsi/scsi.h> #include "scsi_priv.h" #include <scsi/scsi_device.h> @@ -50,14 +38,14 @@ /* Our blacklist flags */ enum { - SPI_BLIST_NOIUS = 0x1, + SPI_BLIST_NOIUS = (__force blist_flags_t)0x1, }; /* blacklist table, modelled on scsi_devinfo.c */ static struct { char *vendor; char *model; - unsigned flags; + blist_flags_t flags; } spi_static_device_list[] __initdata = { {"HP", "Ultrium 3-SCSI", SPI_BLIST_NOIUS }, {"IBM", "ULTRIUM-TD3", SPI_BLIST_NOIUS }, @@ -117,29 +105,33 @@ static int sprint_frac(char *dest, int value, int denom) } static int spi_execute(struct scsi_device *sdev, const void *cmd, - enum dma_data_direction dir, - void *buffer, unsigned bufflen, + enum req_op op, void *buffer, unsigned int bufflen, struct scsi_sense_hdr *sshdr) { - int i, result; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - struct scsi_sense_hdr sshdr_tmp; - - if (!sshdr) - sshdr = &sshdr_tmp; - - for(i = 0; i < DV_RETRIES; i++) { - result = scsi_execute(sdev, cmd, dir, buffer, bufflen, sense, - sshdr, DV_TIMEOUT, /* retries */ 1, - REQ_FAILFAST_DEV | - REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER, - 0, NULL); - if (!(driver_byte(result) & DRIVER_SENSE) || - sshdr->sense_key != UNIT_ATTENTION) - break; - } - return result; + blk_opf_t opf = op | REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; + struct scsi_failure failure_defs[] = { + { + .sense = UNIT_ATTENTION, + .asc = SCMD_FAILURE_ASC_ANY, + .ascq = SCMD_FAILURE_ASCQ_ANY, + .allowed = DV_RETRIES, + .result = SAM_STAT_CHECK_CONDITION, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; + const struct scsi_exec_args exec_args = { + /* bypass the SDEV_QUIESCE state with BLK_MQ_REQ_PM */ + .req_flags = BLK_MQ_REQ_PM, + .sshdr = sshdr, + .failures = &failures, + }; + + return scsi_execute_cmd(sdev, cmd, opf, buffer, bufflen, DV_TIMEOUT, 1, + &exec_args); } static struct { @@ -221,9 +213,11 @@ static int spi_device_configure(struct transport_container *tc, { struct scsi_device *sdev = to_scsi_device(dev); struct scsi_target *starget = sdev->sdev_target; - unsigned bflags = scsi_get_device_flags_keyed(sdev, &sdev->inquiry[8], - &sdev->inquiry[16], - SCSI_DEVINFO_SPI); + blist_flags_t bflags; + + bflags = scsi_get_device_flags_keyed(sdev, &sdev->inquiry[8], + &sdev->inquiry[16], + SCSI_DEVINFO_SPI); /* Populate the target capability fields with the values * gleaned from the device inquiry */ @@ -349,7 +343,7 @@ store_spi_transport_##field(struct device *dev, \ struct spi_transport_attrs *tp \ = (struct spi_transport_attrs *)&starget->starget_data; \ \ - if (i->f->set_##field) \ + if (!i->f->set_##field) \ return -EINVAL; \ val = simple_strtoul(buf, NULL, 0); \ if (val > tp->max_##field) \ @@ -681,12 +675,12 @@ spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer, } for (r = 0; r < retries; r++) { - result = spi_execute(sdev, spi_write_buffer, DMA_TO_DEVICE, + result = spi_execute(sdev, spi_write_buffer, REQ_OP_DRV_OUT, buffer, len, &sshdr); - if(result || !scsi_device_online(sdev)) { + if (result || !scsi_device_online(sdev)) { scsi_device_set_state(sdev, SDEV_QUIESCE); - if (scsi_sense_valid(&sshdr) + if (result > 0 && scsi_sense_valid(&sshdr) && sshdr.sense_key == ILLEGAL_REQUEST /* INVALID FIELD IN CDB */ && sshdr.asc == 0x24 && sshdr.ascq == 0x00) @@ -703,7 +697,7 @@ spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer, } memset(ptr, 0, len); - spi_execute(sdev, spi_read_buffer, DMA_FROM_DEVICE, + spi_execute(sdev, spi_read_buffer, REQ_OP_DRV_IN, ptr, len, NULL); scsi_device_set_state(sdev, SDEV_QUIESCE); @@ -728,7 +722,7 @@ spi_dv_device_compare_inquiry(struct scsi_device *sdev, u8 *buffer, for (r = 0; r < retries; r++) { memset(ptr, 0, len); - result = spi_execute(sdev, spi_inquiry, DMA_FROM_DEVICE, + result = spi_execute(sdev, spi_inquiry, REQ_OP_DRV_IN, ptr, len, NULL); if(result || !scsi_device_online(sdev)) { @@ -819,11 +813,11 @@ spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer) * fails, the device won't let us write to the echo buffer * so just return failure */ - const char spi_test_unit_ready[] = { + static const char spi_test_unit_ready[] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 }; - const char spi_read_buffer_descriptor[] = { + static const char spi_read_buffer_descriptor[] = { READ_BUFFER, 0x0b, 0, 0, 0, 0, 0, 0, 4, 0 }; @@ -834,7 +828,7 @@ spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer) * (reservation conflict, device not ready, etc) just * skip the write tests */ for (l = 0; ; l++) { - result = spi_execute(sdev, spi_test_unit_ready, DMA_NONE, + result = spi_execute(sdev, spi_test_unit_ready, REQ_OP_DRV_IN, NULL, 0, NULL); if(result) { @@ -847,7 +841,7 @@ spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer) } result = spi_execute(sdev, spi_read_buffer_descriptor, - DMA_FROM_DEVICE, buffer, 4, NULL); + REQ_OP_DRV_IN, buffer, 4, NULL); if (result) /* Device has no echo buffer */ @@ -991,7 +985,8 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) } -/** spi_dv_device - Do Domain Validation on the device +/** + * spi_dv_device - Do Domain Validation on the device * @sdev: scsi device to validate * * Performs the domain validation on the given device in the @@ -1004,25 +999,38 @@ void spi_dv_device(struct scsi_device *sdev) { struct scsi_target *starget = sdev->sdev_target; - u8 *buffer; const int len = SPI_MAX_ECHO_BUFFER_SIZE*2; + unsigned int sleep_flags; + u8 *buffer; + + /* + * Because this function and the power management code both call + * scsi_device_quiesce(), it is not safe to perform domain validation + * while suspend or resume is in progress. Hence the + * lock/unlock_system_sleep() calls. + */ + sleep_flags = lock_system_sleep(); + + if (scsi_autopm_get_device(sdev)) + goto unlock_system_sleep; if (unlikely(spi_dv_in_progress(starget))) - return; + goto put_autopm; if (unlikely(scsi_device_get(sdev))) - return; + goto put_autopm; + spi_dv_in_progress(starget) = 1; buffer = kzalloc(len, GFP_KERNEL); if (unlikely(!buffer)) - goto out_put; + goto put_sdev; /* We need to verify that the actual device will quiesce; the * later target quiesce is just a nice to have */ if (unlikely(scsi_device_quiesce(sdev))) - goto out_free; + goto free_buffer; scsi_target_quiesce(starget); @@ -1042,11 +1050,17 @@ spi_dv_device(struct scsi_device *sdev) spi_initial_dv(starget) = 1; - out_free: +free_buffer: kfree(buffer); - out_put: + +put_sdev: spi_dv_in_progress(starget) = 0; scsi_device_put(sdev); +put_autopm: + scsi_autopm_put_device(sdev); + +unlock_system_sleep: + unlock_system_sleep(sleep_flags); } EXPORT_SYMBOL(spi_dv_device); @@ -1218,7 +1232,7 @@ int spi_populate_tag_msg(unsigned char *msg, struct scsi_cmnd *cmd) { if (cmd->flags & SCMD_TAGGED) { *msg++ = SIMPLE_QUEUE_TAG; - *msg++ = cmd->request->tag; + *msg++ = scsi_cmd_to_rq(cmd)->tag; return 2; } |
