From 684b7fe976554d12e6266d7280c87a0f3feff02e Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 27 Feb 2007 22:39:44 -0500 Subject: [SCSI] constants.c: cleanup, verbose result printing Clean up constants.c and make result printing more user friendly: - Refactor the command and sense functions so that the actual formatting can be called from the various helper functions with the correct prefix. - Replace scsi_print_hostbyte() and scsi_print_driverbyte() with scsi_print_result() which is verbose when CONFIG_SCSI_CONSTANTS is on. Signed-off-by: Martin K. Petersen Signed-off-by: James Bottomley --- include/scsi/scsi_dbg.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index 3bbbfbe8cbf..5a43a4cd96c 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -5,14 +5,16 @@ struct scsi_cmnd; struct scsi_sense_hdr; extern void scsi_print_command(struct scsi_cmnd *); -extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *); extern void __scsi_print_command(unsigned char *); -extern void scsi_print_sense(const char *, struct scsi_cmnd *); +extern void scsi_show_extd_sense(unsigned char, unsigned char); +extern void scsi_show_sense_hdr(struct scsi_sense_hdr *); +extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *); +extern void scsi_print_sense(char *, struct scsi_cmnd *); extern void __scsi_print_sense(const char *name, const unsigned char *sense_buffer, int sense_len); -extern void scsi_print_driverbyte(int); -extern void scsi_print_hostbyte(int); +extern void scsi_show_result(int); +extern void scsi_print_result(struct scsi_cmnd *); extern void scsi_print_status(unsigned char); extern const char *scsi_sense_key_string(unsigned char); extern const char *scsi_extd_sense_format(unsigned char, unsigned char); -- cgit v1.2.3-70-g09d2 From a4d04a4cd9881e89fdc62107b6b57053438f2b30 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 27 Feb 2007 22:40:27 -0500 Subject: [SCSI] Make error printing more verbose This patch enhances SCSI error printing by: - Making use of scsi_print_result() in the completion functions. - Having scmd_printk() output the disk name (when applicable). Signed-off-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 47 +++++++++++++++++----------------------------- drivers/scsi/scsi_lib.c | 4 +--- include/scsi/scsi_device.h | 8 ++++++-- 3 files changed, 24 insertions(+), 35 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1c89ee3e69b..4c1e3133476 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -344,7 +344,6 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost) void scsi_log_send(struct scsi_cmnd *cmd) { unsigned int level; - struct scsi_device *sdev; /* * If ML QUEUE log level is greater than or equal to: @@ -361,22 +360,17 @@ void scsi_log_send(struct scsi_cmnd *cmd) level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS); if (level > 1) { - sdev = cmd->device; - sdev_printk(KERN_INFO, sdev, "send "); + scmd_printk(KERN_INFO, cmd, "Send: "); if (level > 2) printk("0x%p ", cmd); - /* - * spaces to match disposition and cmd->result - * output in scsi_log_completion. - */ - printk(" "); + printk("\n"); scsi_print_command(cmd); if (level > 3) { printk(KERN_INFO "buffer = 0x%p, bufflen = %d," " done = 0x%p, queuecommand 0x%p\n", cmd->request_buffer, cmd->request_bufflen, cmd->done, - sdev->host->hostt->queuecommand); + cmd->device->host->hostt->queuecommand); } } @@ -386,7 +380,6 @@ void scsi_log_send(struct scsi_cmnd *cmd) void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) { unsigned int level; - struct scsi_device *sdev; /* * If ML COMPLETE log level is greater than or equal to: @@ -405,8 +398,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) SCSI_LOG_MLCOMPLETE_BITS); if (((level > 0) && (cmd->result || disposition != SUCCESS)) || (level > 1)) { - sdev = cmd->device; - sdev_printk(KERN_INFO, sdev, "done "); + scmd_printk(KERN_INFO, cmd, "Done: "); if (level > 2) printk("0x%p ", cmd); /* @@ -415,40 +407,35 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) */ switch (disposition) { case SUCCESS: - printk("SUCCESS"); + printk("SUCCESS\n"); break; case NEEDS_RETRY: - printk("RETRY "); + printk("RETRY\n"); break; case ADD_TO_MLQUEUE: - printk("MLQUEUE"); + printk("MLQUEUE\n"); break; case FAILED: - printk("FAILED "); + printk("FAILED\n"); break; case TIMEOUT_ERROR: /* * If called via scsi_times_out. */ - printk("TIMEOUT"); + printk("TIMEOUT\n"); break; default: - printk("UNKNOWN"); + printk("UNKNOWN\n"); } - printk(" %8x ", cmd->result); + scsi_print_result(cmd); scsi_print_command(cmd); - if (status_byte(cmd->result) & CHECK_CONDITION) { - /* - * XXX The scsi_print_sense formatting/prefix - * doesn't match this function. - */ + if (status_byte(cmd->result) & CHECK_CONDITION) scsi_print_sense("", cmd); - } - if (level > 3) { - printk(KERN_INFO "scsi host busy %d failed %d\n", - sdev->host->host_busy, - sdev->host->host_failed); - } + if (level > 3) + scmd_printk(KERN_INFO, cmd, + "scsi host busy %d failed %d\n", + cmd->device->host->host_busy, + cmd->device->host->host_failed); } } } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9f7482d0b59..5f955707d90 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -968,9 +968,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } if (result) { if (!(req->cmd_flags & REQ_QUIET)) { - scmd_printk(KERN_INFO, cmd, - "SCSI error: return code = 0x%08x\n", - result); + scsi_print_result(cmd); if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); } diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 9dd37e2f5a8..c86e6ce143d 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -5,6 +5,7 @@ #include #include #include +#include #include struct request_queue; @@ -154,8 +155,11 @@ struct scsi_device { #define sdev_printk(prefix, sdev, fmt, a...) \ dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a) -#define scmd_printk(prefix, scmd, fmt, a...) \ - dev_printk(prefix, &(scmd)->device->sdev_gendev, fmt, ##a) +#define scmd_printk(prefix, scmd, fmt, a...) \ + (scmd)->request->rq_disk ? \ + sdev_printk(prefix, (scmd)->device, "[%s] " fmt, \ + (scmd)->request->rq_disk->disk_name, ##a) : \ + sdev_printk(prefix, (scmd)->device, fmt, ##a) enum scsi_target_state { STARGET_RUNNING = 1, -- cgit v1.2.3-70-g09d2 From e73aec8247032ee730b5f38edf48922c4f72522e Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 27 Feb 2007 22:40:55 -0500 Subject: [SCSI] sd: make printing use a common prefix Make SCSI disk printing more consistent: - Define sd_printk(), sd_print_sense_hdr() and sd_print_result() - Move relevant header bits into sd.h - Remove all the legacy disk_name passing and use scsi_disk pointers where possible - Switch printk() lines to the new sd_ functions so that output is consistent Signed-off-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 253 ++++++++++++++++++++---------------------------------- include/scsi/sd.h | 70 +++++++++++++++ 2 files changed, 165 insertions(+), 158 deletions(-) create mode 100644 include/scsi/sd.h (limited to 'include') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 5a8f55fea5f..b5562b851e7 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -58,16 +58,10 @@ #include #include #include +#include #include "scsi_logging.h" -/* - * More than enough for everybody ;) The huge number of majors - * is a leftover from 16bit dev_t days, we don't really need that - * much numberspace. - */ -#define SD_MAJORS 16 - MODULE_AUTHOR("Eric Youngdale"); MODULE_DESCRIPTION("SCSI disk (sd) driver"); MODULE_LICENSE("GPL"); @@ -89,45 +83,6 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR); -/* - * This is limited by the naming scheme enforced in sd_probe, - * add another character to it if you really need more disks. - */ -#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26) - -/* - * Time out in seconds for disks and Magneto-opticals (which are slower). - */ -#define SD_TIMEOUT (30 * HZ) -#define SD_MOD_TIMEOUT (75 * HZ) - -/* - * Number of allowed retries - */ -#define SD_MAX_RETRIES 5 -#define SD_PASSTHROUGH_RETRIES 1 - -/* - * Size of the initial data buffer for mode and read capacity data - */ -#define SD_BUF_SIZE 512 - -struct scsi_disk { - struct scsi_driver *driver; /* always &sd_template */ - struct scsi_device *device; - struct class_device cdev; - struct gendisk *disk; - unsigned int openers; /* protected by BKL for now, yuck */ - sector_t capacity; /* size in 512-byte sectors */ - u32 index; - u8 media_present; - u8 write_prot; - unsigned WCE : 1; /* state of disk WCE bit */ - unsigned RCD : 1; /* state of disk RCD bit, unused */ - unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ -}; -#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev) - static DEFINE_IDR(sd_index_idr); static DEFINE_SPINLOCK(sd_index_lock); @@ -136,20 +91,6 @@ static DEFINE_SPINLOCK(sd_index_lock); * object after last put) */ static DEFINE_MUTEX(sd_ref_mutex); -static int sd_revalidate_disk(struct gendisk *disk); -static void sd_rw_intr(struct scsi_cmnd * SCpnt); - -static int sd_probe(struct device *); -static int sd_remove(struct device *); -static void sd_shutdown(struct device *dev); -static void sd_rescan(struct device *); -static int sd_init_command(struct scsi_cmnd *); -static int sd_issue_flush(struct device *, sector_t *); -static void sd_prepare_flush(request_queue_t *, struct request *); -static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, - unsigned char *buffer); -static void scsi_disk_release(struct class_device *cdev); - static const char *sd_cache_types[] = { "write through", "none", "write back", "write back, no read (daft)" @@ -199,7 +140,7 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf, if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT, SD_MAX_RETRIES, &data, &sshdr)) { if (scsi_sense_valid(&sshdr)) - scsi_print_sense_hdr(sdkp->disk->disk_name, &sshdr); + sd_print_sense_hdr(sdkp, &sshdr); return -EINVAL; } sd_revalidate_disk(sdkp->disk); @@ -407,7 +348,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) */ if (sdp->sector_size == 1024) { if ((block & 1) || (rq->nr_sectors & 1)) { - printk(KERN_ERR "sd: Bad block number requested"); + scmd_printk(KERN_ERR, SCpnt, + "Bad block number requested\n"); return 0; } else { block = block >> 1; @@ -416,7 +358,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) } if (sdp->sector_size == 2048) { if ((block & 3) || (rq->nr_sectors & 3)) { - printk(KERN_ERR "sd: Bad block number requested"); + scmd_printk(KERN_ERR, SCpnt, + "Bad block number requested\n"); return 0; } else { block = block >> 2; @@ -425,7 +368,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) } if (sdp->sector_size == 4096) { if ((block & 7) || (rq->nr_sectors & 7)) { - printk(KERN_ERR "sd: Bad block number requested"); + scmd_printk(KERN_ERR, SCpnt, + "Bad block number requested\n"); return 0; } else { block = block >> 3; @@ -442,7 +386,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) SCpnt->cmnd[0] = READ_6; SCpnt->sc_data_direction = DMA_FROM_DEVICE; } else { - printk(KERN_ERR "sd: Unknown command %x\n", rq->cmd_flags); + scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags); return 0; } @@ -490,7 +434,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) * during operation and thus turned off * use_10_for_rw. */ - printk(KERN_ERR "sd: FUA write on READ/WRITE(6) drive\n"); + scmd_printk(KERN_ERR, SCpnt, + "FUA write on READ/WRITE(6) drive\n"); return 0; } @@ -786,9 +731,10 @@ not_present: return 1; } -static int sd_sync_cache(struct scsi_device *sdp) +static int sd_sync_cache(struct scsi_disk *sdkp) { int retries, res; + struct scsi_device *sdp = sdkp->device; struct scsi_sense_hdr sshdr; if (!scsi_device_online(sdp)) @@ -809,12 +755,10 @@ static int sd_sync_cache(struct scsi_device *sdp) break; } - if (res) { printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " - "host = %d, driver = %02x\n ", - status_byte(res), msg_byte(res), - host_byte(res), driver_byte(res)); - if (driver_byte(res) & DRIVER_SENSE) - scsi_print_sense_hdr("sd", &sshdr); + if (res) { + sd_print_result(sdkp, res); + if (driver_byte(res) & DRIVER_SENSE) + sd_print_sense_hdr(sdkp, &sshdr); } return res; @@ -823,14 +767,13 @@ static int sd_sync_cache(struct scsi_device *sdp) static int sd_issue_flush(struct device *dev, sector_t *error_sector) { int ret = 0; - struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); if (!sdkp) return -ENODEV; if (sdkp->WCE) - ret = sd_sync_cache(sdp); + ret = sd_sync_cache(sdkp); scsi_disk_put(sdkp); return ret; } @@ -1025,7 +968,7 @@ static int media_not_present(struct scsi_disk *sdkp, * spinup disk - called only in sd_revalidate_disk() */ static void -sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) +sd_spinup_disk(struct scsi_disk *sdkp) { unsigned char cmd[10]; unsigned long spintime_expire = 0; @@ -1069,9 +1012,10 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) if ((driver_byte(the_result) & DRIVER_SENSE) == 0) { /* no sense, TUR either succeeded or failed * with a status error */ - if(!spintime && !scsi_status_is_good(the_result)) - printk(KERN_NOTICE "%s: Unit Not Ready, " - "error = 0x%x\n", diskname, the_result); + if(!spintime && !scsi_status_is_good(the_result)) { + sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n"); + sd_print_result(sdkp, the_result); + } break; } @@ -1096,8 +1040,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) */ } else if (sense_valid && sshdr.sense_key == NOT_READY) { if (!spintime) { - printk(KERN_NOTICE "%s: Spinning up disk...", - diskname); + sd_printk(KERN_NOTICE, sdkp, "Spinning up disk..."); cmd[0] = START_STOP; cmd[1] = 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); @@ -1130,9 +1073,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) /* we don't understand the sense code, so it's * probably pointless to loop */ if(!spintime) { - printk(KERN_NOTICE "%s: Unit Not Ready, " - "sense:\n", diskname); - scsi_print_sense_hdr("", &sshdr); + sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n"); + sd_print_sense_hdr(sdkp, &sshdr); } break; } @@ -1151,8 +1093,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) * read disk capacity */ static void -sd_read_capacity(struct scsi_disk *sdkp, char *diskname, - unsigned char *buffer) +sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) { unsigned char cmd[16]; int the_result, retries; @@ -1191,18 +1132,12 @@ repeat: } while (the_result && retries); if (the_result && !longrc) { - printk(KERN_NOTICE "%s : READ CAPACITY failed.\n" - "%s : status=%x, message=%02x, host=%d, driver=%02x \n", - diskname, diskname, - status_byte(the_result), - msg_byte(the_result), - host_byte(the_result), - driver_byte(the_result)); - + sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n"); + sd_print_result(sdkp, the_result); if (driver_byte(the_result) & DRIVER_SENSE) - scsi_print_sense_hdr("sd", &sshdr); + sd_print_sense_hdr(sdkp, &sshdr); else - printk("%s : sense not available. \n", diskname); + sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n"); /* Set dirty bit for removable devices if not ready - * sometimes drives will not report this properly. */ @@ -1218,16 +1153,10 @@ repeat: return; } else if (the_result && longrc) { /* READ CAPACITY(16) has been failed */ - printk(KERN_NOTICE "%s : READ CAPACITY(16) failed.\n" - "%s : status=%x, message=%02x, host=%d, driver=%02x \n", - diskname, diskname, - status_byte(the_result), - msg_byte(the_result), - host_byte(the_result), - driver_byte(the_result)); - printk(KERN_NOTICE "%s : use 0xffffffff as device size\n", - diskname); - + sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n"); + sd_print_result(sdkp, the_result); + sd_printk(KERN_NOTICE, sdkp, "Use 0xffffffff as device size\n"); + sdkp->capacity = 1 + (sector_t) 0xffffffff; goto got_data; } @@ -1238,14 +1167,14 @@ repeat: if (buffer[0] == 0xff && buffer[1] == 0xff && buffer[2] == 0xff && buffer[3] == 0xff) { if(sizeof(sdkp->capacity) > 4) { - printk(KERN_NOTICE "%s : very big device. try to use" - " READ CAPACITY(16).\n", diskname); + sd_printk(KERN_NOTICE, sdkp, "Very big device. " + "Trying to use READ CAPACITY(16).\n"); longrc = 1; goto repeat; } - printk(KERN_ERR "%s: too big for this kernel. Use a " - "kernel compiled with support for large block " - "devices.\n", diskname); + sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use " + "a kernel compiled with support for large " + "block devices.\n"); sdkp->capacity = 0; goto got_data; } @@ -1284,8 +1213,8 @@ repeat: got_data: if (sector_size == 0) { sector_size = 512; - printk(KERN_NOTICE "%s : sector size 0 reported, " - "assuming 512.\n", diskname); + sd_printk(KERN_NOTICE, sdkp, "Sector size 0 reported, " + "assuming 512.\n"); } if (sector_size != 512 && @@ -1293,8 +1222,8 @@ got_data: sector_size != 2048 && sector_size != 4096 && sector_size != 256) { - printk(KERN_NOTICE "%s : unsupported sector size " - "%d.\n", diskname, sector_size); + sd_printk(KERN_NOTICE, sdkp, "Unsupported sector size %d.\n", + sector_size); /* * The user might want to re-format the drive with * a supported sectorsize. Once this happens, it @@ -1327,10 +1256,10 @@ got_data: mb -= sz - 974; sector_div(mb, 1950); - printk(KERN_NOTICE "SCSI device %s: " - "%llu %d-byte hdwr sectors (%llu MB)\n", - diskname, (unsigned long long)sdkp->capacity, - hard_sector, (unsigned long long)mb); + sd_printk(KERN_NOTICE, sdkp, + "%llu %d-byte hardware sectors (%llu MB)\n", + (unsigned long long)sdkp->capacity, + hard_sector, (unsigned long long)mb); } /* Rescale capacity to 512-byte units */ @@ -1362,8 +1291,7 @@ sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage, * called with buffer of length SD_BUF_SIZE */ static void -sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, - unsigned char *buffer) +sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) { int res; struct scsi_device *sdp = sdkp->device; @@ -1371,7 +1299,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, set_disk_ro(sdkp->disk, 0); if (sdp->skip_ms_page_3f) { - printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname); + sd_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n"); return; } @@ -1403,15 +1331,16 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, } if (!scsi_status_is_good(res)) { - printk(KERN_WARNING - "%s: test WP failed, assume Write Enabled\n", diskname); + sd_printk(KERN_WARNING, sdkp, + "Test WP failed, assume Write Enabled\n"); } else { sdkp->write_prot = ((data.device_specific & 0x80) != 0); set_disk_ro(sdkp->disk, sdkp->write_prot); - printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname, - sdkp->write_prot ? "on" : "off"); - printk(KERN_DEBUG "%s: Mode Sense: %02x %02x %02x %02x\n", - diskname, buffer[0], buffer[1], buffer[2], buffer[3]); + sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n", + sdkp->write_prot ? "on" : "off"); + sd_printk(KERN_DEBUG, sdkp, + "Mode Sense: %02x %02x %02x %02x\n", + buffer[0], buffer[1], buffer[2], buffer[3]); } } @@ -1420,8 +1349,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, * called with buffer of length SD_BUF_SIZE */ static void -sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, - unsigned char *buffer) +sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) { int len = 0, res; struct scsi_device *sdp = sdkp->device; @@ -1450,8 +1378,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, if (!data.header_length) { modepage = 6; - printk(KERN_ERR "%s: missing header in MODE_SENSE response\n", - diskname); + sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n"); } /* that went OK, now ask for the proper length */ @@ -1478,13 +1405,12 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, int offset = data.header_length + data.block_descriptor_length; if (offset >= SD_BUF_SIZE - 2) { - printk(KERN_ERR "%s: malformed MODE SENSE response", - diskname); + sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n"); goto defaults; } if ((buffer[offset] & 0x3f) != modepage) { - printk(KERN_ERR "%s: got wrong page\n", diskname); + sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); goto defaults; } @@ -1498,14 +1424,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, sdkp->DPOFUA = (data.device_specific & 0x10) != 0; if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) { - printk(KERN_NOTICE "SCSI device %s: uses " - "READ/WRITE(6), disabling FUA\n", diskname); + sd_printk(KERN_NOTICE, sdkp, + "Uses READ/WRITE(6), disabling FUA\n"); sdkp->DPOFUA = 0; } - printk(KERN_NOTICE "SCSI device %s: " - "write cache: %s, read cache: %s, %s\n", - diskname, + sd_printk(KERN_NOTICE, sdkp, + "Write cache: %s, read cache: %s, %s\n", sdkp->WCE ? "enabled" : "disabled", sdkp->RCD ? "disabled" : "enabled", sdkp->DPOFUA ? "supports DPO and FUA" @@ -1518,15 +1443,13 @@ bad_sense: if (scsi_sense_valid(&sshdr) && sshdr.sense_key == ILLEGAL_REQUEST && sshdr.asc == 0x24 && sshdr.ascq == 0x0) - printk(KERN_NOTICE "%s: cache data unavailable\n", - diskname); /* Invalid field in CDB */ + /* Invalid field in CDB */ + sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n"); else - printk(KERN_ERR "%s: asking for cache data failed\n", - diskname); + sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n"); defaults: - printk(KERN_ERR "%s: assuming drive cache: write through\n", - diskname); + sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n"); sdkp->WCE = 0; sdkp->RCD = 0; sdkp->DPOFUA = 0; @@ -1555,8 +1478,8 @@ static int sd_revalidate_disk(struct gendisk *disk) buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL | __GFP_DMA); if (!buffer) { - printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation " - "failure.\n"); + sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory " + "allocation failure.\n"); goto out; } @@ -1568,16 +1491,16 @@ static int sd_revalidate_disk(struct gendisk *disk) sdkp->WCE = 0; sdkp->RCD = 0; - sd_spinup_disk(sdkp, disk->disk_name); + sd_spinup_disk(sdkp); /* * Without media there is no reason to ask; moreover, some devices * react badly if we do. */ if (sdkp->media_present) { - sd_read_capacity(sdkp, disk->disk_name, buffer); - sd_read_write_protect_flag(sdkp, disk->disk_name, buffer); - sd_read_cache_type(sdkp, disk->disk_name, buffer); + sd_read_capacity(sdkp, buffer); + sd_read_write_protect_flag(sdkp, buffer); + sd_read_cache_type(sdkp, buffer); } /* @@ -1709,8 +1632,8 @@ static int sd_probe(struct device *dev) dev_set_drvdata(dev, sdkp); add_disk(gd); - sdev_printk(KERN_NOTICE, sdp, "Attached scsi %sdisk %s\n", - sdp->removable ? "removable " : "", gd->disk_name); + sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", + sdp->removable ? "removable " : ""); return 0; @@ -1781,16 +1704,14 @@ static void scsi_disk_release(struct class_device *cdev) */ static void sd_shutdown(struct device *dev) { - struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); if (!sdkp) return; /* this can happen */ if (sdkp->WCE) { - printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n", - sdkp->disk->disk_name); - sd_sync_cache(sdp); + sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); + sd_sync_cache(sdkp); } scsi_disk_put(sdkp); } @@ -1852,3 +1773,19 @@ static void __exit exit_sd(void) module_init(init_sd); module_exit(exit_sd); + +static void sd_print_sense_hdr(struct scsi_disk *sdkp, + struct scsi_sense_hdr *sshdr) +{ + sd_printk(KERN_INFO, sdkp, ""); + scsi_show_sense_hdr(sshdr); + sd_printk(KERN_INFO, sdkp, ""); + scsi_show_extd_sense(sshdr->asc, sshdr->ascq); +} + +static void sd_print_result(struct scsi_disk *sdkp, int result) +{ + sd_printk(KERN_INFO, sdkp, ""); + scsi_show_result(result); +} + diff --git a/include/scsi/sd.h b/include/scsi/sd.h new file mode 100644 index 00000000000..82e6a84b77e --- /dev/null +++ b/include/scsi/sd.h @@ -0,0 +1,70 @@ +#ifndef _SCSI_DISK_H +#define _SCSI_DISK_H + +/* + * More than enough for everybody ;) The huge number of majors + * is a leftover from 16bit dev_t days, we don't really need that + * much numberspace. + */ +#define SD_MAJORS 16 + +/* + * This is limited by the naming scheme enforced in sd_probe, + * add another character to it if you really need more disks. + */ +#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26) + +/* + * Time out in seconds for disks and Magneto-opticals (which are slower). + */ +#define SD_TIMEOUT (30 * HZ) +#define SD_MOD_TIMEOUT (75 * HZ) + +/* + * Number of allowed retries + */ +#define SD_MAX_RETRIES 5 +#define SD_PASSTHROUGH_RETRIES 1 + +/* + * Size of the initial data buffer for mode and read capacity data + */ +#define SD_BUF_SIZE 512 + +struct scsi_disk { + struct scsi_driver *driver; /* always &sd_template */ + struct scsi_device *device; + struct class_device cdev; + struct gendisk *disk; + unsigned int openers; /* protected by BKL for now, yuck */ + sector_t capacity; /* size in 512-byte sectors */ + u32 index; + u8 media_present; + u8 write_prot; + unsigned WCE : 1; /* state of disk WCE bit */ + unsigned RCD : 1; /* state of disk RCD bit, unused */ + unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ +}; +#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev) + +static int sd_revalidate_disk(struct gendisk *disk); +static void sd_rw_intr(struct scsi_cmnd * SCpnt); +static int sd_probe(struct device *); +static int sd_remove(struct device *); +static void sd_shutdown(struct device *dev); +static void sd_rescan(struct device *); +static int sd_init_command(struct scsi_cmnd *); +static int sd_issue_flush(struct device *, sector_t *); +static void sd_prepare_flush(request_queue_t *, struct request *); +static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer); +static void scsi_disk_release(struct class_device *cdev); +static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); +static void sd_print_result(struct scsi_disk *, int); + +#define sd_printk(prefix, sdsk, fmt, a...) \ + (sdsk)->disk ? \ + sdev_printk(prefix, (sdsk)->device, "[%s] " fmt, \ + (sdsk)->disk->disk_name, ##a) : \ + sdev_printk(prefix, (sdsk)->device, fmt, ##a) + +#endif /* _SCSI_DISK_H */ -- cgit v1.2.3-70-g09d2 From bf32ed33e97ac7905fa5a2bf49a634c2eaf62457 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Feb 2007 17:32:17 -0600 Subject: [SCSI] iscsi: rename DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH This patch renames DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH to avoid confusion with the drivers default values (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH is the iscsi RFC specific default). Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iser_initiator.c | 2 +- drivers/scsi/iscsi_tcp.c | 6 +++--- drivers/scsi/libiscsi.c | 2 +- include/scsi/iscsi_proto.h | 12 +++++++++++- 4 files changed, 16 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 89e37283c83..3261bb32728 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -201,7 +201,7 @@ static int iser_post_receive_control(struct iscsi_conn *conn) * what's common for both schemes is that the connection is not started */ if (conn->c_stage != ISCSI_CONN_STARTED) - rx_data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH; + rx_data_size = ISCSI_DEF_MAX_RECV_SEG_LEN; else /* FIXME till user space sets conn->max_recv_dlength correctly */ rx_data_size = 128; diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 8f55e143143..6fd08458349 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -527,12 +527,12 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) * than 8K, but there are no targets that currently do this. * For now we fail until we find a vendor that needs it */ - if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH < + if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { printk(KERN_ERR "iscsi_tcp: received buffer of len %u " "but conn buffer is only %u (opcode %0x)\n", tcp_conn->in.datalen, - DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode); + ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); rc = ISCSI_ERR_PROTO; break; } @@ -1762,7 +1762,7 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) * due to strange issues with iser these are not set * in iscsi_conn_setup */ - conn->max_recv_dlength = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH; + conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL); if (!tcp_conn) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 0ad484f87b1..04707d667c9 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1520,7 +1520,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) } spin_unlock_bh(&session->lock); - data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL); + data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); if (!data) goto login_mtask_data_alloc_fail; conn->login_mtask->data = conn->data = data; diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h index 4a44278ed76..8d1e4e8026f 100644 --- a/include/scsi/iscsi_proto.h +++ b/include/scsi/iscsi_proto.h @@ -588,7 +588,17 @@ struct iscsi_reject { #define VALUE_MAXLEN 255 #define TARGET_NAME_MAXLEN VALUE_MAXLEN -#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH 8192 +#define ISCSI_DEF_MAX_RECV_SEG_LEN 8192 +#define ISCSI_MIN_MAX_RECV_SEG_LEN 512 +#define ISCSI_MAX_MAX_RECV_SEG_LEN 16777215 + +#define ISCSI_DEF_FIRST_BURST_LEN 65536 +#define ISCSI_MIN_FIRST_BURST_LEN 512 +#define ISCSI_MAX_FIRST_BURST_LEN 16777215 + +#define ISCSI_DEF_MAX_BURST_LEN 262144 +#define ISCSI_MIN_MAX_BURST_LEN 512 +#define ISCSI_MAX_MAX_BURST_LEN 16777215 /************************* RFC 3720 End *****************************/ -- cgit v1.2.3-70-g09d2 From 181011e04a2a32f8d5df212254239ac9a3c8ab5e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sat, 3 Mar 2007 09:55:54 +0900 Subject: [SCSI] tgt: rm bio hacks in scsi tgt scsi tgt breaks up a command into multple scatterlists if we cannot fit all the data in one. This was because the block rq helpers did not support large requests and because we can get a command of any old size so it is hard to preallocate pages for scatterlist large enough (we cannot really preallocate pages with the bio map user path). In 2.6.20, we added large request support to the block layer helper, blk_rq_map_user. And at LSF, we talked about increasing SCSI_MAX_PHYS_SEGMENTS for scsi tgt if we want to support really really :) large (greater than 256 * PAGE_SIZE in the worst mapping case) requests. The only target currently implemented does not even support the multiple scatterlists stuff and only supports smaller requests, so this patch just coverts scsi tgt to use blk_rq_map_user. Signed-off-by: Mike Christie Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/scsi_tgt_lib.c | 133 +++++++++++--------------------------------- include/scsi/scsi_cmnd.h | 3 - 2 files changed, 34 insertions(+), 102 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index d402aff5f31..47c29a98c92 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -28,7 +28,6 @@ #include #include #include -#include <../drivers/md/dm-bio-list.h> #include "scsi_tgt_priv.h" @@ -42,9 +41,8 @@ static struct kmem_cache *scsi_tgt_cmd_cache; struct scsi_tgt_cmd { /* TODO replace work with James b's code */ struct work_struct work; - /* TODO replace the lists with a large bio */ - struct bio_list xfer_done_list; - struct bio_list xfer_list; + /* TODO fix limits of some drivers */ + struct bio *bio; struct list_head hash_list; struct request *rq; @@ -93,7 +91,12 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, if (!tcmd) goto put_dev; - rq = blk_get_request(shost->uspace_req_q, write, gfp_mask); + /* + * The blk helpers are used to the READ/WRITE requests + * transfering data from a initiator point of view. Since + * we are in target mode we want the opposite. + */ + rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask); if (!rq) goto free_tcmd; @@ -111,8 +114,6 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, rq->cmd_flags |= REQ_TYPE_BLOCK_PC; rq->end_io_data = tcmd; - bio_list_init(&tcmd->xfer_list); - bio_list_init(&tcmd->xfer_done_list); tcmd->rq = rq; return cmd; @@ -157,22 +158,6 @@ void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd) } EXPORT_SYMBOL_GPL(scsi_host_put_command); -static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd) -{ - struct bio *bio; - - /* must call bio_endio in case bio was bounced */ - while ((bio = bio_list_pop(&tcmd->xfer_done_list))) { - bio_endio(bio, bio->bi_size, 0); - bio_unmap_user(bio); - } - - while ((bio = bio_list_pop(&tcmd->xfer_list))) { - bio_endio(bio, bio->bi_size, 0); - bio_unmap_user(bio); - } -} - static void cmd_hashlist_del(struct scsi_cmnd *cmd) { struct request_queue *q = cmd->request->q; @@ -185,6 +170,11 @@ static void cmd_hashlist_del(struct scsi_cmnd *cmd) spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); } +static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd) +{ + blk_rq_unmap_user(tcmd->bio); +} + static void scsi_tgt_cmd_destroy(struct work_struct *work) { struct scsi_tgt_cmd *tcmd = @@ -193,16 +183,6 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work) dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction, rq_data_dir(cmd->request)); - /* - * We fix rq->cmd_flags here since when we told bio_map_user - * to write vm for WRITE commands, blk_rq_bio_prep set - * rq_data_dir the flags to READ. - */ - if (cmd->sc_data_direction == DMA_TO_DEVICE) - cmd->request->cmd_flags |= REQ_RW; - else - cmd->request->cmd_flags &= ~REQ_RW; - scsi_unmap_user_pages(tcmd); scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd); } @@ -215,6 +195,7 @@ static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd, struct list_head *head; tcmd->tag = tag; + tcmd->bio = NULL; INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); spin_lock_irqsave(&qdata->cmd_hash_lock, flags); head = &qdata->cmd_hash[cmd_hashfn(tag)]; @@ -419,52 +400,33 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, struct request *rq = cmd->request; void *uaddr = tcmd->buffer; unsigned int len = tcmd->bufflen; - struct bio *bio; int err; - while (len > 0) { - dprintk("%lx %u\n", (unsigned long) uaddr, len); - bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw); - if (IS_ERR(bio)) { - err = PTR_ERR(bio); - dprintk("fail to map %lx %u %d %x\n", - (unsigned long) uaddr, len, err, cmd->cmnd[0]); - goto unmap_bios; - } - - uaddr += bio->bi_size; - len -= bio->bi_size; - + dprintk("%lx %u\n", (unsigned long) uaddr, len); + err = blk_rq_map_user(q, rq, uaddr, len); + if (err) { /* - * The first bio is added and merged. We could probably - * try to add others using scsi_merge_bio() but for now - * we keep it simple. The first bio should be pretty large - * (either hitting the 1 MB bio pages limit or a queue limit) - * already but for really large IO we may want to try and - * merge these. + * TODO: need to fixup sg_tablesize, max_segment_size, + * max_sectors, etc for modern HW and software drivers + * where this value is bogus. + * + * TODO2: we can alloc a reserve buffer of max size + * we can handle and do the slow copy path for really large + * IO. */ - if (!rq->bio) { - blk_rq_bio_prep(q, rq, bio); - rq->data_len = bio->bi_size; - } else - /* put list of bios to transfer in next go around */ - bio_list_add(&tcmd->xfer_list, bio); + eprintk("Could not handle request of size %u.\n", len); + return err; } - cmd->offset = 0; + tcmd->bio = rq->bio; err = scsi_tgt_init_cmd(cmd, GFP_KERNEL); if (err) - goto unmap_bios; + goto unmap_rq; return 0; -unmap_bios: - if (rq->bio) { - bio_unmap_user(rq->bio); - while ((bio = bio_list_pop(&tcmd->xfer_list))) - bio_unmap_user(bio); - } - +unmap_rq: + scsi_unmap_user_pages(tcmd); return err; } @@ -473,12 +435,10 @@ static int scsi_tgt_transfer_data(struct scsi_cmnd *); static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd) { struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; - struct bio *bio; int err; /* should we free resources here on error ? */ if (cmd->result) { -send_uspace_err: err = scsi_tgt_uspace_send_status(cmd, tcmd->tag); if (err <= 0) /* the tgt uspace eh will have to pick this up */ @@ -490,34 +450,8 @@ send_uspace_err: cmd, cmd->request_bufflen, tcmd->bufflen); scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); - bio_list_add(&tcmd->xfer_done_list, cmd->request->bio); - tcmd->buffer += cmd->request_bufflen; - cmd->offset += cmd->request_bufflen; - - if (!tcmd->xfer_list.head) { - scsi_tgt_transfer_response(cmd); - return; - } - - dprintk("cmd2 %p request_bufflen %u bufflen %u\n", - cmd, cmd->request_bufflen, tcmd->bufflen); - - bio = bio_list_pop(&tcmd->xfer_list); - BUG_ON(!bio); - - blk_rq_bio_prep(cmd->request->q, cmd->request, bio); - cmd->request->data_len = bio->bi_size; - err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC); - if (err) { - cmd->result = DID_ERROR << 16; - goto send_uspace_err; - } - - if (scsi_tgt_transfer_data(cmd)) { - cmd->result = DID_NO_CONNECT << 16; - goto send_uspace_err; - } + scsi_tgt_transfer_response(cmd); } static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd) @@ -617,8 +551,9 @@ int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, } cmd = rq->special; - dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd, - result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]); + dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n", + cmd, cmd->cmnd[0], result, len, cmd->request_bufflen, + rq_data_dir(rq), cmd->cmnd[0]); if (result == TASK_ABORTED) { scsi_tgt_abort_cmd(shost, cmd); diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index d6948d0e8cd..a2e0c103249 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -73,9 +73,6 @@ struct scsi_cmnd { unsigned short use_sg; /* Number of pieces of scatter-gather */ unsigned short sglist_len; /* size of malloc'd scatter-gather list */ - /* offset in cmd we are at (for multi-transfer tgt cmds) */ - unsigned offset; - unsigned underflow; /* Return error if less than this amount is transferred */ -- cgit v1.2.3-70-g09d2 From bc7e380a6a4c94f79a49c36bdb28062a750b3c2b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 3 Mar 2007 09:55:54 +0900 Subject: [SCSI] tgt: fix sesnse buffer problems This patch simplify the way to notify LLDs of the command completion and addresses the following sense buffer problems: - can't handle both data and sense. - forces user-space to use aligned sense buffer tgt copies sense_data from userspace to cmnd->sense_buffer (if necessary), maps user-space pages (if necessary) and then calls host->transfer_response (host->transfer_data is removed). Signed-off-by: FUJITA Tomonori Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvstgt.c | 21 ++----- drivers/scsi/scsi_tgt_if.c | 6 +- drivers/scsi/scsi_tgt_lib.c | 120 ++++++++------------------------------- drivers/scsi/scsi_tgt_priv.h | 5 +- include/scsi/scsi_host.h | 19 ++----- include/scsi/scsi_tgt_if.h | 6 +- 6 files changed, 44 insertions(+), 133 deletions(-) (limited to 'include') diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index 4368ca0e827..a7fbd10817a 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -273,23 +273,9 @@ static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg, rest -= mlen; } out: - return 0; } -static int ibmvstgt_transfer_data(struct scsi_cmnd *sc, - void (*done)(struct scsi_cmnd *)) -{ - struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; - int err; - - err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); - - done(sc); - - return err; -} - static int ibmvstgt_cmd_done(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) { @@ -297,7 +283,11 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc, struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; struct srp_target *target = iue->target; - dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]); + dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0], + cmd->usg_sg); + + if (sc->use_sg) + srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); spin_lock_irqsave(&target->lock, flags); list_del(&iue->ilist); @@ -794,7 +784,6 @@ static struct scsi_host_template ibmvstgt_sht = { .use_clustering = DISABLE_CLUSTERING, .max_sectors = DEFAULT_MAX_SECTORS, .transfer_response = ibmvstgt_cmd_done, - .transfer_data = ibmvstgt_transfer_data, .eh_abort_handler = ibmvstgt_eh_abort_handler, .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response, .shost_attrs = ibmvstgt_attrs, diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c index 0e08817fdec..ca22ddf8174 100644 --- a/drivers/scsi/scsi_tgt_if.c +++ b/drivers/scsi/scsi_tgt_if.c @@ -179,10 +179,12 @@ static int event_recv_msg(struct tgt_event *ev) switch (ev->hdr.type) { case TGT_UEVENT_CMD_RSP: err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no, - ev->p.cmd_rsp.tag, ev->p.cmd_rsp.result, - ev->p.cmd_rsp.len, + ev->p.cmd_rsp.tag, ev->p.cmd_rsp.uaddr, + ev->p.cmd_rsp.len, + ev->p.cmd_rsp.sense_uaddr, + ev->p.cmd_rsp.sense_len, ev->p.cmd_rsp.rw); break; case TGT_UEVENT_TSK_MGMT_RSP: diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 47c29a98c92..dc8781a68d7 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -47,9 +47,6 @@ struct scsi_tgt_cmd { struct list_head hash_list; struct request *rq; u64 tag; - - void *buffer; - unsigned bufflen; }; #define TGT_HASH_ORDER 4 @@ -330,10 +327,14 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd) dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); scsi_tgt_uspace_send_status(cmd, tcmd->tag); + + if (cmd->request_buffer) + scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); + queue_work(scsi_tgtd, &tcmd->work); } -static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd) +static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd) { struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); int err; @@ -346,30 +347,12 @@ static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd) case SCSI_MLQUEUE_DEVICE_BUSY: return -EAGAIN; } - return 0; } -static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd) -{ - struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; - int err; - - err = __scsi_tgt_transfer_response(cmd); - if (!err) - return; - - cmd->result = DID_BUS_BUSY << 16; - err = scsi_tgt_uspace_send_status(cmd, tcmd->tag); - if (err <= 0) - /* the eh will have to pick this up */ - printk(KERN_ERR "Could not send cmd %p status\n", cmd); -} - static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask) { struct request *rq = cmd->request; - struct scsi_tgt_cmd *tcmd = rq->end_io_data; int count; cmd->use_sg = rq->nr_phys_segments; @@ -379,31 +362,28 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask) cmd->request_bufflen = rq->data_len; - dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg, - rq_data_dir(rq)); + dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq)); count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer); if (likely(count <= cmd->use_sg)) { cmd->use_sg = count; return 0; } - eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg); + eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg); scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); return -EINVAL; } /* TODO: test this crap and replace bio_map_user with new interface maybe */ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, - int rw) + unsigned long uaddr, unsigned int len, int rw) { struct request_queue *q = cmd->request->q; struct request *rq = cmd->request; - void *uaddr = tcmd->buffer; - unsigned int len = tcmd->bufflen; int err; - dprintk("%lx %u\n", (unsigned long) uaddr, len); - err = blk_rq_map_user(q, rq, uaddr, len); + dprintk("%lx %u\n", uaddr, len); + err = blk_rq_map_user(q, rq, (void *)uaddr, len); if (err) { /* * TODO: need to fixup sg_tablesize, max_segment_size, @@ -430,45 +410,6 @@ unmap_rq: return err; } -static int scsi_tgt_transfer_data(struct scsi_cmnd *); - -static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd) -{ - struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; - int err; - - /* should we free resources here on error ? */ - if (cmd->result) { - err = scsi_tgt_uspace_send_status(cmd, tcmd->tag); - if (err <= 0) - /* the tgt uspace eh will have to pick this up */ - printk(KERN_ERR "Could not send cmd %p status\n", cmd); - return; - } - - dprintk("cmd %p request_bufflen %u bufflen %u\n", - cmd, cmd->request_bufflen, tcmd->bufflen); - - scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); - tcmd->buffer += cmd->request_bufflen; - scsi_tgt_transfer_response(cmd); -} - -static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd) -{ - int err; - struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd); - - err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done); - switch (err) { - case SCSI_MLQUEUE_HOST_BUSY: - case SCSI_MLQUEUE_DEVICE_BUSY: - return -EAGAIN; - default: - return 0; - } -} - static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr, unsigned len) { @@ -518,8 +459,9 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag) return rq; } -int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, - unsigned long uaddr, u8 rw) +int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, + unsigned long uaddr, u32 len, unsigned long sense_uaddr, + u32 sense_len, u8 rw) { struct Scsi_Host *shost; struct scsi_cmnd *cmd; @@ -564,36 +506,20 @@ int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, * in the request_* values */ tcmd = cmd->request->end_io_data; - tcmd->buffer = (void *)uaddr; - tcmd->bufflen = len; cmd->result = result; - if (!tcmd->bufflen || cmd->request_buffer) { - err = __scsi_tgt_transfer_response(cmd); - goto done; - } - - /* - * TODO: Do we need to handle case where request does not - * align with LLD. - */ - err = scsi_map_user_pages(rq->end_io_data, cmd, rw); - if (err) { - eprintk("%p %d\n", cmd, err); - err = -EAGAIN; - goto done; - } + if (cmd->result == SAM_STAT_CHECK_CONDITION) + scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len); - /* userspace failure */ - if (cmd->result) { - if (status_byte(cmd->result) == CHECK_CONDITION) - scsi_tgt_copy_sense(cmd, uaddr, len); - err = __scsi_tgt_transfer_response(cmd); - goto done; + if (len) { + err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw); + if (err) { + eprintk("%p %d\n", cmd, err); + err = -EAGAIN; + goto done; + } } - /* ask the target LLD to transfer the data to the buffer */ - err = scsi_tgt_transfer_data(cmd); - + err = scsi_tgt_transfer_response(cmd); done: scsi_host_put(shost); return err; diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h index 84488c51ff6..e9e6db1c417 100644 --- a/drivers/scsi/scsi_tgt_priv.h +++ b/drivers/scsi/scsi_tgt_priv.h @@ -18,8 +18,9 @@ extern int scsi_tgt_if_init(void); extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag); extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag); -extern int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len, - unsigned long uaddr, u8 rw); +extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, + unsigned long uaddr, u32 len, unsigned long sense_uaddr, + u32 sense_len, u8 rw); extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, struct scsi_lun *scsilun, void *data); extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 7f1f411d07a..965b6b8ffec 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -129,6 +129,11 @@ struct scsi_host_template { * the LLD. When the driver is finished processing the command * the done callback is invoked. * + * This is called to inform the LLD to transfer + * cmd->request_bufflen bytes. The cmd->use_sg speciefies the + * number of scatterlist entried in the command and + * cmd->request_buffer contains the scatterlist. + * * return values: see queuecommand * * If the LLD accepts the cmd, it should set the result to an @@ -139,20 +144,6 @@ struct scsi_host_template { /* TODO: rename */ int (* transfer_response)(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *)); - /* - * This is called to inform the LLD to transfer cmd->request_bufflen - * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg - * speciefies the number of scatterlist entried in the command - * and cmd->request_buffer contains the scatterlist. - * - * If the command cannot be processed in one transfer_data call - * becuase a scatterlist within the LLD's limits cannot be - * created then transfer_data will be called multiple times. - * It is initially called from process context, and later - * calls are from the interrup context. - */ - int (* transfer_data)(struct scsi_cmnd *, - void (*done)(struct scsi_cmnd *)); /* Used as callback for the completion of task management request. */ int (* tsk_mgmt_response)(u64 mid, int result); diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h index 07d6e77ae89..4cf9dff29a2 100644 --- a/include/scsi/scsi_tgt_if.h +++ b/include/scsi/scsi_tgt_if.h @@ -45,11 +45,13 @@ struct tgt_event { /* user-> kernel */ struct { int host_no; - uint32_t len; int result; + aligned_u64 tag; aligned_u64 uaddr; + aligned_u64 sense_uaddr; + uint32_t len; + uint32_t sense_len; uint8_t rw; - aligned_u64 tag; } cmd_rsp; struct { int host_no; -- cgit v1.2.3-70-g09d2 From c3d2350a8420dbf9d48f5f8a0fb72117bfcbc1b0 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 12 Mar 2007 14:16:35 -0500 Subject: [SCSI] fc_transport: update potential link speeds This patch updates the FC transport for all speeds identified in SM-HBA. Note: it does not sync the "bit" definitions, as that is actually insulated from user-space via the sysfs text string. (I could do it, but it does introduce a potential binary-incompatibility). Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 2 ++ include/scsi/scsi_transport_fc.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'include') diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 58afdb40170..14c4f065b2b 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -200,6 +200,8 @@ static const struct { { FC_PORTSPEED_2GBIT, "2 Gbit" }, { FC_PORTSPEED_4GBIT, "4 Gbit" }, { FC_PORTSPEED_10GBIT, "10 Gbit" }, + { FC_PORTSPEED_8GBIT, "8 Gbit" }, + { FC_PORTSPEED_16GBIT, "16 Gbit" }, { FC_PORTSPEED_NOT_NEGOTIATED, "Not Negotiated" }, }; fc_bitfield_name_search(port_speed, fc_port_speed_names) diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 798f7c7ee42..1e797308640 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -108,6 +108,8 @@ enum fc_port_state { #define FC_PORTSPEED_2GBIT 2 #define FC_PORTSPEED_4GBIT 4 #define FC_PORTSPEED_10GBIT 8 +#define FC_PORTSPEED_8GBIT 0x10 +#define FC_PORTSPEED_16GBIT 0x20 #define FC_PORTSPEED_NOT_NEGOTIATED (1 << 15) /* Speed not established */ /* -- cgit v1.2.3-70-g09d2 From 6c5f8ce1fb7e8925d957f754a9513911399791b9 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 16 Mar 2007 17:44:41 -0500 Subject: [SCSI] expose eh_timed_out to the host template It looks like megaraid_sas at least needs this to throttle its commands as they begin to time out. The code keeps the existing transport template use of eh_timed_out (and allows the transport to override the host if they both have this callback). Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 11 ++++++++++- include/scsi/scsi_host.h | 13 +++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index b8edcf5b545..7a1a1bb1341 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -184,10 +184,19 @@ int scsi_delete_timer(struct scsi_cmnd *scmd) **/ void scsi_times_out(struct scsi_cmnd *scmd) { + enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); + scsi_log_completion(scmd, TIMEOUT_ERROR); if (scmd->device->host->transportt->eh_timed_out) - switch (scmd->device->host->transportt->eh_timed_out(scmd)) { + eh_timed_out = scmd->device->host->transportt->eh_timed_out; + else if (scmd->device->host->hostt->eh_timed_out) + eh_timed_out = scmd->device->host->hostt->eh_timed_out; + else + eh_timed_out = NULL; + + if (eh_timed_out) + switch (eh_timed_out(scmd)) { case EH_HANDLED: __scsi_done(scmd); return; diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 965b6b8ffec..68f461b7a83 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -325,6 +325,19 @@ struct scsi_host_template { */ int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int); + /* + * This is an optional routine that allows the transport to become + * involved when a scsi io timer fires. The return value tells the + * timer routine how to finish the io timeout handling: + * EH_HANDLED: I fixed the error, please complete the command + * EH_RESET_TIMER: I need more time, reset the timer and + * begin counting again + * EH_NOT_HANDLED Begin normal error recovery + * + * Status: OPTIONAL + */ + enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); + /* * suspend support */ -- cgit v1.2.3-70-g09d2 From c3c94c5a2fb43a654e777f509d5032b0db8ed09f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 21 Mar 2007 00:13:59 +0900 Subject: [SCSI] sd: implement START/STOP management Implement SBC START/STOP management. sdev->mange_start_stop is added. When it's set to one, sd STOPs the device on suspend and shutdown and STARTs it on resume. sdev->manage_start_stop defaults is in sdev instead of scsi_disk cdev to allow ->slave_config() override the default configuration but is exported under scsi_disk sysfs node as sdev->allow_restart is. When manage_start_stop is zero (the default value), this patch doesn't introduce any behavior change. Signed-off-by: Tejun Heo Rejections fixed and Signed-off-by: James Bottomley --- drivers/scsi/scsi_sysfs.c | 31 ++++++++++++-- drivers/scsi/sd.c | 101 +++++++++++++++++++++++++++++++++++++++++++++ include/scsi/scsi_device.h | 1 + include/scsi/sd.h | 2 + 4 files changed, 131 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index c275dcac3f1..96db51c40ef 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -278,6 +278,7 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) static int scsi_bus_suspend(struct device * dev, pm_message_t state) { + struct device_driver *drv = dev->driver; struct scsi_device *sdev = to_scsi_device(dev); struct scsi_host_template *sht = sdev->host->hostt; int err; @@ -286,23 +287,45 @@ static int scsi_bus_suspend(struct device * dev, pm_message_t state) if (err) return err; - if (sht->suspend) + /* call HLD suspend first */ + if (drv && drv->suspend) { + err = drv->suspend(dev, state); + if (err) + return err; + } + + /* then, call host suspend */ + if (sht->suspend) { err = sht->suspend(sdev, state); + if (err) { + if (drv && drv->resume) + drv->resume(dev); + return err; + } + } - return err; + return 0; } static int scsi_bus_resume(struct device * dev) { + struct device_driver *drv = dev->driver; struct scsi_device *sdev = to_scsi_device(dev); struct scsi_host_template *sht = sdev->host->hostt; - int err = 0; + int err = 0, err2 = 0; + /* call host resume first */ if (sht->resume) err = sht->resume(sdev); + /* then, call HLD resume */ + if (drv && drv->resume) + err2 = drv->resume(dev); + scsi_device_resume(sdev); - return err; + + /* favor LLD failure */ + return err ? err : err2;; } struct bus_type scsi_bus_type = { diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3dda77c31f5..49a94ae3225 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -147,6 +147,20 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf, return count; } +static ssize_t sd_store_manage_start_stop(struct class_device *cdev, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + struct scsi_device *sdp = sdkp->device; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + sdp->manage_start_stop = simple_strtoul(buf, NULL, 10); + + return count; +} + static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf, size_t count) { @@ -179,6 +193,14 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf) return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); } +static ssize_t sd_show_manage_start_stop(struct class_device *cdev, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + struct scsi_device *sdp = sdkp->device; + + return snprintf(buf, 20, "%u\n", sdp->manage_start_stop); +} + static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf) { struct scsi_disk *sdkp = to_scsi_disk(cdev); @@ -192,6 +214,8 @@ static struct class_device_attribute sd_disk_attrs[] = { __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart, sd_store_allow_restart), + __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop, + sd_store_manage_start_stop), __ATTR_NULL, }; @@ -208,6 +232,8 @@ static struct scsi_driver sd_template = { .name = "sd", .probe = sd_probe, .remove = sd_remove, + .suspend = sd_suspend, + .resume = sd_resume, .shutdown = sd_shutdown, }, .rescan = sd_rescan, @@ -1707,6 +1733,32 @@ static void scsi_disk_release(struct class_device *cdev) kfree(sdkp); } +static int sd_start_stop_device(struct scsi_device *sdp, int start) +{ + unsigned char cmd[6] = { START_STOP }; /* START_VALID */ + struct scsi_sense_hdr sshdr; + int res; + + if (start) + cmd[4] |= 1; /* START */ + + if (!scsi_device_online(sdp)) + return -ENODEV; + + res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, + SD_TIMEOUT, SD_MAX_RETRIES); + if (res) { + printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " + "host = %d, driver = %02x\n ", + status_byte(res), msg_byte(res), + host_byte(res), driver_byte(res)); + if (driver_byte(res) & DRIVER_SENSE) + scsi_print_sense_hdr("sd", &sshdr); + } + + return res; +} + /* * Send a SYNCHRONIZE CACHE instruction down to the device through * the normal SCSI command structure. Wait for the command to @@ -1714,6 +1766,7 @@ static void scsi_disk_release(struct class_device *cdev) */ static void sd_shutdown(struct device *dev) { + struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); if (!sdkp) @@ -1723,9 +1776,57 @@ static void sd_shutdown(struct device *dev) sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); sd_sync_cache(sdkp); } + + if (system_state != SYSTEM_RESTART && sdp->manage_start_stop) { + printk(KERN_NOTICE "Stopping disk %s: \n", + sdkp->disk->disk_name); + sd_start_stop_device(sdp, 0); + } + scsi_disk_put(sdkp); } +static int sd_suspend(struct device *dev, pm_message_t mesg) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); + int ret; + + if (!sdkp) + return 0; /* this can happen */ + + if (sdkp->WCE) { + printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n", + sdkp->disk->disk_name); + ret = sd_sync_cache(sdkp); + if (ret) + return ret; + } + + if (mesg.event == PM_EVENT_SUSPEND && sdp->manage_start_stop) { + printk(KERN_NOTICE "Stopping disk %s: \n", + sdkp->disk->disk_name); + ret = sd_start_stop_device(sdp, 0); + if (ret) + return ret; + } + + return 0; +} + +static int sd_resume(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); + + if (!sdp->manage_start_stop) + return 0; + + printk(KERN_NOTICE "Starting disk %s: \n", sdkp->disk->disk_name); + + return sd_start_stop_device(sdp, 1); +} + /** * init_sd - entry point for this driver (both when built in or when * a module). diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index c86e6ce143d..b05cd3b09e6 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -120,6 +120,7 @@ struct scsi_device { unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */ unsigned no_start_on_add:1; /* do not issue start on add */ unsigned allow_restart:1; /* issue START_UNIT in error handler */ + unsigned manage_start_stop:1; /* Let HLD (sd) manage start/stop */ unsigned no_uld_attach:1; /* disable connecting to upper level drivers */ unsigned select_no_atn:1; unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */ diff --git a/include/scsi/sd.h b/include/scsi/sd.h index 82e6a84b77e..5261488e110 100644 --- a/include/scsi/sd.h +++ b/include/scsi/sd.h @@ -52,6 +52,8 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt); static int sd_probe(struct device *); static int sd_remove(struct device *); static void sd_shutdown(struct device *dev); +static int sd_suspend(struct device *dev, pm_message_t state); +static int sd_resume(struct device *dev); static void sd_rescan(struct device *); static int sd_init_command(struct scsi_cmnd *); static int sd_issue_flush(struct device *, sector_t *); -- cgit v1.2.3-70-g09d2 From d7b8bcb0a0819315a51cae620ff7ae0c1704c069 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Fri, 27 Oct 2006 16:02:37 +0400 Subject: [SCSI] modalias for scsi devices The following patch adds support for sysfs/uevent modalias attribute for scsi devices (like disks, tapes, cdroms etc), based on whatever current sd.c, sr.c, st.c and osst.c drivers supports. The modalias format is like this: scsi:type-0x04 (for TYPE_WORM, handled by sr.c now). Several comments. o This hexadecimal type value is because all TYPE_XXX constants in include/scsi/scsi.h are given in hex, but __stringify() will not convert them to decimal (so it will NOT be scsi:type-4). Since it does not really matter in which format it is, while both modalias in module and modalias attribute match each other, I descided to go for that 0x%02x format (and added a comment in include/scsi/scsi.h to keep them that way), instead of changing them all to decimal. o There was no .uevent routine for SCSI bus. It might be a good idea to add some more ueven environment variables in there. o osst.c driver handles tapes too, like st.c, but only SOME tapes. With this setup, hotplug scripts (or whatever is used by the user) will try to load both st and osst modules for all SCSI tapes found, because both modules have scsi:type-0x01 alias). It is not harmful, but one extra module is no good either. It is possible to solve this, by exporting more info in modalias attribute, including vendor and device identification strings, so that modalias becomes something like scsi:type-0x12:vendor-Adaptec LTD:device-OnStream Tape Drive and having that, match for all 3 attributes, not only device type. But oh well, vendor and device strings may be large, and they do contain spaces and whatnot. So I left them for now, awaiting for comments first. Signed-off-by: Michael Tokarev Signed-off-by: James Bottomley --- drivers/scsi/osst.c | 1 + drivers/scsi/scsi_sysfs.c | 23 +++++++++++++++++++++++ drivers/scsi/sd.c | 3 +++ drivers/scsi/sr.c | 2 ++ drivers/scsi/st.c | 1 + include/scsi/scsi.h | 1 + include/scsi/scsi_device.h | 5 +++++ 7 files changed, 36 insertions(+) (limited to 'include') diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index a967fadb743..08060fb478b 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -87,6 +87,7 @@ MODULE_AUTHOR("Willem Riede"); MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR); +MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); module_param(max_dev, int, 0444); MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)"); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 96db51c40ef..5326f5cbeae 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -276,6 +276,19 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; } +static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct scsi_device *sdev = to_scsi_device(dev); + int i = 0; + int length = 0; + + add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, + "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); + envp[i] = NULL; + return 0; +} + static int scsi_bus_suspend(struct device * dev, pm_message_t state) { struct device_driver *drv = dev->driver; @@ -331,6 +344,7 @@ static int scsi_bus_resume(struct device * dev) struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, + .uevent = scsi_bus_uevent, .suspend = scsi_bus_suspend, .resume = scsi_bus_resume, }; @@ -558,6 +572,14 @@ show_sdev_iostat(iorequest_cnt); show_sdev_iostat(iodone_cnt); show_sdev_iostat(ioerr_cnt); +static ssize_t +sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev; + sdev = to_scsi_device(dev); + return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "\n", sdev->type); +} +static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); /* Default template for device attributes. May NOT be modified */ static struct device_attribute *scsi_sysfs_sdev_attrs[] = { @@ -577,6 +599,7 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = { &dev_attr_iorequest_cnt, &dev_attr_iodone_cnt, &dev_attr_ioerr_cnt, + &dev_attr_modalias, NULL }; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b044dcf7342..00e46662296 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -82,6 +82,9 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR); +MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK); +MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD); +MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); static DEFINE_IDR(sd_index_idr); static DEFINE_SPINLOCK(sd_index_lock); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 1857d68e719..f9a52af7f5b 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -62,6 +62,8 @@ MODULE_DESCRIPTION("SCSI cdrom (sr) driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR); +MODULE_ALIAS_SCSI_DEVICE(TYPE_ROM); +MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); #define SR_DISKS 256 diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 98d8411bbcc..55bfeccf68a 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -89,6 +89,7 @@ MODULE_AUTHOR("Kai Makisara"); MODULE_DESCRIPTION("SCSI tape (st) driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR); +MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); /* Set 'perm' (4th argument) to 0 to disable module_param's definition * of sysfs parameters (which module_param doesn't yet support). diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 5c0e9791441..9f8f80ab0c8 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -203,6 +203,7 @@ static inline int scsi_status_is_good(int status) /* * DEVICE TYPES + * Please keep them in 0x%02x format for $MODALIAS to work */ #define TYPE_DISK 0x00 diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index b05cd3b09e6..2f3c5b8b1d6 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -358,4 +358,9 @@ static inline int scsi_device_qas(struct scsi_device *sdev) return 0; return sdev->inquiry[56] & 0x02; } + +#define MODULE_ALIAS_SCSI_DEVICE(type) \ + MODULE_ALIAS("scsi:t-" __stringify(type) "*") +#define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x" + #endif /* _SCSI_SCSI_DEVICE_H */ -- cgit v1.2.3-70-g09d2