diff options
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 46 |
1 files changed, 38 insertions, 8 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index aa17e718666e..db52222885b7 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -1973,27 +1973,57 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, | |||
1973 | } | 1973 | } |
1974 | EXPORT_SYMBOL(scsi_mode_sense); | 1974 | EXPORT_SYMBOL(scsi_mode_sense); |
1975 | 1975 | ||
1976 | /** | ||
1977 | * scsi_test_unit_ready - test if unit is ready | ||
1978 | * @sdev: scsi device to change the state of. | ||
1979 | * @timeout: command timeout | ||
1980 | * @retries: number of retries before failing | ||
1981 | * @sshdr_external: Optional pointer to struct scsi_sense_hdr for | ||
1982 | * returning sense. Make sure that this is cleared before passing | ||
1983 | * in. | ||
1984 | * | ||
1985 | * Returns zero if unsuccessful or an error if TUR failed. For | ||
1986 | * removable media, a return of NOT_READY or UNIT_ATTENTION is | ||
1987 | * translated to success, with the ->changed flag updated. | ||
1988 | **/ | ||
1976 | int | 1989 | int |
1977 | scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) | 1990 | scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, |
1991 | struct scsi_sense_hdr *sshdr_external) | ||
1978 | { | 1992 | { |
1979 | char cmd[] = { | 1993 | char cmd[] = { |
1980 | TEST_UNIT_READY, 0, 0, 0, 0, 0, | 1994 | TEST_UNIT_READY, 0, 0, 0, 0, 0, |
1981 | }; | 1995 | }; |
1982 | struct scsi_sense_hdr sshdr; | 1996 | struct scsi_sense_hdr *sshdr; |
1983 | int result; | 1997 | int result; |
1984 | 1998 | ||
1985 | result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr, | 1999 | if (!sshdr_external) |
1986 | timeout, retries); | 2000 | sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); |
2001 | else | ||
2002 | sshdr = sshdr_external; | ||
2003 | |||
2004 | /* try to eat the UNIT_ATTENTION if there are enough retries */ | ||
2005 | do { | ||
2006 | result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr, | ||
2007 | timeout, retries); | ||
2008 | } while ((driver_byte(result) & DRIVER_SENSE) && | ||
2009 | sshdr && sshdr->sense_key == UNIT_ATTENTION && | ||
2010 | --retries); | ||
2011 | |||
2012 | if (!sshdr) | ||
2013 | /* could not allocate sense buffer, so can't process it */ | ||
2014 | return result; | ||
1987 | 2015 | ||
1988 | if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) { | 2016 | if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) { |
1989 | 2017 | ||
1990 | if ((scsi_sense_valid(&sshdr)) && | 2018 | if ((scsi_sense_valid(sshdr)) && |
1991 | ((sshdr.sense_key == UNIT_ATTENTION) || | 2019 | ((sshdr->sense_key == UNIT_ATTENTION) || |
1992 | (sshdr.sense_key == NOT_READY))) { | 2020 | (sshdr->sense_key == NOT_READY))) { |
1993 | sdev->changed = 1; | 2021 | sdev->changed = 1; |
1994 | result = 0; | 2022 | result = 0; |
1995 | } | 2023 | } |
1996 | } | 2024 | } |
2025 | if (!sshdr_external) | ||
2026 | kfree(sshdr); | ||
1997 | return result; | 2027 | return result; |
1998 | } | 2028 | } |
1999 | EXPORT_SYMBOL(scsi_test_unit_ready); | 2029 | EXPORT_SYMBOL(scsi_test_unit_ready); |