X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fblock%2Fcciss.c;h=5acc6c44aeadd1a57908ad3d63001df665496561;hb=772dce71f5468d97143aef74be04e34faa712d48;hp=892e092afe9a8235ca013febe1ed05a08e7d9291;hpb=1ecb9c0f3c9ef6af77c39a9f584940691847ccf4;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 892e092..5acc6c4 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -45,6 +45,10 @@ #include #include #include +#include +#include +#include +#include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) #define DRIVER_NAME "HP CISS Driver (v 3.6.14)" @@ -225,6 +229,8 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, #include "cciss_scsi.c" /* For SCSI tape support */ +#define RAID_UNKNOWN 6 + #ifdef CONFIG_PROC_FS /* @@ -232,7 +238,6 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, */ #define ENG_GIG 1000000000 #define ENG_GIG_FACTOR (ENG_GIG/512) -#define RAID_UNKNOWN 6 static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", "UNKNOWN" }; @@ -535,7 +540,7 @@ static int do_ioctl(struct file *f, unsigned cmd, unsigned long arg) { int ret; lock_kernel(); - ret = cciss_ioctl(f->f_dentry->d_inode, f, cmd, arg); + ret = cciss_ioctl(f->f_path.dentry->d_inode, f, cmd, arg); unlock_kernel(); return ret; } @@ -1039,7 +1044,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, status = -ENOMEM; goto cleanup1; } - buff_size = (int *)kmalloc(MAXSGENTRIES * sizeof(int), + buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL); if (!buff_size) { status = -ENOMEM; @@ -1151,6 +1156,30 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, kfree(ioc); return status; } + + /* scsi_cmd_ioctl handles these, below, though some are not */ + /* very meaningful for cciss. SG_IO is the main one people want. */ + + case SG_GET_VERSION_NUM: + case SG_SET_TIMEOUT: + case SG_GET_TIMEOUT: + case SG_GET_RESERVED_SIZE: + case SG_SET_RESERVED_SIZE: + case SG_EMULATED_HOST: + case SG_IO: + case SCSI_IOCTL_SEND_COMMAND: + return scsi_cmd_ioctl(filep, disk, cmd, argp); + + /* scsi_cmd_ioctl would normally handle these, below, but */ + /* they aren't a good fit for cciss, as CD-ROMs are */ + /* not supported, and we don't have any bus/target/lun */ + /* which we present to the kernel. */ + + case CDROM_SEND_PACKET: + case CDROMCLOSETRAY: + case CDROMEJECT: + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_GET_BUS_NUMBER: default: return -ENOTTY; } @@ -1233,7 +1262,7 @@ static void cciss_softirq_done(struct request *rq) pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); } - complete_buffers(rq->bio, rq->errors); + complete_buffers(rq->bio, (rq->errors == 0)); if (blk_fs_request(rq)) { const int rw = rq_data_dir(rq); @@ -1247,7 +1276,7 @@ static void cciss_softirq_done(struct request *rq) add_disk_randomness(rq->rq_disk); spin_lock_irqsave(&h->lock, flags); - end_that_request_last(rq, rq->errors); + end_that_request_last(rq, (rq->errors == 0)); cmd_free(h, cmd, 1); cciss_check_queues(h); spin_unlock_irqrestore(&h->lock, flags); @@ -1290,13 +1319,19 @@ static void cciss_update_drive_info(int ctlr, int drv_index) if (inq_buff == NULL) goto mem_msg; + /* testing to see if 16-byte CDBs are already being used */ + if (h->cciss_read == CCISS_READ_16) { + cciss_read_capacity_16(h->ctlr, drv_index, 1, + &total_size, &block_size); + goto geo_inq; + } + cciss_read_capacity(ctlr, drv_index, 1, &total_size, &block_size); - /* total size = last LBA + 1 */ - /* FFFFFFFF + 1 = 0, cannot have a logical volume of size 0 */ - /* so we assume this volume this must be >2TB in size */ - if (total_size == (__u32) 0) { + /* if read_capacity returns all F's this volume is >2TB in size */ + /* so we switch to 16-byte CDB's for all read/write ops */ + if (total_size == 0xFFFFFFFFULL) { cciss_read_capacity_16(ctlr, drv_index, 1, &total_size, &block_size); h->cciss_read = CCISS_READ_16; @@ -1305,6 +1340,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index) h->cciss_read = CCISS_READ_10; h->cciss_write = CCISS_WRITE_10; } +geo_inq: cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, inq_buff, &h->drv[drv_index]); @@ -1431,7 +1467,7 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) if (return_code == IO_OK) { listlength = - be32_to_cpu(*(__u32 *) ld_buff->LUNListLength); + be32_to_cpu(*(__be32 *) ld_buff->LUNListLength); } else { /* reading number of logical volumes failed */ printk(KERN_WARNING "cciss: report logical volume" " command failed\n"); @@ -1907,6 +1943,8 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, "does not support reading geometry\n"); drv->heads = 255; drv->sectors = 32; // Sectors per track + drv->cylinders = total_size + 1; + drv->raid_level = RAID_UNKNOWN; } else { drv->heads = inq_buff->data_byte[6]; drv->sectors = inq_buff->data_byte[7]; @@ -1915,13 +1953,14 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, drv->raid_level = inq_buff->data_byte[8]; } drv->block_size = block_size; - drv->nr_blocks = total_size; + drv->nr_blocks = total_size + 1; t = drv->heads * drv->sectors; if (t > 1) { - unsigned rem = sector_div(total_size, t); + sector_t real_size = total_size + 1; + unsigned long rem = sector_div(real_size, t); if (rem) - total_size++; - drv->cylinders = total_size; + real_size++; + drv->cylinders = real_size; } } else { /* Get geometry failed */ printk(KERN_WARNING "cciss: reading geometry failed\n"); @@ -1951,16 +1990,16 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, ctlr, buf, sizeof(ReadCapdata_struct), 1, logvol, 0, NULL, TYPE_CMD); if (return_code == IO_OK) { - *total_size = be32_to_cpu(*(__u32 *) buf->total_size)+1; - *block_size = be32_to_cpu(*(__u32 *) buf->block_size); + *total_size = be32_to_cpu(*(__be32 *) buf->total_size); + *block_size = be32_to_cpu(*(__be32 *) buf->block_size); } else { /* read capacity command failed */ printk(KERN_WARNING "cciss: read capacity failed\n"); *total_size = 0; *block_size = BLOCK_SIZE; } - if (*total_size != (__u32) 0) + if (*total_size != 0) printk(KERN_INFO " blocks= %llu block_size= %d\n", - (unsigned long long)*total_size, *block_size); + (unsigned long long)*total_size+1, *block_size); kfree(buf); return; } @@ -1987,15 +2026,15 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, 1, logvol, 0, NULL, TYPE_CMD); } if (return_code == IO_OK) { - *total_size = be64_to_cpu(*(__u64 *) buf->total_size)+1; - *block_size = be32_to_cpu(*(__u32 *) buf->block_size); + *total_size = be64_to_cpu(*(__be64 *) buf->total_size); + *block_size = be32_to_cpu(*(__be32 *) buf->block_size); } else { /* read capacity command failed */ printk(KERN_WARNING "cciss: read capacity failed\n"); *total_size = 0; *block_size = BLOCK_SIZE; } printk(KERN_INFO " blocks= %llu block_size= %d\n", - (unsigned long long)*total_size, *block_size); + (unsigned long long)*total_size+1, *block_size); kfree(buf); return; } @@ -2325,6 +2364,44 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) start_io(h); } +static inline int evaluate_target_status(CommandList_struct *cmd) +{ + unsigned char sense_key; + int error_count = 1; + + if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */ + if (!blk_pc_request(cmd->rq)) + printk(KERN_WARNING "cciss: cmd %p " + "has SCSI Status 0x%x\n", + cmd, cmd->err_info->ScsiStatus); + return error_count; + } + + /* check the sense key */ + sense_key = 0xf & cmd->err_info->SenseInfo[2]; + /* no status or recovered error */ + if ((sense_key == 0x0) || (sense_key == 0x1)) + error_count = 0; + + if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ + if (error_count != 0) + printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" + " sense key = 0x%x\n", cmd, sense_key); + return error_count; + } + + /* SG_IO or similar, copy sense data back */ + if (cmd->rq->sense) { + if (cmd->rq->sense_len > cmd->err_info->SenseLen) + cmd->rq->sense_len = cmd->err_info->SenseLen; + memcpy(cmd->rq->sense, cmd->err_info->SenseInfo, + cmd->rq->sense_len); + } else + cmd->rq->sense_len = 0; + + return error_count; +} + /* checks the status of the job and calls complete buffers to mark all * buffers for the completed job. Note that this function does not need * to hold the hba/queue lock. @@ -2332,109 +2409,99 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, int timeout) { - int status = 1; int retry_cmd = 0; + struct request *rq = cmd->rq; + + rq->errors = 0; if (timeout) - status = 0; + rq->errors = 1; - if (cmd->err_info->CommandStatus != 0) { /* an error has occurred */ - switch (cmd->err_info->CommandStatus) { - unsigned char sense_key; - case CMD_TARGET_STATUS: - status = 0; + if (cmd->err_info->CommandStatus == 0) /* no error has occurred */ + goto after_error_processing; - if (cmd->err_info->ScsiStatus == 0x02) { - printk(KERN_WARNING "cciss: cmd %p " - "has CHECK CONDITION " - " byte 2 = 0x%x\n", cmd, - cmd->err_info->SenseInfo[2] - ); - /* check the sense key */ - sense_key = 0xf & cmd->err_info->SenseInfo[2]; - /* no status or recovered error */ - if ((sense_key == 0x0) || (sense_key == 0x1)) { - status = 1; - } - } else { - printk(KERN_WARNING "cciss: cmd %p " - "has SCSI Status 0x%x\n", - cmd, cmd->err_info->ScsiStatus); - } - break; - case CMD_DATA_UNDERRUN: + switch (cmd->err_info->CommandStatus) { + case CMD_TARGET_STATUS: + rq->errors = evaluate_target_status(cmd); + break; + case CMD_DATA_UNDERRUN: + if (blk_fs_request(cmd->rq)) { printk(KERN_WARNING "cciss: cmd %p has" " completed with data underrun " "reported\n", cmd); - break; - case CMD_DATA_OVERRUN: + cmd->rq->data_len = cmd->err_info->ResidualCnt; + } + break; + case CMD_DATA_OVERRUN: + if (blk_fs_request(cmd->rq)) printk(KERN_WARNING "cciss: cmd %p has" " completed with data overrun " "reported\n", cmd); - break; - case CMD_INVALID: - printk(KERN_WARNING "cciss: cmd %p is " - "reported invalid\n", cmd); - status = 0; - break; - case CMD_PROTOCOL_ERR: - printk(KERN_WARNING "cciss: cmd %p has " - "protocol error \n", cmd); - status = 0; - break; - case CMD_HARDWARE_ERR: - printk(KERN_WARNING "cciss: cmd %p had " - " hardware error\n", cmd); - status = 0; - break; - case CMD_CONNECTION_LOST: - printk(KERN_WARNING "cciss: cmd %p had " - "connection lost\n", cmd); - status = 0; - break; - case CMD_ABORTED: - printk(KERN_WARNING "cciss: cmd %p was " - "aborted\n", cmd); - status = 0; - break; - case CMD_ABORT_FAILED: - printk(KERN_WARNING "cciss: cmd %p reports " - "abort failed\n", cmd); - status = 0; - break; - case CMD_UNSOLICITED_ABORT: - printk(KERN_WARNING "cciss%d: unsolicited " - "abort %p\n", h->ctlr, cmd); - if (cmd->retry_count < MAX_CMD_RETRIES) { - retry_cmd = 1; - printk(KERN_WARNING - "cciss%d: retrying %p\n", h->ctlr, cmd); - cmd->retry_count++; - } else - printk(KERN_WARNING - "cciss%d: %p retried too " - "many times\n", h->ctlr, cmd); - status = 0; - break; - case CMD_TIMEOUT: - printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); - status = 0; - break; - default: - printk(KERN_WARNING "cciss: cmd %p returned " - "unknown status %x\n", cmd, - cmd->err_info->CommandStatus); - status = 0; - } + break; + case CMD_INVALID: + printk(KERN_WARNING "cciss: cmd %p is " + "reported invalid\n", cmd); + rq->errors = 1; + break; + case CMD_PROTOCOL_ERR: + printk(KERN_WARNING "cciss: cmd %p has " + "protocol error \n", cmd); + rq->errors = 1; + break; + case CMD_HARDWARE_ERR: + printk(KERN_WARNING "cciss: cmd %p had " + " hardware error\n", cmd); + rq->errors = 1; + break; + case CMD_CONNECTION_LOST: + printk(KERN_WARNING "cciss: cmd %p had " + "connection lost\n", cmd); + rq->errors = 1; + break; + case CMD_ABORTED: + printk(KERN_WARNING "cciss: cmd %p was " + "aborted\n", cmd); + rq->errors = 1; + break; + case CMD_ABORT_FAILED: + printk(KERN_WARNING "cciss: cmd %p reports " + "abort failed\n", cmd); + rq->errors = 1; + break; + case CMD_UNSOLICITED_ABORT: + printk(KERN_WARNING "cciss%d: unsolicited " + "abort %p\n", h->ctlr, cmd); + if (cmd->retry_count < MAX_CMD_RETRIES) { + retry_cmd = 1; + printk(KERN_WARNING + "cciss%d: retrying %p\n", h->ctlr, cmd); + cmd->retry_count++; + } else + printk(KERN_WARNING + "cciss%d: %p retried too " + "many times\n", h->ctlr, cmd); + rq->errors = 1; + break; + case CMD_TIMEOUT: + printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); + rq->errors = 1; + break; + default: + printk(KERN_WARNING "cciss: cmd %p returned " + "unknown status %x\n", cmd, + cmd->err_info->CommandStatus); + rq->errors = 1; } + +after_error_processing: + /* We need to return this command */ if (retry_cmd) { resend_cciss_cmd(h, cmd); return; } - + cmd->rq->data_len = 0; cmd->rq->completion_data = cmd; - cmd->rq->errors = status; blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE); blk_complete_request(cmd->rq); } @@ -2491,7 +2558,7 @@ static void do_cciss_request(request_queue_t *q) c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = - (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; + (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE; c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; @@ -2528,32 +2595,40 @@ static void do_cciss_request(request_queue_t *q) #endif /* CCISS_DEBUG */ c->Header.SGList = c->Header.SGTotal = seg; - if(h->cciss_read == CCISS_READ_10) { - c->Request.CDB[1] = 0; - c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB - c->Request.CDB[3] = (start_blk >> 16) & 0xff; - c->Request.CDB[4] = (start_blk >> 8) & 0xff; - c->Request.CDB[5] = start_blk & 0xff; - c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB - c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; - c->Request.CDB[8] = creq->nr_sectors & 0xff; - c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; + if (likely(blk_fs_request(creq))) { + if(h->cciss_read == CCISS_READ_10) { + c->Request.CDB[1] = 0; + c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB + c->Request.CDB[3] = (start_blk >> 16) & 0xff; + c->Request.CDB[4] = (start_blk >> 8) & 0xff; + c->Request.CDB[5] = start_blk & 0xff; + c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB + c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff; + c->Request.CDB[8] = creq->nr_sectors & 0xff; + c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; + } else { + c->Request.CDBLen = 16; + c->Request.CDB[1]= 0; + c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB + c->Request.CDB[3]= (start_blk >> 48) & 0xff; + c->Request.CDB[4]= (start_blk >> 40) & 0xff; + c->Request.CDB[5]= (start_blk >> 32) & 0xff; + c->Request.CDB[6]= (start_blk >> 24) & 0xff; + c->Request.CDB[7]= (start_blk >> 16) & 0xff; + c->Request.CDB[8]= (start_blk >> 8) & 0xff; + c->Request.CDB[9]= start_blk & 0xff; + c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; + c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; + c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; + c->Request.CDB[13]= creq->nr_sectors & 0xff; + c->Request.CDB[14] = c->Request.CDB[15] = 0; + } + } else if (blk_pc_request(creq)) { + c->Request.CDBLen = creq->cmd_len; + memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB); } else { - c->Request.CDBLen = 16; - c->Request.CDB[1]= 0; - c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB - c->Request.CDB[3]= (start_blk >> 48) & 0xff; - c->Request.CDB[4]= (start_blk >> 40) & 0xff; - c->Request.CDB[5]= (start_blk >> 32) & 0xff; - c->Request.CDB[6]= (start_blk >> 24) & 0xff; - c->Request.CDB[7]= (start_blk >> 16) & 0xff; - c->Request.CDB[8]= (start_blk >> 8) & 0xff; - c->Request.CDB[9]= start_blk & 0xff; - c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff; - c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff; - c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff; - c->Request.CDB[13]= creq->nr_sectors & 0xff; - c->Request.CDB[14] = c->Request.CDB[15] = 0; + printk(KERN_WARNING "cciss%d: bad request type %d\n", h->ctlr, creq->cmd_type); + BUG(); } spin_lock_irq(q->queue_lock); @@ -2837,7 +2912,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) if (err) { printk(KERN_ERR "cciss: Cannot obtain PCI resources, " "aborting\n"); - goto err_out_disable_pdev; + return err; } subsystem_vendor_id = pdev->subsystem_vendor; @@ -2865,7 +2940,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) #ifdef CCISS_DEBUG printk("address 0 = %x\n", c->paddr); #endif /* CCISS_DEBUG */ - c->vaddr = remap_pci_mem(c->paddr, 200); + c->vaddr = remap_pci_mem(c->paddr, 0x250); /* Wait for the board to become ready. (PCI hotplug needs this.) * We poll for up to 120 secs, once per 100ms. */ @@ -3004,11 +3079,12 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) } return 0; - err_out_free_res: +err_out_free_res: + /* + * Deliberately omit pci_disable_device(): it does something nasty to + * Smart Array controllers that pci_enable_device does not undo + */ pci_release_regions(pdev); - - err_out_disable_pdev: - pci_disable_device(pdev); return err; } @@ -3116,8 +3192,9 @@ static void cciss_getgeometry(int cntl_num) } cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size); - /* total_size = last LBA + 1 */ - if(total_size == (__u32) 0) { + /* If read_capacity returns all F's the logical is >2TB */ + /* so we switch to 16-byte CDBs for all read/write ops */ + if(total_size == 0xFFFFFFFFULL) { cciss_read_capacity_16(cntl_num, i, 0, &total_size, &block_size); hba[cntl_num]->cciss_read = CCISS_READ_16; @@ -3382,54 +3459,63 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, if (drv->queue) blk_cleanup_queue(drv->queue); } + /* + * Deliberately omit pci_disable_device(): it does something nasty to + * Smart Array controllers that pci_enable_device does not undo + */ pci_release_regions(pdev); - pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_hba(i); return -1; } -static void __devexit cciss_remove_one(struct pci_dev *pdev) +static void cciss_shutdown(struct pci_dev *pdev) { ctlr_info_t *tmp_ptr; - int i, j; + int i; char flush_buf[4]; int return_code; - if (pci_get_drvdata(pdev) == NULL) { - printk(KERN_ERR "cciss: Unable to remove device \n"); - return; - } tmp_ptr = pci_get_drvdata(pdev); + if (tmp_ptr == NULL) + return; i = tmp_ptr->ctlr; - if (hba[i] == NULL) { - printk(KERN_ERR "cciss: device appears to " - "already be removed \n"); + if (hba[i] == NULL) return; - } + /* Turn board interrupts off and send the flush cache command */ /* sendcmd will turn off interrupt, and send the flush... * To write all data in the battery backed cache to disks */ memset(flush_buf, 0, 4); return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, TYPE_CMD); - if (return_code != IO_OK) { - printk(KERN_WARNING "Error Flushing cache on controller %d\n", - i); + if (return_code == IO_OK) { + printk(KERN_INFO "Completed flushing cache on controller %d\n", i); + } else { + printk(KERN_WARNING "Error flushing cache on controller %d\n", i); } free_irq(hba[i]->intr[2], hba[i]); +} -#ifdef CONFIG_PCI_MSI - if (hba[i]->msix_vector) - pci_disable_msix(hba[i]->pdev); - else if (hba[i]->msi_vector) - pci_disable_msi(hba[i]->pdev); -#endif /* CONFIG_PCI_MSI */ +static void __devexit cciss_remove_one(struct pci_dev *pdev) +{ + ctlr_info_t *tmp_ptr; + int i, j; + + if (pci_get_drvdata(pdev) == NULL) { + printk(KERN_ERR "cciss: Unable to remove device \n"); + return; + } + tmp_ptr = pci_get_drvdata(pdev); + i = tmp_ptr->ctlr; + if (hba[i] == NULL) { + printk(KERN_ERR "cciss: device appears to " + "already be removed \n"); + return; + } - iounmap(hba[i]->vaddr); - cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ - unregister_blkdev(hba[i]->major, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); + unregister_blkdev(hba[i]->major, hba[i]->devname); /* remove it from the disk list */ for (j = 0; j < CISS_MAX_LUN; j++) { @@ -3444,6 +3530,19 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) } } + cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ + + cciss_shutdown(pdev); + +#ifdef CONFIG_PCI_MSI + if (hba[i]->msix_vector) + pci_disable_msix(hba[i]->pdev); + else if (hba[i]->msi_vector) + pci_disable_msi(hba[i]->pdev); +#endif /* CONFIG_PCI_MSI */ + + iounmap(hba[i]->vaddr); + pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(CommandList_struct), hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle); pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(ErrorInfo_struct), @@ -3452,8 +3551,11 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) #ifdef CONFIG_CISS_SCSI_TAPE kfree(hba[i]->scsi_rejects.complete); #endif + /* + * Deliberately omit pci_disable_device(): it does something nasty to + * Smart Array controllers that pci_enable_device does not undo + */ pci_release_regions(pdev); - pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_hba(i); } @@ -3463,6 +3565,7 @@ static struct pci_driver cciss_pci_driver = { .probe = cciss_init_one, .remove = __devexit_p(cciss_remove_one), .id_table = cciss_pci_device_id, /* id_table */ + .shutdown = cciss_shutdown, }; /*