diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/libata-scsi.c | 8 | ||||
-rw-r--r-- | drivers/char/drm/radeon_cp.c | 5 | ||||
-rw-r--r-- | drivers/char/drm/radeon_drv.h | 1 | ||||
-rw-r--r-- | drivers/char/drm/sis_mm.c | 1 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 9 | ||||
-rw-r--r-- | drivers/s390/cio/cmf.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 2 | ||||
-rw-r--r-- | drivers/s390/net/smsgiucv.c | 4 | ||||
-rw-r--r-- | drivers/scsi/ibmvscsi/ibmvscsi.c | 19 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 5 | ||||
-rw-r--r-- | drivers/scsi/osst.c | 6 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 136 | ||||
-rw-r--r-- | drivers/scsi/scsi_scan.c | 3 | ||||
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 47 |
14 files changed, 231 insertions, 19 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 245057df69d6..94144ed50a6b 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -841,6 +841,9 @@ static void ata_scsi_dev_config(struct scsi_device *sdev, | |||
841 | blk_queue_max_hw_segments(q, q->max_hw_segments - 1); | 841 | blk_queue_max_hw_segments(q, q->max_hw_segments - 1); |
842 | } | 842 | } |
843 | 843 | ||
844 | if (dev->flags & ATA_DFLAG_AN) | ||
845 | set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events); | ||
846 | |||
844 | if (dev->flags & ATA_DFLAG_NCQ) { | 847 | if (dev->flags & ATA_DFLAG_NCQ) { |
845 | int depth; | 848 | int depth; |
846 | 849 | ||
@@ -3296,10 +3299,9 @@ static void ata_scsi_handle_link_detach(struct ata_link *link) | |||
3296 | */ | 3299 | */ |
3297 | void ata_scsi_media_change_notify(struct ata_device *dev) | 3300 | void ata_scsi_media_change_notify(struct ata_device *dev) |
3298 | { | 3301 | { |
3299 | #ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED | ||
3300 | if (dev->sdev) | 3302 | if (dev->sdev) |
3301 | scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE); | 3303 | sdev_evt_send_simple(dev->sdev, SDEV_EVT_MEDIA_CHANGE, |
3302 | #endif | 3304 | GFP_ATOMIC); |
3303 | } | 3305 | } |
3304 | 3306 | ||
3305 | /** | 3307 | /** |
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 335423c5c186..24fca8ec1379 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c | |||
@@ -1679,7 +1679,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) | |||
1679 | dev_priv->gart_info.bus_addr = | 1679 | dev_priv->gart_info.bus_addr = |
1680 | dev_priv->pcigart_offset + dev_priv->fb_location; | 1680 | dev_priv->pcigart_offset + dev_priv->fb_location; |
1681 | dev_priv->gart_info.mapping.offset = | 1681 | dev_priv->gart_info.mapping.offset = |
1682 | dev_priv->gart_info.bus_addr; | 1682 | dev_priv->pcigart_offset + dev_priv->fb_aper_offset; |
1683 | dev_priv->gart_info.mapping.size = | 1683 | dev_priv->gart_info.mapping.size = |
1684 | dev_priv->gart_info.table_size; | 1684 | dev_priv->gart_info.table_size; |
1685 | 1685 | ||
@@ -2275,7 +2275,8 @@ int radeon_driver_firstopen(struct drm_device *dev) | |||
2275 | if (ret != 0) | 2275 | if (ret != 0) |
2276 | return ret; | 2276 | return ret; |
2277 | 2277 | ||
2278 | ret = drm_addmap(dev, drm_get_resource_start(dev, 0), | 2278 | dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0); |
2279 | ret = drm_addmap(dev, dev_priv->fb_aper_offset, | ||
2279 | drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER, | 2280 | drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER, |
2280 | _DRM_WRITE_COMBINING, &map); | 2281 | _DRM_WRITE_COMBINING, &map); |
2281 | if (ret != 0) | 2282 | if (ret != 0) |
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index e4077bc212b3..bfbb60a9298c 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h | |||
@@ -293,6 +293,7 @@ typedef struct drm_radeon_private { | |||
293 | 293 | ||
294 | /* starting from here on, data is preserved accross an open */ | 294 | /* starting from here on, data is preserved accross an open */ |
295 | uint32_t flags; /* see radeon_chip_flags */ | 295 | uint32_t flags; /* see radeon_chip_flags */ |
296 | unsigned long fb_aper_offset; | ||
296 | } drm_radeon_private_t; | 297 | } drm_radeon_private_t; |
297 | 298 | ||
298 | typedef struct drm_radeon_buf_priv { | 299 | typedef struct drm_radeon_buf_priv { |
diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c index 6be1c5757580..a6b7ccdaf73d 100644 --- a/drivers/char/drm/sis_mm.c +++ b/drivers/char/drm/sis_mm.c | |||
@@ -134,6 +134,7 @@ static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file_priv, | |||
134 | dev_priv->agp_initialized)) { | 134 | dev_priv->agp_initialized)) { |
135 | DRM_ERROR | 135 | DRM_ERROR |
136 | ("Attempt to allocate from uninitialized memory manager.\n"); | 136 | ("Attempt to allocate from uninitialized memory manager.\n"); |
137 | mutex_unlock(&dev->struct_mutex); | ||
137 | return -EINVAL; | 138 | return -EINVAL; |
138 | } | 139 | } |
139 | 140 | ||
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 859f870552e3..5e083d1f57e7 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -193,6 +193,12 @@ dcssblk_segment_warn(int rc, char* seg_name) | |||
193 | } | 193 | } |
194 | } | 194 | } |
195 | 195 | ||
196 | static void dcssblk_unregister_callback(struct device *dev) | ||
197 | { | ||
198 | device_unregister(dev); | ||
199 | put_device(dev); | ||
200 | } | ||
201 | |||
196 | /* | 202 | /* |
197 | * device attribute for switching shared/nonshared (exclusive) | 203 | * device attribute for switching shared/nonshared (exclusive) |
198 | * operation (show + store) | 204 | * operation (show + store) |
@@ -276,8 +282,7 @@ removeseg: | |||
276 | blk_cleanup_queue(dev_info->dcssblk_queue); | 282 | blk_cleanup_queue(dev_info->dcssblk_queue); |
277 | dev_info->gd->queue = NULL; | 283 | dev_info->gd->queue = NULL; |
278 | put_disk(dev_info->gd); | 284 | put_disk(dev_info->gd); |
279 | device_unregister(dev); | 285 | rc = device_schedule_callback(dev, dcssblk_unregister_callback); |
280 | put_device(dev); | ||
281 | out: | 286 | out: |
282 | up_write(&dcssblk_devices_sem); | 287 | up_write(&dcssblk_devices_sem); |
283 | return rc; | 288 | return rc; |
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 725b0dd14269..f4c132ab39ed 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c | |||
@@ -343,10 +343,10 @@ static int cmf_copy_block(struct ccw_device *cdev) | |||
343 | 343 | ||
344 | if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) { | 344 | if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) { |
345 | /* Don't copy if a start function is in progress. */ | 345 | /* Don't copy if a start function is in progress. */ |
346 | if ((!sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED) && | 346 | if ((!(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED)) && |
347 | (sch->schib.scsw.actl & | 347 | (sch->schib.scsw.actl & |
348 | (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) && | 348 | (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) && |
349 | (!sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) | 349 | (!(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS))) |
350 | return -EBUSY; | 350 | return -EBUSY; |
351 | } | 351 | } |
352 | cmb_data = cdev->private->cmb; | 352 | cmb_data = cdev->private->cmb; |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 7ee57f084a89..74f6b539974a 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -738,7 +738,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, | |||
738 | atomic_set(&cdev->private->onoff, 0); | 738 | atomic_set(&cdev->private->onoff, 0); |
739 | cdev->dev.parent = &sch->dev; | 739 | cdev->dev.parent = &sch->dev; |
740 | cdev->dev.release = ccw_device_release; | 740 | cdev->dev.release = ccw_device_release; |
741 | INIT_LIST_HEAD(&cdev->private->kick_work.entry); | 741 | INIT_WORK(&cdev->private->kick_work, NULL); |
742 | cdev->dev.groups = ccwdev_attr_groups; | 742 | cdev->dev.groups = ccwdev_attr_groups; |
743 | /* Do first half of device_register. */ | 743 | /* Do first half of device_register. */ |
744 | device_initialize(&cdev->dev); | 744 | device_initialize(&cdev->dev); |
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 3ccca5871fdf..47bb47b48581 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c | |||
@@ -148,6 +148,10 @@ static int __init smsg_init(void) | |||
148 | { | 148 | { |
149 | int rc; | 149 | int rc; |
150 | 150 | ||
151 | if (!MACHINE_IS_VM) { | ||
152 | rc = -EPROTONOSUPPORT; | ||
153 | goto out; | ||
154 | } | ||
151 | rc = driver_register(&smsg_driver); | 155 | rc = driver_register(&smsg_driver); |
152 | if (rc != 0) | 156 | if (rc != 0) |
153 | goto out; | 157 | goto out; |
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 22d91ee173c5..5f2396c03958 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c | |||
@@ -556,7 +556,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, | |||
556 | unsigned long timeout) | 556 | unsigned long timeout) |
557 | { | 557 | { |
558 | u64 *crq_as_u64 = (u64 *) &evt_struct->crq; | 558 | u64 *crq_as_u64 = (u64 *) &evt_struct->crq; |
559 | int request_status; | 559 | int request_status = 0; |
560 | int rc; | 560 | int rc; |
561 | 561 | ||
562 | /* If we have exhausted our request limit, just fail this request, | 562 | /* If we have exhausted our request limit, just fail this request, |
@@ -574,6 +574,13 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, | |||
574 | if (request_status < -1) | 574 | if (request_status < -1) |
575 | goto send_error; | 575 | goto send_error; |
576 | /* Otherwise, we may have run out of requests. */ | 576 | /* Otherwise, we may have run out of requests. */ |
577 | /* If request limit was 0 when we started the adapter is in the | ||
578 | * process of performing a login with the server adapter, or | ||
579 | * we may have run out of requests. | ||
580 | */ | ||
581 | else if (request_status == -1 && | ||
582 | evt_struct->iu.srp.login_req.opcode != SRP_LOGIN_REQ) | ||
583 | goto send_busy; | ||
577 | /* Abort and reset calls should make it through. | 584 | /* Abort and reset calls should make it through. |
578 | * Nothing except abort and reset should use the last two | 585 | * Nothing except abort and reset should use the last two |
579 | * slots unless we had two or less to begin with. | 586 | * slots unless we had two or less to begin with. |
@@ -633,7 +640,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, | |||
633 | unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); | 640 | unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); |
634 | 641 | ||
635 | free_event_struct(&hostdata->pool, evt_struct); | 642 | free_event_struct(&hostdata->pool, evt_struct); |
636 | atomic_inc(&hostdata->request_limit); | 643 | if (request_status != -1) |
644 | atomic_inc(&hostdata->request_limit); | ||
637 | return SCSI_MLQUEUE_HOST_BUSY; | 645 | return SCSI_MLQUEUE_HOST_BUSY; |
638 | 646 | ||
639 | send_error: | 647 | send_error: |
@@ -927,10 +935,11 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata) | |||
927 | login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT; | 935 | login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT; |
928 | 936 | ||
929 | spin_lock_irqsave(hostdata->host->host_lock, flags); | 937 | spin_lock_irqsave(hostdata->host->host_lock, flags); |
930 | /* Start out with a request limit of 1, since this is negotiated in | 938 | /* Start out with a request limit of 0, since this is negotiated in |
931 | * the login request we are just sending | 939 | * the login request we are just sending and login requests always |
940 | * get sent by the driver regardless of request_limit. | ||
932 | */ | 941 | */ |
933 | atomic_set(&hostdata->request_limit, 1); | 942 | atomic_set(&hostdata->request_limit, 0); |
934 | 943 | ||
935 | rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2); | 944 | rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2); |
936 | spin_unlock_irqrestore(hostdata->host->host_lock, flags); | 945 | spin_unlock_irqrestore(hostdata->host->host_lock, flags); |
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c0755565fae9..4e46045dea6d 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -682,6 +682,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, | |||
682 | IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; | 682 | IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; |
683 | struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); | 683 | struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); |
684 | int datadir = scsi_cmnd->sc_data_direction; | 684 | int datadir = scsi_cmnd->sc_data_direction; |
685 | char tag[2]; | ||
685 | 686 | ||
686 | lpfc_cmd->fcp_rsp->rspSnsLen = 0; | 687 | lpfc_cmd->fcp_rsp->rspSnsLen = 0; |
687 | /* clear task management bits */ | 688 | /* clear task management bits */ |
@@ -692,8 +693,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, | |||
692 | 693 | ||
693 | memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16); | 694 | memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16); |
694 | 695 | ||
695 | if (scsi_cmnd->device->tagged_supported) { | 696 | if (scsi_populate_tag_msg(scsi_cmnd, tag)) { |
696 | switch (scsi_cmnd->tag) { | 697 | switch (tag[0]) { |
697 | case HEAD_OF_QUEUE_TAG: | 698 | case HEAD_OF_QUEUE_TAG: |
698 | fcp_cmnd->fcpCntl1 = HEAD_OF_Q; | 699 | fcp_cmnd->fcpCntl1 = HEAD_OF_Q; |
699 | break; | 700 | break; |
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 4652ad22516b..abef7048f25b 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c | |||
@@ -593,10 +593,11 @@ static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int q | |||
593 | if (aux->frame_type != OS_FRAME_TYPE_DATA && | 593 | if (aux->frame_type != OS_FRAME_TYPE_DATA && |
594 | aux->frame_type != OS_FRAME_TYPE_EOD && | 594 | aux->frame_type != OS_FRAME_TYPE_EOD && |
595 | aux->frame_type != OS_FRAME_TYPE_MARKER) { | 595 | aux->frame_type != OS_FRAME_TYPE_MARKER) { |
596 | if (!quiet) | 596 | if (!quiet) { |
597 | #if DEBUG | 597 | #if DEBUG |
598 | printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type); | 598 | printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type); |
599 | #endif | 599 | #endif |
600 | } | ||
600 | goto err_out; | 601 | goto err_out; |
601 | } | 602 | } |
602 | if (aux->frame_type == OS_FRAME_TYPE_EOD && | 603 | if (aux->frame_type == OS_FRAME_TYPE_EOD && |
@@ -606,11 +607,12 @@ static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int q | |||
606 | goto err_out; | 607 | goto err_out; |
607 | } | 608 | } |
608 | if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) { | 609 | if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) { |
609 | if (!quiet) | 610 | if (!quiet) { |
610 | #if DEBUG | 611 | #if DEBUG |
611 | printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", | 612 | printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", |
612 | name, ntohl(aux->frame_seq_num), frame_seq_number); | 613 | name, ntohl(aux->frame_seq_num), frame_seq_number); |
613 | #endif | 614 | #endif |
615 | } | ||
614 | goto err_out; | 616 | goto err_out; |
615 | } | 617 | } |
616 | if (aux->frame_type == OS_FRAME_TYPE_MARKER) { | 618 | if (aux->frame_type == OS_FRAME_TYPE_MARKER) { |
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 88de771d3569..0e81e4cf8876 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -2115,6 +2115,142 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) | |||
2115 | EXPORT_SYMBOL(scsi_device_set_state); | 2115 | EXPORT_SYMBOL(scsi_device_set_state); |
2116 | 2116 | ||
2117 | /** | 2117 | /** |
2118 | * sdev_evt_emit - emit a single SCSI device uevent | ||
2119 | * @sdev: associated SCSI device | ||
2120 | * @evt: event to emit | ||
2121 | * | ||
2122 | * Send a single uevent (scsi_event) to the associated scsi_device. | ||
2123 | */ | ||
2124 | static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt) | ||
2125 | { | ||
2126 | int idx = 0; | ||
2127 | char *envp[3]; | ||
2128 | |||
2129 | switch (evt->evt_type) { | ||
2130 | case SDEV_EVT_MEDIA_CHANGE: | ||
2131 | envp[idx++] = "SDEV_MEDIA_CHANGE=1"; | ||
2132 | break; | ||
2133 | |||
2134 | default: | ||
2135 | /* do nothing */ | ||
2136 | break; | ||
2137 | } | ||
2138 | |||
2139 | envp[idx++] = NULL; | ||
2140 | |||
2141 | kobject_uevent_env(&sdev->sdev_gendev.kobj, KOBJ_CHANGE, envp); | ||
2142 | } | ||
2143 | |||
2144 | /** | ||
2145 | * sdev_evt_thread - send a uevent for each scsi event | ||
2146 | * @work: work struct for scsi_device | ||
2147 | * | ||
2148 | * Dispatch queued events to their associated scsi_device kobjects | ||
2149 | * as uevents. | ||
2150 | */ | ||
2151 | void scsi_evt_thread(struct work_struct *work) | ||
2152 | { | ||
2153 | struct scsi_device *sdev; | ||
2154 | LIST_HEAD(event_list); | ||
2155 | |||
2156 | sdev = container_of(work, struct scsi_device, event_work); | ||
2157 | |||
2158 | while (1) { | ||
2159 | struct scsi_event *evt; | ||
2160 | struct list_head *this, *tmp; | ||
2161 | unsigned long flags; | ||
2162 | |||
2163 | spin_lock_irqsave(&sdev->list_lock, flags); | ||
2164 | list_splice_init(&sdev->event_list, &event_list); | ||
2165 | spin_unlock_irqrestore(&sdev->list_lock, flags); | ||
2166 | |||
2167 | if (list_empty(&event_list)) | ||
2168 | break; | ||
2169 | |||
2170 | list_for_each_safe(this, tmp, &event_list) { | ||
2171 | evt = list_entry(this, struct scsi_event, node); | ||
2172 | list_del(&evt->node); | ||
2173 | scsi_evt_emit(sdev, evt); | ||
2174 | kfree(evt); | ||
2175 | } | ||
2176 | } | ||
2177 | } | ||
2178 | |||
2179 | /** | ||
2180 | * sdev_evt_send - send asserted event to uevent thread | ||
2181 | * @sdev: scsi_device event occurred on | ||
2182 | * @evt: event to send | ||
2183 | * | ||
2184 | * Assert scsi device event asynchronously. | ||
2185 | */ | ||
2186 | void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt) | ||
2187 | { | ||
2188 | unsigned long flags; | ||
2189 | |||
2190 | if (!test_bit(evt->evt_type, sdev->supported_events)) { | ||
2191 | kfree(evt); | ||
2192 | return; | ||
2193 | } | ||
2194 | |||
2195 | spin_lock_irqsave(&sdev->list_lock, flags); | ||
2196 | list_add_tail(&evt->node, &sdev->event_list); | ||
2197 | schedule_work(&sdev->event_work); | ||
2198 | spin_unlock_irqrestore(&sdev->list_lock, flags); | ||
2199 | } | ||
2200 | EXPORT_SYMBOL_GPL(sdev_evt_send); | ||
2201 | |||
2202 | /** | ||
2203 | * sdev_evt_alloc - allocate a new scsi event | ||
2204 | * @evt_type: type of event to allocate | ||
2205 | * @gfpflags: GFP flags for allocation | ||
2206 | * | ||
2207 | * Allocates and returns a new scsi_event. | ||
2208 | */ | ||
2209 | struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, | ||
2210 | gfp_t gfpflags) | ||
2211 | { | ||
2212 | struct scsi_event *evt = kzalloc(sizeof(struct scsi_event), gfpflags); | ||
2213 | if (!evt) | ||
2214 | return NULL; | ||
2215 | |||
2216 | evt->evt_type = evt_type; | ||
2217 | INIT_LIST_HEAD(&evt->node); | ||
2218 | |||
2219 | /* evt_type-specific initialization, if any */ | ||
2220 | switch (evt_type) { | ||
2221 | case SDEV_EVT_MEDIA_CHANGE: | ||
2222 | default: | ||
2223 | /* do nothing */ | ||
2224 | break; | ||
2225 | } | ||
2226 | |||
2227 | return evt; | ||
2228 | } | ||
2229 | EXPORT_SYMBOL_GPL(sdev_evt_alloc); | ||
2230 | |||
2231 | /** | ||
2232 | * sdev_evt_send_simple - send asserted event to uevent thread | ||
2233 | * @sdev: scsi_device event occurred on | ||
2234 | * @evt_type: type of event to send | ||
2235 | * @gfpflags: GFP flags for allocation | ||
2236 | * | ||
2237 | * Assert scsi device event asynchronously, given an event type. | ||
2238 | */ | ||
2239 | void sdev_evt_send_simple(struct scsi_device *sdev, | ||
2240 | enum scsi_device_event evt_type, gfp_t gfpflags) | ||
2241 | { | ||
2242 | struct scsi_event *evt = sdev_evt_alloc(evt_type, gfpflags); | ||
2243 | if (!evt) { | ||
2244 | sdev_printk(KERN_ERR, sdev, "event %d eaten due to OOM\n", | ||
2245 | evt_type); | ||
2246 | return; | ||
2247 | } | ||
2248 | |||
2249 | sdev_evt_send(sdev, evt); | ||
2250 | } | ||
2251 | EXPORT_SYMBOL_GPL(sdev_evt_send_simple); | ||
2252 | |||
2253 | /** | ||
2118 | * scsi_device_quiesce - Block user issued commands. | 2254 | * scsi_device_quiesce - Block user issued commands. |
2119 | * @sdev: scsi device to quiesce. | 2255 | * @sdev: scsi device to quiesce. |
2120 | * | 2256 | * |
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b53c5f67e372..40ea71cd2ca6 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -236,6 +236,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, | |||
236 | struct scsi_device *sdev; | 236 | struct scsi_device *sdev; |
237 | int display_failure_msg = 1, ret; | 237 | int display_failure_msg = 1, ret; |
238 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 238 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
239 | extern void scsi_evt_thread(struct work_struct *work); | ||
239 | 240 | ||
240 | sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size, | 241 | sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size, |
241 | GFP_ATOMIC); | 242 | GFP_ATOMIC); |
@@ -254,7 +255,9 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, | |||
254 | INIT_LIST_HEAD(&sdev->same_target_siblings); | 255 | INIT_LIST_HEAD(&sdev->same_target_siblings); |
255 | INIT_LIST_HEAD(&sdev->cmd_list); | 256 | INIT_LIST_HEAD(&sdev->cmd_list); |
256 | INIT_LIST_HEAD(&sdev->starved_entry); | 257 | INIT_LIST_HEAD(&sdev->starved_entry); |
258 | INIT_LIST_HEAD(&sdev->event_list); | ||
257 | spin_lock_init(&sdev->list_lock); | 259 | spin_lock_init(&sdev->list_lock); |
260 | INIT_WORK(&sdev->event_work, scsi_evt_thread); | ||
258 | 261 | ||
259 | sdev->sdev_gendev.parent = get_device(&starget->dev); | 262 | sdev->sdev_gendev.parent = get_device(&starget->dev); |
260 | sdev->sdev_target = starget; | 263 | sdev->sdev_target = starget; |
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index d531ceeb0d8c..f374fdcb6815 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -268,6 +268,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) | |||
268 | struct scsi_device *sdev; | 268 | struct scsi_device *sdev; |
269 | struct device *parent; | 269 | struct device *parent; |
270 | struct scsi_target *starget; | 270 | struct scsi_target *starget; |
271 | struct list_head *this, *tmp; | ||
271 | unsigned long flags; | 272 | unsigned long flags; |
272 | 273 | ||
273 | sdev = container_of(work, struct scsi_device, ew.work); | 274 | sdev = container_of(work, struct scsi_device, ew.work); |
@@ -282,6 +283,16 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) | |||
282 | list_del(&sdev->starved_entry); | 283 | list_del(&sdev->starved_entry); |
283 | spin_unlock_irqrestore(sdev->host->host_lock, flags); | 284 | spin_unlock_irqrestore(sdev->host->host_lock, flags); |
284 | 285 | ||
286 | cancel_work_sync(&sdev->event_work); | ||
287 | |||
288 | list_for_each_safe(this, tmp, &sdev->event_list) { | ||
289 | struct scsi_event *evt; | ||
290 | |||
291 | evt = list_entry(this, struct scsi_event, node); | ||
292 | list_del(&evt->node); | ||
293 | kfree(evt); | ||
294 | } | ||
295 | |||
285 | if (sdev->request_queue) { | 296 | if (sdev->request_queue) { |
286 | sdev->request_queue->queuedata = NULL; | 297 | sdev->request_queue->queuedata = NULL; |
287 | /* user context needed to free queue */ | 298 | /* user context needed to free queue */ |
@@ -614,6 +625,41 @@ sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) | |||
614 | } | 625 | } |
615 | static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); | 626 | static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); |
616 | 627 | ||
628 | #define DECLARE_EVT_SHOW(name, Cap_name) \ | ||
629 | static ssize_t \ | ||
630 | sdev_show_evt_##name(struct device *dev, struct device_attribute *attr, \ | ||
631 | char *buf) \ | ||
632 | { \ | ||
633 | struct scsi_device *sdev = to_scsi_device(dev); \ | ||
634 | int val = test_bit(SDEV_EVT_##Cap_name, sdev->supported_events);\ | ||
635 | return snprintf(buf, 20, "%d\n", val); \ | ||
636 | } | ||
637 | |||
638 | #define DECLARE_EVT_STORE(name, Cap_name) \ | ||
639 | static ssize_t \ | ||
640 | sdev_store_evt_##name(struct device *dev, struct device_attribute *attr, \ | ||
641 | const char *buf, size_t count) \ | ||
642 | { \ | ||
643 | struct scsi_device *sdev = to_scsi_device(dev); \ | ||
644 | int val = simple_strtoul(buf, NULL, 0); \ | ||
645 | if (val == 0) \ | ||
646 | clear_bit(SDEV_EVT_##Cap_name, sdev->supported_events); \ | ||
647 | else if (val == 1) \ | ||
648 | set_bit(SDEV_EVT_##Cap_name, sdev->supported_events); \ | ||
649 | else \ | ||
650 | return -EINVAL; \ | ||
651 | return count; \ | ||
652 | } | ||
653 | |||
654 | #define DECLARE_EVT(name, Cap_name) \ | ||
655 | DECLARE_EVT_SHOW(name, Cap_name) \ | ||
656 | DECLARE_EVT_STORE(name, Cap_name) \ | ||
657 | static DEVICE_ATTR(evt_##name, S_IRUGO, sdev_show_evt_##name, \ | ||
658 | sdev_store_evt_##name); | ||
659 | #define REF_EVT(name) &dev_attr_evt_##name.attr | ||
660 | |||
661 | DECLARE_EVT(media_change, MEDIA_CHANGE) | ||
662 | |||
617 | /* Default template for device attributes. May NOT be modified */ | 663 | /* Default template for device attributes. May NOT be modified */ |
618 | static struct attribute *scsi_sdev_attrs[] = { | 664 | static struct attribute *scsi_sdev_attrs[] = { |
619 | &dev_attr_device_blocked.attr, | 665 | &dev_attr_device_blocked.attr, |
@@ -631,6 +677,7 @@ static struct attribute *scsi_sdev_attrs[] = { | |||
631 | &dev_attr_iodone_cnt.attr, | 677 | &dev_attr_iodone_cnt.attr, |
632 | &dev_attr_ioerr_cnt.attr, | 678 | &dev_attr_ioerr_cnt.attr, |
633 | &dev_attr_modalias.attr, | 679 | &dev_attr_modalias.attr, |
680 | REF_EVT(media_change), | ||
634 | NULL | 681 | NULL |
635 | }; | 682 | }; |
636 | 683 | ||