}
        return (!found);        
 }
+struct scsi2map {
+       char scsi3addr[8];
+       int bus, target, lun;
+};
 
 static int 
 cciss_scsi_add_entry(int ctlr, int hostno, 
-               unsigned char *scsi3addr, int devtype)
+               unsigned char *scsi3addr, int devtype,
+               struct scsi2map *added, int *nadded)
 {
        /* assumes hba[ctlr]->scsi_ctlr->lock is held */ 
        int n = ccissscsi[ctlr].ndevices;
        sd = &ccissscsi[ctlr].dev[n];
        if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0)
                return -1;
+
+       added[*nadded].bus = sd->bus;
+       added[*nadded].target = sd->target;
+       added[*nadded].lun = sd->lun;
+       (*nadded)++;
+
        memcpy(&sd->scsi3addr[0], scsi3addr, 8);
        sd->devtype = devtype;
        ccissscsi[ctlr].ndevices++;
 }
 
 static void
-cciss_scsi_remove_entry(int ctlr, int hostno, int entry)
+cciss_scsi_remove_entry(int ctlr, int hostno, int entry,
+       struct scsi2map *removed, int *nremoved)
 {
        /* assumes hba[ctlr]->scsi_ctlr->lock is held */ 
        int i;
 
        if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return;
        sd = ccissscsi[ctlr].dev[entry];
+       removed[*nremoved].bus    = sd.bus;
+       removed[*nremoved].target = sd.target;
+       removed[*nremoved].lun    = sd.lun;
+       (*nremoved)++;
        for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++)
                ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
        ccissscsi[ctlr].ndevices--;
        (a)[1] == (b)[1] && \
        (a)[0] == (b)[0])
 
+static void fixup_botched_add(int ctlr, char *scsi3addr)
+{
+       /* called when scsi_add_device fails in order to re-adjust */
+       /* ccissscsi[] to match the mid layer's view. */
+       unsigned long flags;
+       int i, j;
+       CPQ_TAPE_LOCK(ctlr, flags);
+       for (i = 0; i < ccissscsi[ctlr].ndevices; i++) {
+               if (memcmp(scsi3addr,
+                               ccissscsi[ctlr].dev[i].scsi3addr, 8) == 0) {
+                       for (j = i; j < ccissscsi[ctlr].ndevices-1; j++)
+                               ccissscsi[ctlr].dev[j] =
+                                       ccissscsi[ctlr].dev[j+1];
+                       ccissscsi[ctlr].ndevices--;
+                       break;
+               }
+       }
+       CPQ_TAPE_UNLOCK(ctlr, flags);
+}
+
 static int
 adjust_cciss_scsi_table(int ctlr, int hostno,
        struct cciss_scsi_dev_t sd[], int nsds)
        int i,j, found, changes=0;
        struct cciss_scsi_dev_t *csd;
        unsigned long flags;
+       struct scsi2map *added, *removed;
+       int nadded, nremoved;
+       struct Scsi_Host *sh = NULL;
+
+       added = kzalloc(sizeof(*added) * CCISS_MAX_SCSI_DEVS_PER_HBA,
+                       GFP_KERNEL);
+       removed = kzalloc(sizeof(*removed) * CCISS_MAX_SCSI_DEVS_PER_HBA,
+                       GFP_KERNEL);
+
+       if (!added || !removed) {
+               printk(KERN_WARNING "cciss%d: Out of memory in "
+                       "adjust_cciss_scsi_table\n", ctlr);
+               goto free_and_out;
+       }
 
        CPQ_TAPE_LOCK(ctlr, flags);
 
+       if (hostno != -1)  /* if it's not the first time... */
+               sh = ((struct cciss_scsi_adapter_data_t *)
+                       hba[ctlr]->scsi_ctlr)->scsi_host;
+
        /* find any devices in ccissscsi[] that are not in 
           sd[] and remove them from ccissscsi[] */
 
        i = 0;
+       nremoved = 0;
+       nadded = 0;
        while(i<ccissscsi[ctlr].ndevices) {
                csd = &ccissscsi[ctlr].dev[i];
                found=0;
                        /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
                                ctlr, scsi_device_type(csd->devtype), hostno,
                                        csd->bus, csd->target, csd->lun); */
-                       cciss_scsi_remove_entry(ctlr, hostno, i);
-                       /* note, i not incremented */
+                       cciss_scsi_remove_entry(ctlr, hostno, i,
+                               removed, &nremoved);
+                       /* remove ^^^, hence i not incremented */
                } 
                else if (found == 1) { /* device is different kind */
                        changes++;
                                "(device type now %s).\n",
                                ctlr, hostno, csd->bus, csd->target, csd->lun,
                                        scsi_device_type(csd->devtype));
+                       cciss_scsi_remove_entry(ctlr, hostno, i,
+                               removed, &nremoved);
+                       /* remove ^^^, hence i not incremented */
+                       if (cciss_scsi_add_entry(ctlr, hostno,
+                               &sd[j].scsi3addr[0], sd[j].devtype,
+                               added, &nadded) != 0)
+                               /* we just removed one, so add can't fail. */
+                                       BUG();
                        csd->devtype = sd[j].devtype;
-                       i++;    /* so just move along. */
                } else          /* device is same as it ever was, */
                        i++;    /* so just move along. */
        }
                if (!found) {
                        changes++;
                        if (cciss_scsi_add_entry(ctlr, hostno, 
-                               &sd[i].scsi3addr[0], sd[i].devtype) != 0)
+
+                               &sd[i].scsi3addr[0], sd[i].devtype,
+                               added, &nadded) != 0)
                                break;
                } else if (found == 1) {
                        /* should never happen... */
        }
        CPQ_TAPE_UNLOCK(ctlr, flags);
 
-       if (!changes) 
-               printk("cciss%d: No device changes detected.\n", ctlr);
+       /* Don't notify scsi mid layer of any changes the first time through */
+       /* (or if there are no changes) scsi_scan_host will do it later the */
+       /* first time through. */
+       if (hostno == -1 || !changes)
+               goto free_and_out;
+
+       /* Notify scsi mid layer of any removed devices */
+       for (i = 0; i < nremoved; i++) {
+               struct scsi_device *sdev =
+                       scsi_device_lookup(sh, removed[i].bus,
+                               removed[i].target, removed[i].lun);
+               if (sdev != NULL) {
+                       scsi_remove_device(sdev);
+                       scsi_device_put(sdev);
+               } else {
+                       /* We don't expect to get here. */
+                       /* future cmds to this device will get selection */
+                       /* timeout as if the device was gone. */
+                       printk(KERN_WARNING "cciss%d: didn't find "
+                               "c%db%dt%dl%d\n for removal.",
+                               ctlr, hostno, removed[i].bus,
+                               removed[i].target, removed[i].lun);
+               }
+       }
+
+       /* Notify scsi mid layer of any added devices */
+       for (i = 0; i < nadded; i++) {
+               int rc;
+               rc = scsi_add_device(sh, added[i].bus,
+                       added[i].target, added[i].lun);
+               if (rc == 0)
+                       continue;
+               printk(KERN_WARNING "cciss%d: scsi_add_device "
+                       "c%db%dt%dl%d failed, device not added.\n",
+                       ctlr, hostno,
+                       added[i].bus, added[i].target, added[i].lun);
+               /* now we have to remove it from ccissscsi, */
+               /* since it didn't get added to scsi mid layer */
+               fixup_botched_add(ctlr, added[i].scsi3addr);
+       }
 
+free_and_out:
+       kfree(added);
+       kfree(removed);
        return 0;
 }
 
        kfree(sa);
 }
 
-static int 
-cciss_register_scsi(int ctlr)
-{
-       unsigned long flags;
-
-       CPQ_TAPE_LOCK(ctlr, flags);
-
-       /* Since this is really a block driver, the SCSI core may not be 
-          initialized at init time, in which case, calling scsi_register_host
-          would hang.  Instead, we do it later, via /proc filesystem
-          and rc scripts, when we know SCSI core is good to go. */
-
-       /* Only register if SCSI devices are detected. */
-       if (ccissscsi[ctlr].ndevices != 0) {
-               ((struct cciss_scsi_adapter_data_t *) 
-                       hba[ctlr]->scsi_ctlr)->registered = 1;
-               CPQ_TAPE_UNLOCK(ctlr, flags);
-               return cciss_scsi_detect(ctlr);
-       }
-       CPQ_TAPE_UNLOCK(ctlr, flags);
-       printk(KERN_INFO 
-               "cciss%d: No appropriate SCSI device detected, "
-               "SCSI subsystem not engaged.\n", ctlr);
-       return 0;
-}
-
 static int 
 cciss_engage_scsi(int ctlr)
 {
        sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
        stk = &sa->cmd_stack; 
 
-       if (((struct cciss_scsi_adapter_data_t *) 
-               hba[ctlr]->scsi_ctlr)->registered) {
+       if (sa->registered) {
                printk("cciss%d: SCSI subsystem already engaged.\n", ctlr);
                spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
                return ENXIO;
        }
+       sa->registered = 1;
        spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
        cciss_update_non_disk_devices(ctlr, -1);
-       cciss_register_scsi(ctlr);
+       cciss_scsi_detect(ctlr);
        return 0;
 }
 
 /* If no tape support, then these become defined out of existence */
 
 #define cciss_scsi_setup(cntl_num)
-#define cciss_unregister_scsi(ctlr)
-#define cciss_register_scsi(ctlr)
 
 #endif /* CONFIG_CISS_SCSI_TAPE */