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 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; } }
void scsi_scan_host(struct Scsi_Host *host) { struct scsi_cmnd *cmnd; struct scsi_device *sdev; struct scsi_target *target; struct completion compl; void *result; init_completion(&compl); sdev = (struct scsi_device *)kmalloc(sizeof(struct scsi_device), GFP_KERNEL); target = (struct scsi_target *)kmalloc(sizeof(struct scsi_target), GFP_KERNEL); cmnd = _scsi_alloc_command(); /* init device */ sdev->sdev_target = target; sdev->host = host; sdev->id = 0; sdev->lun = 0; host->hostt->slave_alloc(sdev); host->hostt->slave_configure(sdev); /* inquiry (36 bytes for usb) */ scsi_alloc_buffer(sdev->inquiry_len, cmnd); cmnd->cmnd[0] = INQUIRY; cmnd->cmnd[4] = sdev->inquiry_len; cmnd->device = sdev; cmnd->cmd_len = 6; cmnd->sc_data_direction = DMA_FROM_DEVICE; cmnd->back = &compl; cmnd->scsi_done = inquiry_done; host->hostt->queuecommand(host, cmnd); wait_for_completion(&compl); /* if PQ and PDT are zero we have a direct access block device conntected */ result = scsi_buffer_data(cmnd); if (!((char*)result)[0]) scsi_add_device(sdev); else { kfree(sdev); kfree(target); } scsi_free_buffer(cmnd); _scsi_free_command(cmnd); }
static int tcm_loop_port_link( struct se_portal_group *se_tpg, struct se_lun *lun) { struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; atomic_inc_mb(&tl_tpg->tl_tpg_port_count); /* * Add Linux/SCSI struct scsi_device by HCTL */ scsi_add_device(tl_hba->sh, 0, tl_tpg->tl_tpgt, lun->unpacked_lun); pr_debug("TCM_Loop_ConfigFS: Port Link Successful\n"); return 0; }
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; }