static void tcm_loop_port_unlink( struct se_portal_group *se_tpg, struct se_lun *se_lun) { struct scsi_device *sd; struct tcm_loop_hba *tl_hba; struct tcm_loop_tpg *tl_tpg; tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); tl_hba = tl_tpg->tl_hba; sd = scsi_device_lookup(tl_hba->sh, 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); if (!sd) { pr_err("Unable to locate struct scsi_device for %d:%d:" "%d\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); return; } /* * Remove Linux/SCSI struct scsi_device by HCTL */ scsi_remove_device(sd); scsi_device_put(sd); atomic_dec(&tl_tpg->tl_tpg_port_count); smp_mb__after_atomic_dec(); pr_debug("TCM_Loop_ConfigFS: Port Unlink Successful\n"); }
static void channel_rescan(void *data) { struct rescan_wrapper* rescan = (struct rescan_wrapper*)data; struct Scsi_Host *host; struct scsi_device *sdev = NULL; MV_U16 target; if (rescan->pAdapter->host[rescan->channelIndex] == NULL) { kfree(rescan); return; } host = rescan->pAdapter->host[rescan->channelIndex]->scsihost; down(&rescan->pAdapter->rescan_mutex); if (atomic_read(&rescan->pAdapter->stopped) > 0) { up(&rescan->pAdapter->rescan_mutex); kfree(rescan); return; } mvLogMsg(MV_IAL_LOG_ID, MV_DEBUG, "[%d %d] channel_rescan(): " "targets to add 0x%X, targets to remove 0x%X\n", rescan->pAdapter->mvSataAdapter.adapterId, rescan->channelIndex, rescan->targetsToRemove, rescan->targetsToAdd); for (target = 0; (rescan->targetsToRemove != 0) && (target < host->max_id); target++) { if (rescan->targetsToRemove & (1 << target)) { sdev = scsi_device_lookup(host, 0, target, 0); if (sdev != NULL) { scsi_device_cancel(sdev, 0); scsi_remove_device(sdev); scsi_device_put(sdev); } } } sdev = NULL; for (target = 0; (rescan->targetsToAdd != 0) && (target < host->max_id); target++) { if (rescan->targetsToAdd & (1 << target)) { sdev = scsi_add_device(host, 0, target, 0); if (NULL == sdev) { mvLogMsg(MV_IAL_LOG_ID, MV_DEBUG_ERROR, "[%d %d %d] Error adding scsi device\n", rescan->pAdapter->mvSataAdapter.adapterId, rescan->channelIndex, target); } } } up(&rescan->pAdapter->rescan_mutex); kfree(rescan); }
static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct zfcp_port *port = dev_get_drvdata(dev); struct zfcp_unit *unit; u64 fcp_lun; LIST_HEAD(unit_remove_lh); struct scsi_device *sdev; mutex_lock(&zfcp_data.config_mutex); if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_REMOVE) { mutex_unlock(&zfcp_data.config_mutex); return -EBUSY; } if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) { mutex_unlock(&zfcp_data.config_mutex); return -EINVAL; } read_lock_irq(&zfcp_data.config_lock); unit = zfcp_get_unit_by_lun(port, fcp_lun); read_unlock_irq(&zfcp_data.config_lock); if (!unit) { mutex_unlock(&zfcp_data.config_mutex); return -ENXIO; } zfcp_unit_get(unit); mutex_unlock(&zfcp_data.config_mutex); sdev = scsi_device_lookup(port->adapter->scsi_host, 0, port->starget_id, scsilun_to_int((struct scsi_lun *)&fcp_lun)); if (sdev) { scsi_remove_device(sdev); scsi_device_put(sdev); } mutex_lock(&zfcp_data.config_mutex); zfcp_unit_put(unit); if (atomic_read(&unit->refcount)) { mutex_unlock(&zfcp_data.config_mutex); return -ENXIO; } write_lock_irq(&zfcp_data.config_lock); atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); list_move(&unit->list, &unit_remove_lh); write_unlock_irq(&zfcp_data.config_lock); mutex_unlock(&zfcp_data.config_mutex); zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); zfcp_erp_wait(unit->port->adapter); zfcp_unit_dequeue(unit); return (ssize_t)count; }
static void pvscsi_process_msg(const struct pvscsi_adapter *adapter, const struct PVSCSIRingMsgDesc *e) { struct PVSCSIRingsState *s = adapter->rings_state; struct Scsi_Host *host = adapter->host; struct scsi_device *sdev; printk(KERN_INFO "vmw_pvscsi: msg type: 0x%x - MSG RING: %u/%u (%u) \n", e->type, s->msgProdIdx, s->msgConsIdx, s->msgNumEntriesLog2); BUILD_BUG_ON(PVSCSI_MSG_LAST != 2); if (e->type == PVSCSI_MSG_DEV_ADDED) { struct PVSCSIMsgDescDevStatusChanged *desc; desc = (struct PVSCSIMsgDescDevStatusChanged *)e; printk(KERN_INFO "vmw_pvscsi: msg: device added at scsi%u:%u:%u\n", desc->bus, desc->target, desc->lun[1]); if (!scsi_host_get(host)) return; sdev = scsi_device_lookup(host, desc->bus, desc->target, desc->lun[1]); if (sdev) { printk(KERN_INFO "vmw_pvscsi: device already exists\n"); scsi_device_put(sdev); } else scsi_add_device(adapter->host, desc->bus, desc->target, desc->lun[1]); scsi_host_put(host); } else if (e->type == PVSCSI_MSG_DEV_REMOVED) { struct PVSCSIMsgDescDevStatusChanged *desc; desc = (struct PVSCSIMsgDescDevStatusChanged *)e; printk(KERN_INFO "vmw_pvscsi: msg: device removed at scsi%u:%u:%u\n", desc->bus, desc->target, desc->lun[1]); if (!scsi_host_get(host)) return; sdev = scsi_device_lookup(host, desc->bus, desc->target, desc->lun[1]); if (sdev) { scsi_remove_device(sdev); scsi_device_put(sdev); } else printk(KERN_INFO "vmw_pvscsi: failed to lookup scsi%u:%u:%u\n", desc->bus, desc->target, desc->lun[1]); scsi_host_put(host); } }
static void hba_proc_msg(struct mv_hba_msg *pmsg) { PHBA_Extension phba; struct scsi_device *psdev; /* we don't do things without pmsg->data */ if (NULL == pmsg->data) return; phba = (PHBA_Extension) pmsg->data; MV_DBG(DMSG_HBA, "__MV__ In hba_proc_msg.\n"); MV_ASSERT(pmsg); switch (pmsg->msg) { case EVENT_DEVICE_ARRIVAL: if (scsi_add_device(phba->host, 0, pmsg->param, 0)) MV_DBG(DMSG_SCSI, "__MV__ add scsi disk %d-%d-%d failed.\n", 0, pmsg->param, 0); else MV_DBG(DMSG_SCSI, "__MV__ add scsi disk %d-%d-%d.\n", 0, pmsg->param, 0); break; case EVENT_DEVICE_REMOVAL: psdev = scsi_device_lookup(phba->host, 0, pmsg->param, 0); if (NULL != psdev) { MV_DBG(DMSG_SCSI, "__MV__ remove scsi disk %d-%d-%d.\n", 0, pmsg->param, 0); scsi_remove_device(psdev); scsi_device_put(psdev); } else { MV_DBG(DMSG_SCSI, "__MV__ no disk to remove %d-%d-%d\n", 0, pmsg->param, 0); } break; case EVENT_HOT_PLUG: sata_hotplug(pmsg->data, pmsg->param); break; default: break; } }
/** * scsi_remove_single_device - Respond to user request to remove a device * @host: user-supplied decimal integer * @channel: user-supplied decimal integer * @id: user-supplied decimal integer * @lun: user-supplied decimal integer * * Description: called by writing "scsi remove-single-device" to * /proc/scsi/scsi. Does a scsi_device_lookup() and scsi_remove_device() */ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) { struct scsi_device *sdev; struct Scsi_Host *shost; int error = -ENXIO; shost = scsi_host_lookup(host); if (IS_ERR(shost)) return PTR_ERR(shost); sdev = scsi_device_lookup(shost, channel, id, lun); if (sdev) { scsi_remove_device(sdev); scsi_device_put(sdev); error = 0; } scsi_host_put(shost); return error; }
static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); struct zfcp_unit *unit; u64 fcp_lun; int retval = -EINVAL; struct scsi_device *sdev; if (!(port && get_device(&port->dev))) return -EBUSY; if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun)) goto out; unit = zfcp_get_unit_by_lun(port, fcp_lun); if (!unit) goto out; else retval = 0; sdev = scsi_device_lookup(port->adapter->scsi_host, 0, port->starget_id, scsilun_to_int((struct scsi_lun *)&fcp_lun)); if (sdev) { scsi_remove_device(sdev); scsi_device_put(sdev); } write_lock_irq(&port->unit_list_lock); list_del(&unit->list); write_unlock_irq(&port->unit_list_lock); put_device(&unit->dev); zfcp_erp_unit_shutdown(unit, 0, "syurs_1", NULL); zfcp_device_unregister(&unit->dev, &zfcp_sysfs_unit_attrs); out: put_device(&port->dev); return retval ? retval : (ssize_t) count; }
static void scsifront_free(struct vscsifrnt_info *info) { struct Scsi_Host *host = info->host; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) if (host->shost_state != SHOST_DEL) { #else if (!test_bit(SHOST_DEL, &host->shost_state)) { #endif scsi_remove_host(info->host); } if (info->ring_ref != GRANT_INVALID_REF) { gnttab_end_foreign_access(info->ring_ref, (unsigned long)info->ring.sring); info->ring_ref = GRANT_INVALID_REF; info->ring.sring = NULL; } if (info->irq) unbind_from_irqhandler(info->irq, info); info->irq = 0; scsi_host_put(info->host); } static int scsifront_alloc_ring(struct vscsifrnt_info *info) { struct xenbus_device *dev = info->dev; struct vscsiif_sring *sring; int err = -ENOMEM; info->ring_ref = GRANT_INVALID_REF; /***** Frontend to Backend ring start *****/ sring = (struct vscsiif_sring *) __get_free_page(GFP_KERNEL); if (!sring) { xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Front to Back)"); return err; } SHARED_RING_INIT(sring); FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); err = xenbus_grant_ring(dev, virt_to_mfn(sring)); if (err < 0) { free_page((unsigned long) sring); info->ring.sring = NULL; xenbus_dev_fatal(dev, err, "fail to grant shared ring (Front to Back)"); goto free_sring; } info->ring_ref = err; err = bind_listening_port_to_irqhandler( dev->otherend_id, scsifront_intr, SA_SAMPLE_RANDOM, "scsifront", info); if (err <= 0) { xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler"); goto free_sring; } info->irq = err; return 0; /* free resource */ free_sring: scsifront_free(info); return err; } static int scsifront_init_ring(struct vscsifrnt_info *info) { struct xenbus_device *dev = info->dev; struct xenbus_transaction xbt; int err; DPRINTK("%s\n",__FUNCTION__); err = scsifront_alloc_ring(info); if (err) return err; DPRINTK("%u %u\n", info->ring_ref, info->evtchn); again: err = xenbus_transaction_start(&xbt); if (err) { xenbus_dev_fatal(dev, err, "starting transaction"); } err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u", info->ring_ref); if (err) { xenbus_dev_fatal(dev, err, "%s", "writing ring-ref"); goto fail; } err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", irq_to_evtchn_port(info->irq)); if (err) { xenbus_dev_fatal(dev, err, "%s", "writing event-channel"); goto fail; } err = xenbus_transaction_end(xbt, 0); if (err) { if (err == -EAGAIN) goto again; xenbus_dev_fatal(dev, err, "completing transaction"); goto free_sring; } return 0; fail: xenbus_transaction_end(xbt, 1); free_sring: /* free resource */ scsifront_free(info); return err; } static int scsifront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { struct vscsifrnt_info *info; struct Scsi_Host *host; int i, err = -ENOMEM; char name[DEFAULT_TASK_COMM_LEN]; host = scsi_host_alloc(&scsifront_sht, sizeof(*info)); if (!host) { xenbus_dev_fatal(dev, err, "fail to allocate scsi host"); return err; } info = (struct vscsifrnt_info *) host->hostdata; info->host = host; dev->dev.driver_data = info; info->dev = dev; for (i = 0; i < VSCSIIF_MAX_REQS; i++) { info->shadow[i].next_free = i + 1; init_waitqueue_head(&(info->shadow[i].wq_reset)); info->shadow[i].wait_reset = 0; } info->shadow[VSCSIIF_MAX_REQS - 1].next_free = 0x0fff; err = scsifront_init_ring(info); if (err) { scsi_host_put(host); return err; } init_waitqueue_head(&info->wq); spin_lock_init(&info->io_lock); spin_lock_init(&info->shadow_lock); snprintf(name, DEFAULT_TASK_COMM_LEN, "vscsiif.%d", info->host->host_no); info->kthread = kthread_run(scsifront_schedule, info, name); if (IS_ERR(info->kthread)) { err = PTR_ERR(info->kthread); info->kthread = NULL; printk(KERN_ERR "scsifront: kthread start err %d\n", err); goto free_sring; } host->max_id = VSCSIIF_MAX_TARGET; host->max_channel = 0; host->max_lun = VSCSIIF_MAX_LUN; host->max_sectors = (VSCSIIF_SG_TABLESIZE - 1) * PAGE_SIZE / 512; err = scsi_add_host(host, &dev->dev); if (err) { printk(KERN_ERR "scsifront: fail to add scsi host %d\n", err); goto free_sring; } xenbus_switch_state(dev, XenbusStateInitialised); return 0; free_sring: /* free resource */ scsifront_free(info); return err; } static int scsifront_remove(struct xenbus_device *dev) { struct vscsifrnt_info *info = dev->dev.driver_data; DPRINTK("%s: %s removed\n",__FUNCTION__ ,dev->nodename); if (info->kthread) { kthread_stop(info->kthread); info->kthread = NULL; } scsifront_free(info); return 0; } static int scsifront_disconnect(struct vscsifrnt_info *info) { struct xenbus_device *dev = info->dev; struct Scsi_Host *host = info->host; DPRINTK("%s: %s disconnect\n",__FUNCTION__ ,dev->nodename); /* When this function is executed, all devices of Frontend have been deleted. Therefore, it need not block I/O before remove_host. */ scsi_remove_host(host); xenbus_frontend_closed(dev); return 0; } #define VSCSIFRONT_OP_ADD_LUN 1 #define VSCSIFRONT_OP_DEL_LUN 2 static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) { struct xenbus_device *dev = info->dev; int i, err = 0; char str[64], state_str[64]; char **dir; unsigned int dir_n = 0; unsigned int device_state; unsigned int hst, chn, tgt, lun; struct scsi_device *sdev; dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n); if (IS_ERR(dir)) return; for (i = 0; i < dir_n; i++) { /* read status */ snprintf(str, sizeof(str), "vscsi-devs/%s/state", dir[i]); err = xenbus_scanf(XBT_NIL, dev->otherend, str, "%u", &device_state); if (XENBUS_EXIST_ERR(err)) continue; /* virtual SCSI device */ snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]); err = xenbus_scanf(XBT_NIL, dev->otherend, str, "%u:%u:%u:%u", &hst, &chn, &tgt, &lun); if (XENBUS_EXIST_ERR(err)) continue; /* front device state path */ snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]); switch (op) { case VSCSIFRONT_OP_ADD_LUN: if (device_state == XenbusStateInitialised) { sdev = scsi_device_lookup(info->host, chn, tgt, lun); if (sdev) { printk(KERN_ERR "scsifront: Device already in use.\n"); scsi_device_put(sdev); xenbus_printf(XBT_NIL, dev->nodename, state_str, "%d", XenbusStateClosed); } else { scsi_add_device(info->host, chn, tgt, lun); xenbus_printf(XBT_NIL, dev->nodename, state_str, "%d", XenbusStateConnected); } } break; case VSCSIFRONT_OP_DEL_LUN: if (device_state == XenbusStateClosing) { sdev = scsi_device_lookup(info->host, chn, tgt, lun); if (sdev) { scsi_remove_device(sdev); scsi_device_put(sdev); xenbus_printf(XBT_NIL, dev->nodename, state_str, "%d", XenbusStateClosed); } } break; default: break; } } kfree(dir); return; } static void scsifront_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct vscsifrnt_info *info = dev->dev.driver_data; DPRINTK("%p %u %u\n", dev, dev->state, backend_state); switch (backend_state) { case XenbusStateUnknown: case XenbusStateInitialising: case XenbusStateInitWait: case XenbusStateClosed: break; case XenbusStateInitialised: break; case XenbusStateConnected: if (xenbus_read_driver_state(dev->nodename) == XenbusStateInitialised) { scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN); } if (dev->state == XenbusStateConnected) break; xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateClosing: scsifront_disconnect(info); break; case XenbusStateReconfiguring: scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_DEL_LUN); xenbus_switch_state(dev, XenbusStateReconfiguring); break; case XenbusStateReconfigured: scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN); xenbus_switch_state(dev, XenbusStateConnected); break; } } static struct xenbus_device_id scsifront_ids[] = { { "vscsi" }, { "" } }; MODULE_ALIAS("xen:vscsi"); static struct xenbus_driver scsifront_driver = { .name = "vscsi", .owner = THIS_MODULE, .ids = scsifront_ids, .probe = scsifront_probe, .remove = scsifront_remove, /* .resume = scsifront_resume, */ .otherend_changed = scsifront_backend_changed, }; int scsifront_xenbus_init(void) { return xenbus_register_frontend(&scsifront_driver); } void scsifront_xenbus_unregister(void) { xenbus_unregister_driver(&scsifront_driver); }
static int adjust_cciss_scsi_table(ctlr_info_t *h, int hostno, struct cciss_scsi_dev_t sd[], int nsds) { /* sd contains scsi3 addresses and devtypes, but bus target and lun are not filled in. This funciton takes what's in sd to be the current and adjusts ccissscsi[] to be in line with what's in sd. */ 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) { dev_warn(&h->pdev->dev, "Out of memory in adjust_cciss_scsi_table\n"); goto free_and_out; } CPQ_TAPE_LOCK(h, flags); if (hostno != -1) /* if it's not the first time... */ sh = h->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[h->ctlr].ndevices) { csd = &ccissscsi[h->ctlr].dev[i]; found=0; for (j=0;j<nsds;j++) { if (SCSI3ADDR_EQ(sd[j].scsi3addr, csd->scsi3addr)) { if (device_is_the_same(&sd[j], csd)) found=2; else found=1; break; } } if (found == 0) { /* device no longer present. */ changes++; cciss_scsi_remove_entry(h, hostno, i, removed, &nremoved); /* remove ^^^, hence i not incremented */ } else if (found == 1) { /* device is different in some way */ changes++; dev_info(&h->pdev->dev, "device c%db%dt%dl%d has changed.\n", hostno, csd->bus, csd->target, csd->lun); cciss_scsi_remove_entry(h, hostno, i, removed, &nremoved); /* remove ^^^, hence i not incremented */ if (cciss_scsi_add_entry(h, hostno, &sd[j], added, &nadded) != 0) /* we just removed one, so add can't fail. */ BUG(); csd->devtype = sd[j].devtype; memcpy(csd->device_id, sd[j].device_id, sizeof(csd->device_id)); memcpy(csd->vendor, sd[j].vendor, sizeof(csd->vendor)); memcpy(csd->model, sd[j].model, sizeof(csd->model)); memcpy(csd->revision, sd[j].revision, sizeof(csd->revision)); } else /* device is same as it ever was, */ i++; /* so just move along. */ } /* Now, make sure every device listed in sd[] is also listed in ccissscsi[], adding them if they aren't found */ for (i=0;i<nsds;i++) { found=0; for (j = 0; j < ccissscsi[h->ctlr].ndevices; j++) { csd = &ccissscsi[h->ctlr].dev[j]; if (SCSI3ADDR_EQ(sd[i].scsi3addr, csd->scsi3addr)) { if (device_is_the_same(&sd[i], csd)) found=2; /* found device */ else found=1; /* found a bug. */ break; } } if (!found) { changes++; if (cciss_scsi_add_entry(h, hostno, &sd[i], added, &nadded) != 0) break; } else if (found == 1) { /* should never happen... */ changes++; dev_warn(&h->pdev->dev, "device unexpectedly changed\n"); /* but if it does happen, we just ignore that device */ } } CPQ_TAPE_UNLOCK(h, flags); /* 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. */ dev_warn(&h->pdev->dev, "didn't find " "c%db%dt%dl%d\n for removal.", 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; dev_warn(&h->pdev->dev, "scsi_add_device " "c%db%dt%dl%d failed, device not added.\n", 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(h, added[i].scsi3addr); } free_and_out: kfree(added); kfree(removed); return 0; }