diff options
Diffstat (limited to 'drivers/scsi/3w-9xxx.c')
| -rw-r--r-- | drivers/scsi/3w-9xxx.c | 459 |
1 files changed, 207 insertions, 252 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 5e1e12c0cf42..a377a6f6900a 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1,8 +1,8 @@ /* 3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux. - Written By: Adam Radford <linuxraid@lsi.com> - Modifications By: Tom Couch <linuxraid@lsi.com> + Written By: Adam Radford <aradford@gmail.com> + Modifications By: Tom Couch Copyright (C) 2004-2009 Applied Micro Circuits Corporation. Copyright (C) 2010 LSI Corporation. @@ -41,10 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com + aradford@gmail.com Note: This version of the driver does not contain a bundled firmware image. @@ -95,7 +92,7 @@ #include <linux/slab.h> #include <asm/io.h> #include <asm/irq.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <scsi/scsi.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> @@ -131,14 +128,14 @@ static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_ static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id); static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id); static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, - u32 set_features, unsigned short current_fw_srl, - unsigned short current_fw_arch_id, - unsigned short current_fw_branch, - unsigned short current_fw_build, - unsigned short *fw_on_ctlr_srl, - unsigned short *fw_on_ctlr_arch_id, - unsigned short *fw_on_ctlr_branch, - unsigned short *fw_on_ctlr_build, + u32 set_features, unsigned short current_fw_srl, + unsigned short current_fw_arch_id, + unsigned short current_fw_branch, + unsigned short current_fw_build, + unsigned short *fw_on_ctlr_srl, + unsigned short *fw_on_ctlr_arch_id, + unsigned short *fw_on_ctlr_branch, + unsigned short *fw_on_ctlr_build, u32 *init_connect_result); static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length); static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds); @@ -146,10 +143,11 @@ static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int secon static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal); static int twa_reset_device_extension(TW_Device_Extension *tw_dev); static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset); -static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg); +static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, + unsigned char *cdb, int use_sg, + TW_SG_Entry *sglistarg); static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id); static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code); -static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id); /* Functions */ @@ -163,60 +161,49 @@ static ssize_t twa_show_stats(struct device *dev, ssize_t len; spin_lock_irqsave(tw_dev->host->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n" - "Current commands posted: %4d\n" - "Max commands posted: %4d\n" - "Current pending commands: %4d\n" - "Max pending commands: %4d\n" - "Last sgl length: %4d\n" - "Max sgl length: %4d\n" - "Last sector count: %4d\n" - "Max sector count: %4d\n" - "SCSI Host Resets: %4d\n" - "AEN's: %4d\n", - TW_DRIVER_VERSION, - tw_dev->posted_request_count, - tw_dev->max_posted_request_count, - tw_dev->pending_request_count, - tw_dev->max_pending_request_count, - tw_dev->sgl_entries, - tw_dev->max_sgl_entries, - tw_dev->sector_count, - tw_dev->max_sector_count, - tw_dev->num_resets, - tw_dev->aen_count); + len = sysfs_emit(buf, "3w-9xxx Driver version: %s\n" + "Current commands posted: %4d\n" + "Max commands posted: %4d\n" + "Current pending commands: %4d\n" + "Max pending commands: %4d\n" + "Last sgl length: %4d\n" + "Max sgl length: %4d\n" + "Last sector count: %4d\n" + "Max sector count: %4d\n" + "SCSI Host Resets: %4d\n" + "AEN's: %4d\n", + TW_DRIVER_VERSION, + tw_dev->posted_request_count, + tw_dev->max_posted_request_count, + tw_dev->pending_request_count, + tw_dev->max_pending_request_count, + tw_dev->sgl_entries, + tw_dev->max_sgl_entries, + tw_dev->sector_count, + tw_dev->max_sector_count, + tw_dev->num_resets, + tw_dev->aen_count); spin_unlock_irqrestore(tw_dev->host->host_lock, flags); return len; } /* End twa_show_stats() */ -/* This function will set a devices queue depth */ -static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (queue_depth > TW_Q_LENGTH-2) - queue_depth = TW_Q_LENGTH-2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); - return queue_depth; -} /* End twa_change_queue_depth() */ - /* Create sysfs 'stats' entry */ static struct device_attribute twa_host_stats_attr = { .attr = { - .name = "stats", + .name = "stats", .mode = S_IRUGO, }, .show = twa_show_stats }; /* Host attributes initializer */ -static struct device_attribute *twa_host_attrs[] = { - &twa_host_stats_attr, +static struct attribute *twa_host_attrs[] = { + &twa_host_stats_attr.attr, NULL, }; +ATTRIBUTE_GROUPS(twa_host); + /* File operations struct for character device */ static const struct file_operations twa_fops = { .owner = THIS_MODULE, @@ -226,6 +213,17 @@ static const struct file_operations twa_fops = { .llseek = noop_llseek, }; +/* + * The controllers use an inline buffer instead of a mapped SGL for small, + * single entry buffers. Note that we treat a zero-length transfer like + * a mapped SGL. + */ +static bool twa_command_mapped(struct scsi_cmnd *cmd) +{ + return scsi_sg_count(cmd) != 1 || + scsi_bufflen(cmd) >= TW_MIN_SGL_LENGTH; +} + /* This function will complete an aen request from the isr */ static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id) { @@ -246,7 +244,7 @@ static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id) /* Keep reading the queue in case there are more aen's */ if (twa_aen_read_queue(tw_dev, request_id)) goto out2; - else { + else { retval = 0; goto out; } @@ -284,7 +282,7 @@ out: static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset) { int request_id = 0; - char cdb[TW_MAX_CDB_LEN]; + unsigned char cdb[TW_MAX_CDB_LEN]; TW_SG_Entry sglist[1]; int finished = 0, count = 0; TW_Command_Full *full_command_packet; @@ -307,10 +305,10 @@ static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset) /* Initialize sglist */ memset(&sglist, 0, sizeof(TW_SG_Entry)); - sglist[0].length = TW_SECTOR_SIZE; - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; + sglist[0].length = cpu_to_le32(TW_SECTOR_SIZE); + sglist[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); - if (sglist[0].address & TW_ALIGNMENT_9000_SGL) { + if (tw_dev->generic_buffer_phys[request_id] & TW_ALIGNMENT_9000_SGL) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain"); goto out; } @@ -375,7 +373,6 @@ out: static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header) { u32 local_time; - struct timeval time; TW_Event *event; unsigned short aen; char host[16]; @@ -398,8 +395,8 @@ static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_H memset(event, 0, sizeof(TW_Event)); event->severity = TW_SEV_OUT(header->status_block.severity__reserved); - do_gettimeofday(&time); - local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); + /* event->time_stamp_sec overflows in y2106 */ + local_time = (u32)(ktime_get_real_seconds() - (sys_tz.tz_minuteswest * 60)); event->time_stamp_sec = local_time; event->aen_code = aen; event->retrieved = TW_AEN_NOT_RETRIEVED; @@ -430,7 +427,7 @@ static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_H /* This function will read the aen queue from the isr */ static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) { - char cdb[TW_MAX_CDB_LEN]; + unsigned char cdb[TW_MAX_CDB_LEN]; TW_SG_Entry sglist[1]; TW_Command_Full *full_command_packet; int retval = 1; @@ -445,8 +442,8 @@ static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) /* Initialize sglist */ memset(&sglist, 0, sizeof(TW_SG_Entry)); - sglist[0].length = TW_SECTOR_SIZE; - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; + sglist[0].length = cpu_to_le32(TW_SECTOR_SIZE); + sglist[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); /* Mark internal command */ tw_dev->srb[request_id] = NULL; @@ -479,11 +476,10 @@ out: static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) { u32 schedulertime; - struct timeval utc; TW_Command_Full *full_command_packet; TW_Command *command_packet; TW_Param_Apache *param; - u32 local_time; + time64_t local_time; /* Fill out the command packet */ full_command_packet = tw_dev->command_packet_virt[request_id]; @@ -503,14 +499,12 @@ static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */ param->parameter_size_bytes = cpu_to_le16(4); - /* Convert system time in UTC to local time seconds since last + /* Convert system time in UTC to local time seconds since last Sunday 12:00AM */ - do_gettimeofday(&utc); - local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); - schedulertime = local_time - (3 * 86400); - schedulertime = cpu_to_le32(schedulertime % 604800); + local_time = (ktime_get_real_seconds() - (sys_tz.tz_minuteswest * 60)); + div_u64_rem(local_time - (3 * 86400), 604800, &schedulertime); - memcpy(param->data, &schedulertime, sizeof(u32)); + memcpy(param->data, &(__le32){cpu_to_le32(schedulertime)}, sizeof(__le32)); /* Mark internal command */ tw_dev->srb[request_id] = NULL; @@ -527,7 +521,8 @@ static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) unsigned long *cpu_addr; int retval = 1; - cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); + cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, + size * TW_Q_LENGTH, &dma_handle, GFP_KERNEL); if (!cpu_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); goto out; @@ -535,7 +530,8 @@ static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory"); - pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, size * TW_Q_LENGTH, + cpu_addr, dma_handle); goto out; } @@ -621,7 +617,8 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed) } /* Load rest of compatibility struct */ - strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); + strscpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, + sizeof(tw_dev->tw_compat_info.driver_version)); tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; @@ -653,8 +650,7 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long TW_Command_Full *full_command_packet; TW_Compatibility_Info *tw_compat_info; TW_Event *event; - struct timeval current_time; - u32 current_time_ms; + ktime_t current_time; TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)]; int retval = TW_IOCTL_ERROR_OS_EFAULT; void __user *argp = (void __user *)arg; @@ -681,7 +677,9 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511; /* Now allocate ioctl buf memory */ - cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL); + cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, + sizeof(TW_Ioctl_Buf_Apache) + data_buffer_length_adjusted, + &dma_handle, GFP_KERNEL); if (!cpu_addr) { retval = TW_IOCTL_ERROR_OS_ENOMEM; goto out2; @@ -690,7 +688,7 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr; /* Now copy down the entire ioctl */ - if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1)) + if (copy_from_user(tw_ioctl, argp, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length)) goto out3; /* See which ioctl we are doing */ @@ -734,7 +732,7 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long /* Now copy in the command packet response */ memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full)); - + /* Now complete the io */ spin_lock_irqsave(tw_dev->host->host_lock, flags); tw_dev->posted_request_count--; @@ -771,7 +769,7 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long if (tw_dev->aen_clobber) { tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; tw_dev->aen_clobber = 0; - } else + } else tw_ioctl->driver_command.status = 0; event_index = tw_dev->error_index; } else { @@ -845,17 +843,17 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long break; case TW_IOCTL_GET_LOCK: tw_lock = (TW_Lock *)tw_ioctl->data_buffer; - do_gettimeofday(¤t_time); - current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000); + current_time = ktime_get(); - if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) { + if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || + ktime_after(current_time, tw_dev->ioctl_time)) { tw_dev->ioctl_sem_lock = 1; - tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec; + tw_dev->ioctl_time = ktime_add_ms(current_time, tw_lock->timeout_msec); tw_ioctl->driver_command.status = 0; tw_lock->time_remaining_msec = tw_lock->timeout_msec; } else { tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED; - tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms; + tw_lock->time_remaining_msec = ktime_ms_delta(tw_dev->ioctl_time, current_time); } break; case TW_IOCTL_RELEASE_LOCK: @@ -872,11 +870,13 @@ static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long } /* Now copy the entire response to userspace */ - if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0) + if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length) == 0) retval = 0; out3: /* Now free ioctl buf memory */ - dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, + sizeof(TW_Ioctl_Buf_Apache) + data_buffer_length_adjusted, + cpu_addr, dma_handle); out2: mutex_unlock(&tw_dev->ioctl_lock); out: @@ -891,6 +891,11 @@ static int twa_chrdev_open(struct inode *inode, struct file *file) unsigned int minor_number; int retval = TW_IOCTL_ERROR_OS_ENODEV; + if (!capable(CAP_SYS_ADMIN)) { + retval = -EACCES; + goto out; + } + minor_number = iminor(inode); if (minor_number >= twa_device_extension_count) goto out; @@ -939,13 +944,13 @@ out: /* This function will empty the response queue */ static int twa_empty_response_queue(TW_Device_Extension *tw_dev) { - u32 status_reg_value, response_que_value; + u32 status_reg_value; int count = 0, retval = 1; status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) { - response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); + readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); count++; } @@ -1000,19 +1005,13 @@ static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_ if (print_host) printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", tw_dev->host->host_no, - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, - full_command_packet->header.status_block.error, - error_str[0] == '\0' ? - twa_string_lookup(twa_error_table, - full_command_packet->header.status_block.error) : error_str, + TW_MESSAGE_SOURCE_CONTROLLER_ERROR, error, + error_str[0] ? error_str : twa_string_lookup(twa_error_table, error), full_command_packet->header.err_specific_desc); else printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n", - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, - full_command_packet->header.status_block.error, - error_str[0] == '\0' ? - twa_string_lookup(twa_error_table, - full_command_packet->header.status_block.error) : error_str, + TW_MESSAGE_SOURCE_CONTROLLER_ERROR, error, + error_str[0] ? error_str : twa_string_lookup(twa_error_table, error), full_command_packet->header.err_specific_desc); } @@ -1031,16 +1030,16 @@ out: static void twa_free_device_extension(TW_Device_Extension *tw_dev) { if (tw_dev->command_packet_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, - sizeof(TW_Command_Full)*TW_Q_LENGTH, - tw_dev->command_packet_virt[0], - tw_dev->command_packet_phys[0]); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, + sizeof(TW_Command_Full) * TW_Q_LENGTH, + tw_dev->command_packet_virt[0], + tw_dev->command_packet_phys[0]); if (tw_dev->generic_buffer_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, - TW_SECTOR_SIZE*TW_Q_LENGTH, - tw_dev->generic_buffer_virt[0], - tw_dev->generic_buffer_phys[0]); + dma_free_coherent(&tw_dev->tw_pci_dev->dev, + TW_SECTOR_SIZE * TW_Q_LENGTH, + tw_dev->generic_buffer_virt[0], + tw_dev->generic_buffer_phys[0]); kfree(tw_dev->event_queue[0]); } /* End twa_free_device_extension() */ @@ -1067,8 +1066,8 @@ static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int tabl command_packet = &full_command_packet->command.oldcommand; command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); - command_packet->size = TW_COMMAND_SIZE; - command_packet->request_id = request_id; + command_packet->size = TW_COMMAND_SIZE; + command_packet->request_id = request_id; command_packet->byte6_offset.block_count = cpu_to_le16(1); /* Now setup the param */ @@ -1106,14 +1105,14 @@ static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id) /* This function will send an initconnection command to controller */ static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, - u32 set_features, unsigned short current_fw_srl, - unsigned short current_fw_arch_id, - unsigned short current_fw_branch, - unsigned short current_fw_build, - unsigned short *fw_on_ctlr_srl, - unsigned short *fw_on_ctlr_arch_id, - unsigned short *fw_on_ctlr_branch, - unsigned short *fw_on_ctlr_build, + u32 set_features, unsigned short current_fw_srl, + unsigned short current_fw_arch_id, + unsigned short current_fw_branch, + unsigned short current_fw_build, + unsigned short *fw_on_ctlr_srl, + unsigned short *fw_on_ctlr_arch_id, + unsigned short *fw_on_ctlr_branch, + unsigned short *fw_on_ctlr_build, u32 *init_connect_result) { TW_Command_Full *full_command_packet; @@ -1124,17 +1123,16 @@ static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, full_command_packet = tw_dev->command_packet_virt[request_id]; memset(full_command_packet, 0, sizeof(TW_Command_Full)); full_command_packet->header.header_desc.size_header = 128; - + tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand; tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); tw_initconnect->request_id = request_id; tw_initconnect->message_credits = cpu_to_le16(message_credits); - tw_initconnect->features = set_features; /* Turn on 64-bit sgl support if we need to */ - tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0; + set_features |= sizeof(dma_addr_t) > 4 ? 1 : 0; - tw_initconnect->features = cpu_to_le32(tw_initconnect->features); + tw_initconnect->features = cpu_to_le32(set_features); if (set_features & TW_EXTENDED_INIT_CONNECT) { tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; @@ -1142,7 +1140,7 @@ static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id); tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch); tw_initconnect->fw_build = cpu_to_le16(current_fw_build); - } else + } else tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE; /* Send command packet to the board */ @@ -1342,21 +1340,24 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) /* If error, command failed */ if (error == 1) { /* Ask for a host reset */ - cmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + cmd->result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION; } /* Report residual bytes for single sgl */ if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) { - if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id])) - scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length); + u32 length = le32_to_cpu(full_command_packet->command.newcommand.sg_list[0].length); + + if (length < scsi_bufflen(cmd)) + scsi_set_resid(cmd, scsi_bufflen(cmd) - length); } /* Now complete the io */ + if (twa_command_mapped(cmd)) + scsi_dma_unmap(cmd); + scsi_done(cmd); tw_dev->state[request_id] = TW_S_COMPLETED; twa_free_request_id(tw_dev, request_id); tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - twa_unmap_scsi_data(tw_dev, request_id); } /* Check for valid status after each drain */ @@ -1389,13 +1390,13 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { newcommand = &full_command_packet->command.newcommand; newcommand->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id)); + TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id); if (length) { - newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); + newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache)); newcommand->sg_list[0].length = cpu_to_le32(length); } newcommand->sgl_entries__lunh = - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0)); + TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0); } else { oldcommand = &full_command_packet->command.oldcommand; oldcommand->request_id = request_id; @@ -1406,7 +1407,7 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae); else sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset)); - sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); + sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache)); sgl->length = cpu_to_le32(length); oldcommand->size += pae; @@ -1414,26 +1415,6 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm } } /* End twa_load_sgl() */ -/* This function will perform a pci-dma mapping for a scatter gather list */ -static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) -{ - int use_sg; - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - use_sg = scsi_dma_map(cmd); - if (!use_sg) - return 0; - else if (use_sg < 0) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list"); - return 0; - } - - cmd->SCp.phase = TW_PHASE_SGLIST; - cmd->SCp.have_data_in = use_sg; - - return use_sg; -} /* End twa_map_scsi_sg_data() */ - /* This function will poll for a response interrupt of a request */ static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds) { @@ -1474,7 +1455,7 @@ out: /* This function will poll the status register for a flag */ static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds) { - u32 status_reg_value; + u32 status_reg_value; unsigned long before; int retval = 1; @@ -1612,9 +1593,12 @@ static int twa_reset_device_extension(TW_Device_Extension *tw_dev) (tw_dev->state[i] != TW_S_INITIAL) && (tw_dev->state[i] != TW_S_COMPLETED)) { if (tw_dev->srb[i]) { - tw_dev->srb[i]->result = (DID_RESET << 16); - tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); - twa_unmap_scsi_data(tw_dev, i); + struct scsi_cmnd *cmd = tw_dev->srb[i]; + + cmd->result = (DID_RESET << 16); + if (twa_command_mapped(cmd)) + scsi_dma_unmap(cmd); + scsi_done(cmd); } } } @@ -1711,12 +1695,9 @@ out: } /* End twa_reset_sequence() */ /* This funciton returns unit geometry in cylinders/heads/sectors */ -static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) +static int twa_scsi_biosparam(struct scsi_device *sdev, struct gendisk *unused, sector_t capacity, int geom[]) { int heads, sectors, cylinders; - TW_Device_Extension *tw_dev; - - tw_dev = (TW_Device_Extension *)sdev->host->hostdata; if (capacity >= 0x200000) { heads = 255; @@ -1765,8 +1746,9 @@ out: } /* End twa_scsi_eh_reset() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt) { + void (*done)(struct scsi_cmnd *) = scsi_done; int request_id, retval; TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; @@ -1784,30 +1766,26 @@ static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_ goto out; } - /* Save done function into scsi_cmnd struct */ - SCpnt->scsi_done = done; - /* Get a free request id */ twa_get_request_id(tw_dev, &request_id); /* Save the scsi command for use by the ISR */ tw_dev->srb[request_id] = SCpnt; - /* Initialize phase to zero */ - SCpnt->SCp.phase = TW_PHASE_INITIAL; - retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); switch (retval) { case SCSI_MLQUEUE_HOST_BUSY: + if (twa_command_mapped(SCpnt)) + scsi_dma_unmap(SCpnt); twa_free_request_id(tw_dev, request_id); - twa_unmap_scsi_data(tw_dev, request_id); break; case 1: - tw_dev->state[request_id] = TW_S_COMPLETED; - twa_free_request_id(tw_dev, request_id); - twa_unmap_scsi_data(tw_dev, request_id); SCpnt->result = (DID_ERROR << 16); + if (twa_command_mapped(SCpnt)) + scsi_dma_unmap(SCpnt); done(SCpnt); + tw_dev->state[request_id] = TW_S_COMPLETED; + twa_free_request_id(tw_dev, request_id); retval = 0; } out: @@ -1817,21 +1795,20 @@ out: static DEF_SCSI_QCMD(twa_scsi_queue) /* This function hands scsi cdb's to the firmware */ -static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg) +static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, + unsigned char *cdb, int use_sg, + TW_SG_Entry *sglistarg) { TW_Command_Full *full_command_packet; TW_Command_Apache *command_packet; u32 num_sectors = 0x0; int i, sg_count; struct scsi_cmnd *srb = NULL; - struct scatterlist *sglist = NULL, *sg; + struct scatterlist *sg; int retval = 1; - if (tw_dev->srb[request_id]) { + if (tw_dev->srb[request_id]) srb = tw_dev->srb[request_id]; - if (scsi_sglist(srb)) - sglist = scsi_sglist(srb); - } /* Initialize command packet */ full_command_packet = tw_dev->command_packet_virt[request_id]; @@ -1852,10 +1829,10 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, if (srb) { command_packet->unit = srb->device->id; command_packet->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id)); + TW_REQ_LUN_IN(srb->device->lun, request_id); } else { command_packet->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(0, request_id)); + TW_REQ_LUN_IN(0, request_id); command_packet->unit = 0; } @@ -1865,8 +1842,7 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, /* Map sglist from scsi layer to cmd packet */ if (scsi_sg_count(srb)) { - if ((scsi_sg_count(srb) == 1) && - (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) { + if (!twa_command_mapped(srb)) { if (srb->sc_data_direction == DMA_TO_DEVICE || srb->sc_data_direction == DMA_BIDIRECTIONAL) scsi_sg_copy_to_buffer(srb, @@ -1875,8 +1851,8 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH); } else { - sg_count = twa_map_scsi_sg_data(tw_dev, request_id); - if (sg_count == 0) + sg_count = scsi_dma_map(srb); + if (sg_count < 0) goto out; scsi_for_each_sg(srb, sg, sg_count, i) { @@ -1888,19 +1864,19 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, } } } - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id]))); + command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id])); } } else { /* Internal cdb post */ for (i = 0; i < use_sg; i++) { - command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address); - command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length); + command_packet->sg_list[i].address = sglistarg[i].address; + command_packet->sg_list[i].length = sglistarg[i].length; if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post"); goto out; } } - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg)); + command_packet->sgl_entries__lunh = TW_REQ_LUN_IN(0, use_sg); } if (srb) { @@ -1939,7 +1915,7 @@ static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int re { struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - if (scsi_bufflen(cmd) < TW_MIN_SGL_LENGTH && + if (!twa_command_mapped(cmd) && (cmd->sc_data_direction == DMA_FROM_DEVICE || cmd->sc_data_direction == DMA_BIDIRECTIONAL)) { if (scsi_sg_count(cmd) == 1) { @@ -1991,41 +1967,32 @@ static char *twa_string_lookup(twa_message_type *table, unsigned int code) return(table[index].text); } /* End twa_string_lookup() */ -/* This function will perform a pci-dma unmap */ -static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) -{ - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - if (cmd->SCp.phase == TW_PHASE_SGLIST) - scsi_dma_unmap(cmd); -} /* End twa_unmap_scsi_data() */ - /* This function gets called when a disk is coming on-line */ -static int twa_slave_configure(struct scsi_device *sdev) +static int twa_sdev_configure(struct scsi_device *sdev, + struct queue_limits *lim) { /* Force 60 second timeout */ blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); return 0; -} /* End twa_slave_configure() */ +} /* End twa_sdev_configure() */ -/* scsi_host_template initializer */ -static struct scsi_host_template driver_template = { +static const struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = "3ware 9000 Storage Controller", .queuecommand = twa_scsi_queue, .eh_host_reset_handler = twa_scsi_eh_reset, .bios_param = twa_scsi_biosparam, - .change_queue_depth = twa_change_queue_depth, + .change_queue_depth = scsi_change_queue_depth, .can_queue = TW_Q_LENGTH-2, - .slave_configure = twa_slave_configure, + .sdev_configure = twa_sdev_configure, .this_id = -1, .sg_tablesize = TW_APACHE_MAX_SGL_LENGTH, .max_sectors = TW_MAX_SECTORS, .cmd_per_lun = TW_MAX_CMDS_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = twa_host_attrs, - .emulated = 1 + .shost_groups = twa_host_groups, + .emulated = 1, + .no_write_same = 1, }; /* This function will probe and initialize a card */ @@ -2034,25 +2001,25 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) struct Scsi_Host *host = NULL; TW_Device_Extension *tw_dev; unsigned long mem_addr, mem_len; - int retval = -ENODEV; + int retval; retval = pci_enable_device(pdev); if (retval) { TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device"); - goto out_disable_device; + return -ENODEV; } pci_set_master(pdev); pci_try_set_mwi(pdev); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); - retval = -ENODEV; - goto out_disable_device; - } + retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (retval) + retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (retval) { + TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); + retval = -ENODEV; + goto out_disable_device; + } host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); if (!host) { @@ -2068,6 +2035,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (twa_initialize_device_extension(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension"); + retval = -ENOMEM; goto out_free_device_extension; } @@ -2090,6 +2058,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = ioremap(mem_addr, mem_len); if (!tw_dev->base_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap"); + retval = -ENOMEM; goto out_release_mem_region; } @@ -2097,8 +2066,10 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) TW_DISABLE_INTERRUPTS(tw_dev); /* Initialize the card */ - if (twa_reset_sequence(tw_dev, 0)) + if (twa_reset_sequence(tw_dev, 0)) { + retval = -ENOMEM; goto out_iounmap; + } /* Set host specific parameters */ if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) || @@ -2130,7 +2101,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE, TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), - le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, + le32_to_cpu(*(__le32 *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH))); /* Try to enable MSI */ @@ -2212,10 +2183,10 @@ static void twa_remove(struct pci_dev *pdev) twa_device_extension_count--; } /* End twa_remove() */ -#ifdef CONFIG_PM /* This function is called on PCI suspend */ -static int twa_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused twa_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct Scsi_Host *host = pci_get_drvdata(pdev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; @@ -2235,42 +2206,29 @@ static int twa_suspend(struct pci_dev *pdev, pm_message_t state) } TW_CLEAR_ALL_INTERRUPTS(tw_dev); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } /* End twa_suspend() */ /* This function is called on PCI resume */ -static int twa_resume(struct pci_dev *pdev) +static int __maybe_unused twa_resume(struct device *dev) { int retval = 0; + struct pci_dev *pdev = to_pci_dev(dev); struct Scsi_Host *host = pci_get_drvdata(pdev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; printk(KERN_WARNING "3w-9xxx: Resuming host %d.\n", tw_dev->host->host_no); - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - retval = pci_enable_device(pdev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x39, "Enable device failed during resume"); - return retval; - } - pci_set_master(pdev); pci_try_set_mwi(pdev); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume"); - retval = -ENODEV; - goto out_disable_device; - } + retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (retval) + retval = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (retval) { + TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume"); + retval = -ENODEV; + goto out_disable_device; + } /* Initialize the card */ if (twa_reset_sequence(tw_dev, 0)) { @@ -2298,14 +2256,12 @@ static int twa_resume(struct pci_dev *pdev) out_disable_device: scsi_remove_host(host); - pci_disable_device(pdev); return retval; } /* End twa_resume() */ -#endif /* PCI Devices supported by this driver */ -static struct pci_device_id twa_pci_tbl[] = { +static const struct pci_device_id twa_pci_tbl[] = { { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX, @@ -2318,16 +2274,15 @@ static struct pci_device_id twa_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, twa_pci_tbl); +static SIMPLE_DEV_PM_OPS(twa_pm_ops, twa_suspend, twa_resume); + /* pci_driver initializer */ static struct pci_driver twa_driver = { .name = "3w-9xxx", .id_table = twa_pci_tbl, .probe = twa_probe, .remove = twa_remove, -#ifdef CONFIG_PM - .suspend = twa_suspend, - .resume = twa_resume, -#endif + .driver.pm = &twa_pm_ops, .shutdown = twa_shutdown }; |
