diff options
Diffstat (limited to 'drivers/scsi/hpsa.c')
-rw-r--r-- | drivers/scsi/hpsa.c | 793 |
1 files changed, 571 insertions, 222 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index bb96fdd58e2..03697ba9425 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -52,7 +52,7 @@ #include "hpsa.h" /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "1.0.0" +#define HPSA_DRIVER_VERSION "2.0.1-3" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" /* How long to wait (in milliseconds) for board to go into simple mode */ @@ -77,9 +77,6 @@ MODULE_PARM_DESC(hpsa_allow_any, /* define the PCI info for the cards we can control */ static const struct pci_device_id hpsa_pci_device_id[] = { - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3223}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3234}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x323D}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3243}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245}, @@ -87,6 +84,9 @@ static const struct pci_device_id hpsa_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324a}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324b}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3233}, +#define PCI_DEVICE_ID_HP_CISSF 0x333f + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F}, {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, {0,} @@ -99,9 +99,6 @@ MODULE_DEVICE_TABLE(pci, hpsa_pci_device_id); * access = Address of the struct of function pointers */ static struct board_type products[] = { - {0x3223103C, "Smart Array P800", &SA5_access}, - {0x3234103C, "Smart Array P400", &SA5_access}, - {0x323d103c, "Smart Array P700M", &SA5_access}, {0x3241103C, "Smart Array P212", &SA5_access}, {0x3243103C, "Smart Array P410", &SA5_access}, {0x3245103C, "Smart Array P410i", &SA5_access}, @@ -109,6 +106,8 @@ static struct board_type products[] = { {0x3249103C, "Smart Array P812", &SA5_access}, {0x324a103C, "Smart Array P712m", &SA5_access}, {0x324b103C, "Smart Array P711m", &SA5_access}, + {0x3233103C, "StorageWorks P1210m", &SA5_access}, + {0x333F103C, "StorageWorks P1210m", &SA5_access}, {0xFFFF103C, "Unknown Smart Array", &SA5_access}, }; @@ -126,12 +125,15 @@ static void cmd_free(struct ctlr_info *h, struct CommandList *c); static void cmd_special_free(struct ctlr_info *h, struct CommandList *c); static struct CommandList *cmd_alloc(struct ctlr_info *h); static struct CommandList *cmd_special_alloc(struct ctlr_info *h); -static void fill_cmd(struct CommandList *c, __u8 cmd, struct ctlr_info *h, - void *buff, size_t size, __u8 page_code, unsigned char *scsi3addr, +static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, + void *buff, size_t size, u8 page_code, unsigned char *scsi3addr, int cmd_type); static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); +static void hpsa_scan_start(struct Scsi_Host *); +static int hpsa_scan_finished(struct Scsi_Host *sh, + unsigned long elapsed_time); static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); static int hpsa_slave_alloc(struct scsi_device *sdev); @@ -150,6 +152,11 @@ static int check_for_unit_attention(struct ctlr_info *h, struct CommandList *c); static void check_ioctl_unit_attention(struct ctlr_info *h, struct CommandList *c); +/* performant mode helper functions */ +static void calc_bucket_map(int *bucket, int num_buckets, + int nsgs, int *bucket_map); +static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); +static inline u32 next_command(struct ctlr_info *h); static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); @@ -173,10 +180,10 @@ static struct scsi_host_template hpsa_driver_template = { .name = "hpsa", .proc_name = "hpsa", .queuecommand = hpsa_scsi_queue_command, - .can_queue = 512, + .scan_start = hpsa_scan_start, + .scan_finished = hpsa_scan_finished, .this_id = -1, .sg_tablesize = MAXSGENTRIES, - .cmd_per_lun = 512, .use_clustering = ENABLE_CLUSTERING, .eh_device_reset_handler = hpsa_eh_device_reset_handler, .ioctl = hpsa_ioctl, @@ -195,6 +202,12 @@ static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) return (struct ctlr_info *) *priv; } +static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh) +{ + unsigned long *priv = shost_priv(sh); + return (struct ctlr_info *) *priv; +} + static struct task_struct *hpsa_scan_thread; static DEFINE_MUTEX(hpsa_scan_mutex); static LIST_HEAD(hpsa_scan_q); @@ -312,7 +325,7 @@ static int hpsa_scan_func(__attribute__((unused)) void *data) h->busy_scanning = 1; mutex_unlock(&hpsa_scan_mutex); host_no = h->scsi_host ? h->scsi_host->host_no : -1; - hpsa_update_scsi_devices(h, host_no); + hpsa_scan_start(h->scsi_host); complete_all(&h->scan_wait); mutex_lock(&hpsa_scan_mutex); h->busy_scanning = 0; @@ -379,8 +392,7 @@ static ssize_t host_store_rescan(struct device *dev, { struct ctlr_info *h; struct Scsi_Host *shost = class_to_shost(dev); - unsigned long *priv = shost_priv(shost); - h = (struct ctlr_info *) *priv; + h = shost_to_hba(shost); if (add_to_scan_list(h)) { wake_up_process(hpsa_scan_thread); wait_for_completion_interruptible(&h->scan_wait); @@ -394,10 +406,44 @@ static inline void addQ(struct hlist_head *list, struct CommandList *c) hlist_add_head(&c->list, list); } +static inline u32 next_command(struct ctlr_info *h) +{ + u32 a; + + if (unlikely(h->transMethod != CFGTBL_Trans_Performant)) + return h->access.command_completed(h); + + if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { + a = *(h->reply_pool_head); /* Next cmd in ring buffer */ + (h->reply_pool_head)++; + h->commands_outstanding--; + } else { + a = FIFO_EMPTY; + } + /* Check for wraparound */ + if (h->reply_pool_head == (h->reply_pool + h->max_commands)) { + h->reply_pool_head = h->reply_pool; + h->reply_pool_wraparound ^= 1; + } + return a; +} + +/* set_performant_mode: Modify the tag for cciss performant + * set bit 0 for pull model, bits 3-1 for block fetch + * register number + */ +static void set_performant_mode(struct ctlr_info *h, struct CommandList *c) +{ + if (likely(h->transMethod == CFGTBL_Trans_Performant)) + c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); +} + static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { unsigned long flags; + + set_performant_mode(h, c); spin_lock_irqsave(&h->lock, flags); addQ(&h->reqQ, c); h->Qdepth++; @@ -422,6 +468,15 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) return (scsi3addr[3] & 0xC0) == 0x40; } +static inline int is_scsi_rev_5(struct ctlr_info *h) +{ + if (!h->hba_inquiry_data) + return 0; + if ((h->hba_inquiry_data[2] & 0x07) == 5) + return 1; + return 0; +} + static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", "UNKNOWN" }; @@ -431,7 +486,7 @@ static ssize_t raid_level_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t l = 0; - int rlevel; + unsigned char rlevel; struct ctlr_info *h; struct scsi_device *sdev; struct hpsa_scsi_dev_t *hdev; @@ -455,7 +510,7 @@ static ssize_t raid_level_show(struct device *dev, rlevel = hdev->raid_level; spin_unlock_irqrestore(&h->lock, flags); - if (rlevel < 0 || rlevel > RAID_UNKNOWN) + if (rlevel > RAID_UNKNOWN) rlevel = RAID_UNKNOWN; l = snprintf(buf, PAGE_SIZE, "RAID %s\n", raid_label[rlevel]); return l; @@ -620,6 +675,24 @@ lun_assigned: return 0; } +/* Replace an entry from h->dev[] array. */ +static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, + int entry, struct hpsa_scsi_dev_t *new_entry, + struct hpsa_scsi_dev_t *added[], int *nadded, + struct hpsa_scsi_dev_t *removed[], int *nremoved) +{ + /* assumes h->devlock is held */ + BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA); + removed[*nremoved] = h->dev[entry]; + (*nremoved)++; + h->dev[entry] = new_entry; + added[*nadded] = new_entry; + (*nadded)++; + dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d changed.\n", + scsi_device_type(new_entry->devtype), hostno, new_entry->bus, + new_entry->target, new_entry->lun); +} + /* Remove an entry from h->dev[] array. */ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, struct hpsa_scsi_dev_t *removed[], int *nremoved) @@ -628,8 +701,7 @@ static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, int i; struct hpsa_scsi_dev_t *sd; - if (entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA) - BUG(); + BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA); sd = h->dev[entry]; removed[*nremoved] = h->dev[entry]; @@ -722,6 +794,8 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle, #define DEVICE_CHANGED 1 #define DEVICE_SAME 2 for (i = 0; i < haystack_size; i++) { + if (haystack[i] == NULL) /* previously removed. */ + continue; if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) { *index = i; if (device_is_the_same(needle, haystack[i])) @@ -734,7 +808,7 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle, return DEVICE_NOT_FOUND; } -static int adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, +static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, struct hpsa_scsi_dev_t *sd[], int nsds) { /* sd contains scsi3 addresses and devtypes, and inquiry @@ -779,12 +853,12 @@ static int adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, continue; /* remove ^^^, hence i not incremented */ } else if (device_change == DEVICE_CHANGED) { changes++; - hpsa_scsi_remove_entry(h, hostno, i, - removed, &nremoved); - (void) hpsa_scsi_add_entry(h, hostno, sd[entry], - added, &nadded); - /* add can't fail, we just removed one. */ - sd[entry] = NULL; /* prevent it from being freed */ + hpsa_scsi_replace_entry(h, hostno, i, sd[entry], + added, &nadded, removed, &nremoved); + /* Set it to NULL to prevent it from being freed + * at the bottom of hpsa_update_scsi_devices() + */ + sd[entry] = NULL; } i++; } @@ -860,7 +934,6 @@ static int adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, free_and_out: kfree(added); kfree(removed); - return 0; } /* @@ -900,7 +973,7 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) static void hpsa_slave_destroy(struct scsi_device *sdev) { - return; /* nothing to do. */ + /* nothing to do. */ } static void hpsa_scsi_setup(struct ctlr_info *h) @@ -908,11 +981,10 @@ static void hpsa_scsi_setup(struct ctlr_info *h) h->ndevices = 0; h->scsi_host = NULL; spin_lock_init(&h->devlock); - return; } static void complete_scsi_command(struct CommandList *cp, - int timeout, __u32 tag) + int timeout, u32 tag) { struct scsi_cmnd *cmd; struct ctlr_info *h; @@ -987,7 +1059,6 @@ static void complete_scsi_command(struct CommandList *cp, * required */ if ((asc == 0x04) && (ascq == 0x03)) { - cmd->result = DID_NO_CONNECT << 16; dev_warn(&h->pdev->dev, "cp %p " "has check condition: unit " "not ready, manual " @@ -995,14 +1066,22 @@ static void complete_scsi_command(struct CommandList *cp, break; } } - - + if (sense_key == ABORTED_COMMAND) { + /* Aborted command is retryable */ + dev_warn(&h->pdev->dev, "cp %p " + "has check condition: aborted command: " + "ASC: 0x%x, ASCQ: 0x%x\n", + cp, asc, ascq); + cmd->result = DID_SOFT_ERROR << 16; + break; + } /* Must be some other type of check condition */ dev_warn(&h->pdev->dev, "cp %p has check condition: " "unknown type: " "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, " "Returning result: 0x%x, " "cmd=[%02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x]\n", cp, sense_key, asc, ascq, cmd->result, @@ -1010,7 +1089,10 @@ static void complete_scsi_command(struct CommandList *cp, cmd->cmnd[2], cmd->cmnd[3], cmd->cmnd[4], cmd->cmnd[5], cmd->cmnd[6], cmd->cmnd[7], - cmd->cmnd[8], cmd->cmnd[9]); + cmd->cmnd[8], cmd->cmnd[9], + cmd->cmnd[10], cmd->cmnd[11], + cmd->cmnd[12], cmd->cmnd[13], + cmd->cmnd[14], cmd->cmnd[15]); break; } @@ -1086,7 +1168,7 @@ static void complete_scsi_command(struct CommandList *cp, dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp); break; case CMD_UNSOLICITED_ABORT: - cmd->result = DID_ABORT << 16; + cmd->result = DID_RESET << 16; dev_warn(&h->pdev->dev, "cp %p aborted do to an unsolicited " "abort\n", cp); break; @@ -1119,9 +1201,11 @@ static int hpsa_scsi_detect(struct ctlr_info *h) sh->max_cmd_len = MAX_COMMAND_SIZE; sh->max_lun = HPSA_MAX_LUN; sh->max_id = HPSA_MAX_LUN; + sh->can_queue = h->nr_cmds; + sh->cmd_per_lun = h->nr_cmds; h->scsi_host = sh; sh->hostdata[0] = (unsigned long) h; - sh->irq = h->intr[SIMPLE_MODE_INT]; + sh->irq = h->intr[PERF_MODE_INT]; sh->unique_id = sh->irq; error = scsi_add_host(sh, &h->pdev->dev); if (error) @@ -1133,11 +1217,11 @@ static int hpsa_scsi_detect(struct ctlr_info *h) dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_add_host" " failed for controller %d\n", h->ctlr); scsi_host_put(sh); - return -1; + return error; fail: dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_host_alloc" " failed for controller %d\n", h->ctlr); - return -1; + return -ENOMEM; } static void hpsa_pci_unmap(struct pci_dev *pdev, @@ -1160,7 +1244,7 @@ static void hpsa_map_one(struct pci_dev *pdev, size_t buflen, int data_direction) { - __u64 addr64; + u64 addr64; if (buflen == 0 || data_direction == PCI_DMA_NONE) { cp->Header.SGList = 0; @@ -1168,14 +1252,14 @@ static void hpsa_map_one(struct pci_dev *pdev, return; } - addr64 = (__u64) pci_map_single(pdev, buf, buflen, data_direction); + addr64 = (u64) pci_map_single(pdev, buf, buflen, data_direction); cp->SG[0].Addr.lower = - (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF); + (u32) (addr64 & (u64) 0x00000000FFFFFFFF); cp->SG[0].Addr.upper = - (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF); + (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF); cp->SG[0].Len = buflen; - cp->Header.SGList = (__u8) 1; /* no. SGs contig in this cmd */ - cp->Header.SGTotal = (__u16) 1; /* total sgs in this cmd list */ + cp->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */ + cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */ } static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, @@ -1274,7 +1358,7 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, if (c == NULL) { /* trouble... */ dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); - return -1; + return -ENOMEM; } fill_cmd(c, HPSA_INQUIRY, h, buf, bufsize, page, scsi3addr, TYPE_CMD); @@ -1366,9 +1450,8 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); return -1; } - - memset(&scsi3addr[0], 0, 8); /* address the controller */ - + /* address the controller */ + memset(scsi3addr, 0, sizeof(scsi3addr)); fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h, buf, bufsize, 0, scsi3addr, TYPE_CMD); if (extended_response) @@ -1409,13 +1492,12 @@ static int hpsa_update_device_info(struct ctlr_info *h, unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device) { #define OBDR_TAPE_INQ_SIZE 49 - unsigned char *inq_buff = NULL; + unsigned char *inq_buff; - inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); + inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); if (!inq_buff) goto bail_out; - memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE); /* Do an inquiry to the device to see what it is. */ if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff, (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) { @@ -1485,32 +1567,51 @@ static int is_msa2xxx(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) * in hpsa_find_target_lun, called by hpsa_scsi_add_entry.) */ static void figure_bus_target_lun(struct ctlr_info *h, - __u8 *lunaddrbytes, int *bus, int *target, int *lun, + u8 *lunaddrbytes, int *bus, int *target, int *lun, struct hpsa_scsi_dev_t *device) { - - __u32 lunid; + u32 lunid; if (is_logical_dev_addr_mode(lunaddrbytes)) { /* logical device */ - memcpy(&lunid, lunaddrbytes, sizeof(lunid)); - lunid = le32_to_cpu(lunid); - - if (is_msa2xxx(h, device)) { - *bus = 1; - *target = (lunid >> 16) & 0x3fff; - *lun = lunid & 0x00ff; - } else { + if (unlikely(is_scsi_rev_5(h))) { + /* p1210m, logical drives lun assignments + * match SCSI REPORT LUNS data. + */ + lunid = le32_to_cpu(*((__le32 *) lunaddrbytes)); *bus = 0; - *lun = 0; - *target = lunid & 0x3fff; + *target = 0; + *lun = (lunid & 0x3fff) + 1; + } else { + /* not p1210m... */ + lunid = le32_to_cpu(*((__le32 *) lunaddrbytes)); + if (is_msa2xxx(h, device)) { + /* msa2xxx way, put logicals on bus 1 + * and match target/lun numbers box + * reports. + */ + *bus = 1; + *target = (lunid >> 16) & 0x3fff; + *lun = lunid & 0x00ff; + } else { + /* Traditional smart array way. */ + *bus = 0; + *lun = 0; + *target = lunid & 0x3fff; + } } } else { /* physical device */ if (is_hba_lunid(lunaddrbytes)) - *bus = 3; + if (unlikely(is_scsi_rev_5(h))) { + *bus = 0; /* put p1210m ctlr at 0,0,0 */ + *target = 0; + *lun = 0; + return; + } else + *bus = 3; /* traditional smartarray */ else - *bus = 2; + *bus = 2; /* physical disk */ *target = -1; *lun = -1; /* we will fill these in later. */ } @@ -1529,7 +1630,7 @@ static void figure_bus_target_lun(struct ctlr_info *h, */ static int add_msa2xxx_enclosure_device(struct ctlr_info *h, struct hpsa_scsi_dev_t *tmpdevice, - struct hpsa_scsi_dev_t *this_device, __u8 *lunaddrbytes, + struct hpsa_scsi_dev_t *this_device, u8 *lunaddrbytes, int bus, int target, int lun, unsigned long lunzerobits[], int *nmsa2xxx_enclosures) { @@ -1550,6 +1651,9 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h, if (is_hba_lunid(scsi3addr)) return 0; /* Don't add the RAID controller here. */ + if (is_scsi_rev_5(h)) + return 0; /* p1210m doesn't need to do this. */ + #define MAX_MSA2XXX_ENCLOSURES 32 if (*nmsa2xxx_enclosures >= MAX_MSA2XXX_ENCLOSURES) { dev_warn(&h->pdev->dev, "Maximum number of MSA2XXX " @@ -1576,18 +1680,14 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h, */ static int hpsa_gather_lun_info(struct ctlr_info *h, int reportlunsize, - struct ReportLUNdata *physdev, __u32 *nphysicals, - struct ReportLUNdata *logdev, __u32 *nlogicals) + struct ReportLUNdata *physdev, u32 *nphysicals, + struct ReportLUNdata *logdev, u32 *nlogicals) { if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize, 0)) { dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); return -1; } - memcpy(nphysicals, &physdev->LUNListLength[0], sizeof(*nphysicals)); - *nphysicals = be32_to_cpu(*nphysicals) / 8; -#ifdef DEBUG - dev_info(&h->pdev->dev, "number of physical luns is %d\n", *nphysicals); -#endif + *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 8; if (*nphysicals > HPSA_MAX_PHYS_LUN) { dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded." " %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN, @@ -1598,11 +1698,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h, dev_err(&h->pdev->dev, "report logical LUNs failed.\n"); return -1; } - memcpy(nlogicals, &logdev->LUNListLength[0], sizeof(*nlogicals)); - *nlogicals = be32_to_cpu(*nlogicals) / 8; -#ifdef DEBUG - dev_info(&h->pdev->dev, "number of logical luns is %d\n", *nlogicals); -#endif + *nlogicals = be32_to_cpu(*((__be32 *) logdev->LUNListLength)) / 8; /* Reject Logicals in excess of our max capability. */ if (*nlogicals > HPSA_MAX_LUN) { dev_warn(&h->pdev->dev, @@ -1621,6 +1717,31 @@ static int hpsa_gather_lun_info(struct ctlr_info *h, return 0; } +u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i, + int nphysicals, int nlogicals, struct ReportLUNdata *physdev_list, + struct ReportLUNdata *logdev_list) +{ + /* Helper function, figure out where the LUN ID info is coming from + * given index i, lists of physical and logical devices, where in + * the list the raid controller is supposed to appear (first or last) + */ + + int logicals_start = nphysicals + (raid_ctlr_position == 0); + int last_device = nphysicals + nlogicals + (raid_ctlr_position == 0); + + if (i == raid_ctlr_position) + return RAID_CTLR_LUNID; + + if (i < logicals_start) + return &physdev_list->LUN[i - (raid_ctlr_position == 0)][0]; + + if (i < last_device) + return &logdev_list->LUN[i - nphysicals - + (raid_ctlr_position == 0)][0]; + BUG(); + return NULL; +} + static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) { /* the idea here is we could get notified @@ -1636,14 +1757,15 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) struct ReportLUNdata *physdev_list = NULL; struct ReportLUNdata *logdev_list = NULL; unsigned char *inq_buff = NULL; - __u32 nphysicals = 0; - __u32 nlogicals = 0; - __u32 ndev_allocated = 0; + u32 nphysicals = 0; + u32 nlogicals = 0; + u32 ndev_allocated = 0; struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; int ncurrent = 0; int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8; int i, nmsa2xxx_enclosures, ndevs_to_allocate; int bus, target, lun; + int raid_ctlr_position; DECLARE_BITMAP(lunzerobits, HPSA_MAX_TARGETS_PER_CTLR); currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_SCSI_DEVS_PER_HBA, @@ -1681,23 +1803,22 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ndev_allocated++; } + if (unlikely(is_scsi_rev_5(h))) + raid_ctlr_position = 0; + else + raid_ctlr_position = nphysicals + nlogicals; + /* adjust our table of devices */ nmsa2xxx_enclosures = 0; for (i = 0; i < nphysicals + nlogicals + 1; i++) { - __u8 *lunaddrbytes; + u8 *lunaddrbytes; /* Figure out where the LUN ID info is coming from */ - if (i < nphysicals) - lunaddrbytes = &physdev_list->LUN[i][0]; - else - if (i < nphysicals + nlogicals) - lunaddrbytes = - &logdev_list->LUN[i-nphysicals][0]; - else /* jam in the RAID controller at the end */ - lunaddrbytes = RAID_CTLR_LUNID; - + lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position, + i, nphysicals, nlogicals, physdev_list, logdev_list); /* skip masked physical devices. */ - if (lunaddrbytes[3] & 0xC0 && i < nphysicals) + if (lunaddrbytes[3] & 0xC0 && + i < nphysicals + (raid_ctlr_position == 0)) continue; /* Get device type, vendor, model, device id */ @@ -1777,7 +1898,6 @@ out: kfree(inq_buff); kfree(physdev_list); kfree(logdev_list); - return; } /* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci @@ -1790,7 +1910,7 @@ static int hpsa_scatter_gather(struct pci_dev *pdev, { unsigned int len; struct scatterlist *sg; - __u64 addr64; + u64 addr64; int use_sg, i; BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES); @@ -1803,20 +1923,20 @@ static int hpsa_scatter_gather(struct pci_dev *pdev, goto sglist_finished; scsi_for_each_sg(cmd, sg, use_sg, i) { - addr64 = (__u64) sg_dma_address(sg); + addr64 = (u64) sg_dma_address(sg); len = sg_dma_len(sg); cp->SG[i].Addr.lower = - (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF); + (u32) (addr64 & (u64) 0x00000000FFFFFFFF); cp->SG[i].Addr.upper = - (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF); + (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF); cp->SG[i].Len = len; cp->SG[i].Ext = 0; /* we are not chaining */ } sglist_finished: - cp->Header.SGList = (__u8) use_sg; /* no. SGs contig in this cmd */ - cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */ + cp->Header.SGList = (u8) use_sg; /* no. SGs contig in this cmd */ + cp->Header.SGTotal = (u16) use_sg; /* total sgs in this cmd list */ return 0; } @@ -1860,7 +1980,8 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd, c->scsi_cmd = cmd; c->Header.ReplyQueue = 0; /* unused in simple mode */ memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); - c->Header.Tag.lower = c->busaddr; /* Use k. address of cmd as tag */ + c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT); + c->Header.Tag.lower |= DIRECT_LOOKUP_BIT; /* Fill in the request block... */ @@ -1914,6 +2035,48 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd, return 0; } +static void hpsa_scan_start(struct Scsi_Host *sh) +{ + struct ctlr_info *h = shost_to_hba(sh); + unsigned long flags; + + /* wait until any scan already in progress is finished. */ + while (1) { + spin_lock_irqsave(&h->scan_lock, flags); + if (h->scan_finished) + break; + spin_unlock_irqrestore(&h->scan_lock, flags); + wait_event(h->scan_wait_queue, h->scan_finished); + /* Note: We don't need to worry about a race between this + * thread and driver unload because the midlayer will + * have incremented the reference count, so unload won't + * happen if we're in here. + */ + } + h->scan_finished = 0; /* mark scan as in progress */ + spin_unlock_irqrestore(&h->scan_lock, flags); + + hpsa_update_scsi_devices(h, h->scsi_host->host_no); + + spin_lock_irqsave(&h->scan_lock, flags); + h->scan_finished = 1; /* mark scan as finished. */ + wake_up_all(&h->scan_wait_queue); + spin_unlock_irqrestore(&h->scan_lock, flags); +} + +static int hpsa_scan_finished(struct Scsi_Host *sh, + unsigned long elapsed_time) +{ + struct ctlr_info *h = shost_to_hba(sh); + unsigned long flags; + int finished; + + spin_lock_irqsave(&h->scan_lock, flags); + finished = h->scan_finished; + spin_unlock_irqrestore(&h->scan_lock, flags); + return finished; +} + static void hpsa_unregister_scsi(struct ctlr_info *h) { /* we are being forcibly unloaded, and may not refuse. */ @@ -1926,7 +2089,6 @@ static int hpsa_register_scsi(struct ctlr_info *h) { int rc; - hpsa_update_scsi_devices(h, -1); rc = hpsa_scsi_detect(h); if (rc != 0) dev_err(&h->pdev->dev, "hpsa_register_scsi: failed" @@ -2003,14 +2165,14 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) h = sdev_to_hba(scsicmd->device); if (h == NULL) /* paranoia */ return FAILED; - dev_warn(&h->pdev->dev, "resetting drive\n"); - dev = scsicmd->device->hostdata; if (!dev) { dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: " "device lookup failed.\n"); return FAILED; } + dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n", + h->scsi_host->host_no, dev->bus, dev->target, dev->lun); /* send a reset to the SCSI LUN which the command was sent to */ rc = hpsa_send_reset(h, dev->scsi3addr); if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0) @@ -2053,8 +2215,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) c->cmdindex = i; INIT_HLIST_NODE(&c->list); - c->busaddr = (__u32) cmd_dma_handle; - temp64.val = (__u64) err_dma_handle; + c->busaddr = (u32) cmd_dma_handle; + temp64.val = (u64) err_dma_handle; c->ErrDesc.Addr.lower = temp64.val32.lower; c->ErrDesc.Addr.upper = temp64.val32.upper; c->ErrDesc.Len = sizeof(*c->err_info); @@ -2091,8 +2253,8 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h) memset(c->err_info, 0, sizeof(*c->err_info)); INIT_HLIST_NODE(&c->list); - c->busaddr = (__u32) cmd_dma_handle; - temp64.val = (__u64) err_dma_handle; + c->busaddr = (u32) cmd_dma_handle; + temp64.val = (u64) err_dma_handle; c->ErrDesc.Addr.lower = temp64.val32.lower; c->ErrDesc.Addr.upper = temp64.val32.upper; c->ErrDesc.Len = sizeof(*c->err_info); @@ -2125,50 +2287,6 @@ static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) #ifdef CONFIG_COMPAT -static int do_ioctl(struct scsi_device *dev, int cmd, void *arg) -{ - int ret; - - lock_kernel(); - ret = hpsa_ioctl(dev, cmd, arg); - unlock_kernel(); - return ret; -} - -static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg); -static int hpsa_ioctl32_big_passthru(struct scsi_device *dev, - int cmd, void *arg); - -static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg) -{ - switch (cmd) { - case CCISS_GETPCIINFO: - case CCISS_GETINTINFO: - case CCISS_SETINTINFO: - case CCISS_GETNODENAME: - case CCISS_SETNODENAME: - case CCISS_GETHEARTBEAT: - case CCISS_GETBUSTYPES: - case CCISS_GETFIRMVER: - case CCISS_GETDRIVVER: - case CCISS_REVALIDVOLS: - case CCISS_DEREGDISK: - case CCISS_REGNEWDISK: - case CCISS_REGNEWD: - case CCISS_RESCANDISK: - case CCISS_GETLUNINFO: - return do_ioctl(dev, cmd, arg); - - case CCISS_PASSTHRU32: - return hpsa_ioctl32_passthru(dev, cmd, arg); - case CCISS_BIG_PASSTHRU32: - return hpsa_ioctl32_big_passthru(dev, cmd, arg); - - default: - return -ENOIOCTLCMD; - } -} - static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg) { IOCTL32_Command_struct __user *arg32 = @@ -2193,7 +2311,7 @@ static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg) if (err) return -EFAULT; - err = do_ioctl(dev, CCISS_PASSTHRU, (void *)p); + err = hpsa_ioctl(dev, CCISS_PASSTHRU, (void *)p); if (err) return err; err |= copy_in_user(&arg32->error_info, &p->error_info, @@ -2230,7 +2348,7 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev, if (err) return -EFAULT; - err = do_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p); + err = hpsa_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p); if (err) return err; err |= copy_in_user(&arg32->error_info, &p->error_info, @@ -2239,6 +2357,36 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev, return -EFAULT; return err; } + +static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg) +{ + switch (cmd) { + case CCISS_GETPCIINFO: + case CCISS_GETINTINFO: + case CCISS_SETINTINFO: + case CCISS_GETNODENAME: + case CCISS_SETNODENAME: + case CCISS_GETHEARTBEAT: + case CCISS_GETBUSTYPES: + case CCISS_GETFIRMVER: + case CCISS_GETDRIVVER: + case CCISS_REVALIDVOLS: + case CCISS_DEREGDISK: + case CCISS_REGNEWDISK: + case CCISS_REGNEWD: + case CCISS_RESCANDISK: + case CCISS_GETLUNINFO: + return hpsa_ioctl(dev, cmd, arg); + + case CCISS_PASSTHRU32: + return hpsa_ioctl32_passthru(dev, cmd, arg); + case CCISS_BIG_PASSTHRU32: + return hpsa_ioctl32_big_passthru(dev, cmd, arg); + + default: + return -ENOIOCTLCMD; + } +} #endif static int hpsa_getpciinfo_ioctl(struct ctlr_info *h, void __user *argp) @@ -2378,8 +2526,8 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) BYTE sg_used = 0; int status = 0; int i; - __u32 left; - __u32 sz; + u32 left; + u32 sz; BYTE __user *data_ptr; if (!argp) @@ -2527,7 +2675,7 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) case CCISS_DEREGDISK: case CCISS_REGNEWDISK: case CCISS_REGNEWD: - hpsa_update_scsi_devices(h, dev->host->host_no); + hpsa_scan_start(h->scsi_host); return 0; case CCISS_GETPCIINFO: return hpsa_getpciinfo_ioctl(h, argp); @@ -2542,8 +2690,8 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) } } -static void fill_cmd(struct CommandList *c, __u8 cmd, struct ctlr_info *h, - void *buff, size_t size, __u8 page_code, unsigned char *scsi3addr, +static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, + void *buff, size_t size, u8 page_code, unsigned char *scsi3addr, int cmd_type) { int pci_dir = XFER_NONE; @@ -2710,19 +2858,20 @@ static inline unsigned long get_next_completion(struct ctlr_info *h) return h->access.command_completed(h); } -static inline int interrupt_pending(struct ctlr_info *h) +static inline bool interrupt_pending(struct ctlr_info *h) { return h->access.intr_pending(h); } static inline long interrupt_not_for_us(struct ctlr_info *h) { - return ((h->access.intr_pending(h) == 0) || - (h->interrupts_enabled == 0)); + return !(h->msi_vector || h->msix_vector) && + ((h->access.intr_pending(h) == 0) || + (h->interrupts_enabled == 0)); } -static inline int bad_tag(struct ctlr_info *h, __u32 tag_index, - __u32 raw_tag) +static inline int bad_tag(struct ctlr_info *h, u32 tag_index, + u32 raw_tag) { if (unlikely(tag_index >= h->nr_cmds)) { dev_warn(&h->pdev->dev, "bad tag 0x%08x ignored.\n", raw_tag); @@ -2731,7 +2880,7 @@ static inline int bad_tag(struct ctlr_info *h, __u32 tag_index, return 0; } -static inline void finish_cmd(struct CommandList *c, __u32 raw_tag) +static inline void finish_cmd(struct CommandList *c, u32 raw_tag) { removeQ(c); if (likely(c->cmd_type == CMD_SCSI)) @@ -2740,42 +2889,79 @@ static inline void finish_cmd(struct CommandList *c, __u32 raw_tag) complete(c->waiting); } +static inline u32 hpsa_tag_contains_index(u32 tag) +{ +#define DIRECT_LOOKUP_BIT 0x10 + return tag & DIRECT_LOOKUP_BIT; +} + +static inline u32 hpsa_tag_to_index(u32 tag) +{ +#define DIRECT_LOOKUP_SHIFT 5 + return tag >> DIRECT_LOOKUP_SHIFT; +} + +static inline u32 hpsa_tag_discard_error_bits(u32 tag) +{ +#define HPSA_ERROR_BITS 0x03 + return tag & ~HPSA_ERROR_BITS; +} + +/* process completion of an indexed ("direct lookup") command */ +static inline u32 process_indexed_cmd(struct ctlr_info *h, + u32 raw_tag) +{ + u32 tag_index; + struct CommandList *c; + + tag_index = hpsa_tag_to_index(raw_tag); + if (bad_tag(h, tag_index, raw_tag)) + return next_command(h); + c = h->cmd_pool + tag_index; + finish_cmd(c, raw_tag); + return next_command(h); +} + +/* process completion of a non-indexed command */ +static inline u32 process_nonindexed_cmd(struct ctlr_info *h, + u32 raw_tag) +{ + u32 tag; + struct CommandList *c = NULL; + struct hlist_node *tmp; + + tag = hpsa_tag_discard_error_bits(raw_tag); + hlist_for_each_entry(c, tmp, &h->cmpQ, list) { + if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) { + finish_cmd(c, raw_tag); + return next_command(h); + } + } + bad_tag(h, h->nr_cmds + 1, raw_tag); + return next_command(h); +} + static irqreturn_t do_hpsa_intr(int irq, void *dev_id) { struct ctlr_info *h = dev_id; - struct CommandList *c; unsigned long flags; - __u32 raw_tag, tag, tag_index; - struct hlist_node *tmp; + u32 raw_tag; if (interrupt_not_for_us(h)) return IRQ_NONE; spin_lock_irqsave(&h->lock, flags); - while (interrupt_pending(h)) { - while ((raw_tag = get_next_completion(h)) != FIFO_EMPTY) { - if (likely(HPSA_TAG_CONTAINS_INDEX(raw_tag))) { - tag_index = HPSA_TAG_TO_INDEX(raw_tag); - if (bad_tag(h, tag_index, raw_tag)) - return IRQ_HANDLED; - c = h->cmd_pool + tag_index; - finish_cmd(c, raw_tag); - continue; - } - tag = HPSA_TAG_DISCARD_ERROR_BITS(raw_tag); - c = NULL; - hlist_for_each_entry(c, tmp, &h->cmpQ, list) { - if (c->busaddr == tag) { - finish_cmd(c, raw_tag); - |