static int do_sync_request(sclp_cmdw_t cmd, void *sccb) { struct completion completion; struct sclp_req *request; int rc; request = kzalloc(sizeof(*request), GFP_KERNEL); if (!request) return -ENOMEM; request->command = cmd; request->sccb = sccb; request->status = SCLP_REQ_FILLED; request->callback = sclp_sync_callback; request->callback_data = &completion; init_completion(&completion); /* Perform sclp request. */ rc = sclp_add_request(request); if (rc) goto out; wait_for_completion(&completion); /* Check response. */ if (request->status != SCLP_REQ_DONE) { pr_warning("sync request failed (cmd=0x%08x, " "status=0x%02x)\n", cmd, request->status); rc = -EIO; } out: kfree(request); return rc; }
static int sdias_sclp_send(struct sclp_req *req) { int retries; int rc; for (retries = SDIAS_RETRIES; retries; retries--) { sclp_req_done = 0; TRACE("add request\n"); rc = sclp_add_request(req); if (rc) { /* not initiated, wait some time and retry */ set_current_state(TASK_INTERRUPTIBLE); TRACE("add request failed: rc = %i\n",rc); schedule_timeout(SDIAS_SLEEP_TICKS); continue; } /* initiated, wait for completion of service call */ wait_event(sdias_wq, (sclp_req_done == 1)); if (req->status == SCLP_REQ_FAILED) { TRACE("sclp request failed\n"); rc = -EIO; continue; } TRACE("request done\n"); break; } return rc; }
int sclp_emit_buffer(struct sclp_buffer *buffer, void (*callback)(struct sclp_buffer *, int)) { struct write_sccb *sccb; /* add current line if there is one */ if (buffer->current_line != NULL) sclp_finalize_mto(buffer); /* Are there messages in the output buffer ? */ if (buffer->mto_number == 0) return -EIO; sccb = buffer->sccb; if (sclp_rw_event.sclp_receive_mask & EVTYP_MSG_MASK) /* Use normal write message */ sccb->msg_buf.header.type = EVTYP_MSG; else if (sclp_rw_event.sclp_receive_mask & EVTYP_PMSGCMD_MASK) /* Use write priority message */ sccb->msg_buf.header.type = EVTYP_PMSGCMD; else return -ENOSYS; buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; buffer->request.status = SCLP_REQ_FILLED; buffer->request.callback = sclp_writedata_callback; buffer->request.callback_data = buffer; buffer->request.sccb = sccb; buffer->callback = callback; return sclp_add_request(&buffer->request); }
static void sclp_buffer_retry(unsigned long data) { struct sclp_buffer *buffer = (struct sclp_buffer *) data; buffer->request.status = SCLP_REQ_FILLED; buffer->sccb->header.response_code = 0x0000; sclp_add_request(&buffer->request); }
static int do_configure(sclp_cmdw_t cmd) { struct chp_cfg_data *data; int rc; if (!SCLP_HAS_CHP_RECONFIG) return -EOPNOTSUPP; /* Prepare sccb. */ data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!data) return -ENOMEM; data->sccb.header.length = sizeof(struct chp_cfg_sccb); data->req.command = cmd; data->req.sccb = &(data->sccb); data->req.status = SCLP_REQ_FILLED; data->req.callback = chp_callback; data->req.callback_data = &(data->completion); init_completion(&data->completion); /* Perform sclp request. */ rc = sclp_add_request(&(data->req)); if (rc) goto out; wait_for_completion(&data->completion); /* Check response .*/ if (data->req.status != SCLP_REQ_DONE) { printk(KERN_WARNING TAG "configure channel-path request failed " "(status=0x%02x)\n", data->req.status); rc = -EIO; goto out; } switch (data->sccb.header.response_code) { case 0x0020: case 0x0120: case 0x0440: case 0x0450: break; default: printk(KERN_WARNING TAG "configure channel-path failed " "(cmd=0x%08x, response=0x%04x)\n", cmd, data->sccb.header.response_code); rc = -EIO; break; } out: free_page((unsigned long) data); return rc; }
/** * sclp_chp_read_info - perform read channel-path information sclp command * @info: resulting channel-path information data * * Perform read channel-path information sclp command and wait for completion. * On success, store channel-path information in @info and return 0. Return * non-zero otherwise. */ int sclp_chp_read_info(struct sclp_chp_info *info) { struct chp_info_data *data; int rc; if (!SCLP_HAS_CHP_INFO) return -EOPNOTSUPP; /* Prepare sccb. */ data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!data) return -ENOMEM; data->sccb.header.length = sizeof(struct chp_info_sccb); data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION; data->req.sccb = &(data->sccb); data->req.status = SCLP_REQ_FILLED; data->req.callback = chp_callback; data->req.callback_data = &(data->completion); init_completion(&data->completion); /* Perform sclp request. */ rc = sclp_add_request(&(data->req)); if (rc) goto out; wait_for_completion(&data->completion); /* Check response .*/ if (data->req.status != SCLP_REQ_DONE) { printk(KERN_WARNING TAG "read channel-path info request failed " "(status=0x%02x)\n", data->req.status); rc = -EIO; goto out; } if (data->sccb.header.response_code != 0x0010) { printk(KERN_WARNING TAG "read channel-path info failed " "(response=0x%04x)\n", data->sccb.header.response_code); rc = -EIO; goto out; } memcpy(info->recognized, data->sccb.recognized, SCLP_CHP_INFO_MASK_SIZE); memcpy(info->standby, data->sccb.standby, SCLP_CHP_INFO_MASK_SIZE); memcpy(info->configured, data->sccb.configured, SCLP_CHP_INFO_MASK_SIZE); out: free_page((unsigned long) data); return rc; }
/* * Setup the request structure in the struct sclp_buffer to do SCLP Write * Event Data and pass the request to the core SCLP loop. */ void sclp_emit_buffer(struct sclp_buffer *buffer, void (*callback)(struct sclp_buffer *, int)) { struct write_sccb *sccb; /* add current line if there is one */ if (buffer->current_line != NULL) sclp_finalize_mto(buffer); /* Are there messages in the output buffer ? */ if (buffer->mto_number == 0) { if (callback != NULL) callback(buffer, 0); return; } sccb = buffer->sccb; if (sclp_rw_event.sclp_send_mask & EvTyp_Msg_Mask) /* Use normal write message */ sccb->msg_buf.header.type = EvTyp_Msg; else if (sclp_rw_event.sclp_send_mask & EvTyp_PMsgCmd_Mask) /* Use write priority message */ sccb->msg_buf.header.type = EvTyp_PMsgCmd; else { if (callback != NULL) callback(buffer, -ENOSYS); return; } buffer->request.command = SCLP_CMDW_WRITEDATA; buffer->request.status = SCLP_REQ_FILLED; buffer->request.callback = sclp_writedata_callback; buffer->request.callback_data = buffer; buffer->request.sccb = sccb; buffer->callback = callback; sclp_add_request(&buffer->request); }
static void sclp_writedata_callback(struct sclp_req *request, void *data) { int rc; struct sclp_buffer *buffer; struct write_sccb *sccb; buffer = (struct sclp_buffer *) data; sccb = buffer->sccb; if (request->status == SCLP_REQ_FAILED) { if (buffer->callback != NULL) buffer->callback(buffer, -EIO); return; } /* check SCLP response code and choose suitable action */ switch (sccb->header.response_code) { case 0x0020 : /* Normal completion, buffer processed, message(s) sent */ rc = 0; break; case 0x0340: /* Contained SCLP equipment check */ if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) { rc = -EIO; break; } /* remove processed buffers and requeue rest */ if (sclp_remove_processed((struct sccb_header *) sccb) > 0) { /* not all buffers were processed */ sccb->header.response_code = 0x0000; buffer->request.status = SCLP_REQ_FILLED; rc = sclp_add_request(request); if (rc == 0) return; } else rc = 0; break; case 0x0040: /* SCLP equipment check */ case 0x05f0: /* Target resource in improper state */ if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) { rc = -EIO; break; } /* retry request */ sccb->header.response_code = 0x0000; buffer->request.status = SCLP_REQ_FILLED; rc = sclp_add_request(request); if (rc == 0) return; break; default: if (sccb->header.response_code == 0x71f0) rc = -ENOMEM; else rc = -EINVAL; break; } if (buffer->callback != NULL) buffer->callback(buffer, rc); }
int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid) { DECLARE_COMPLETION_ONSTACK(completion); struct err_notify_sccb *sccb; struct sclp_req req; int ret; ret = sclp_pci_check_report(report); if (ret) return ret; mutex_lock(&sclp_pci_mutex); ret = sclp_register(&sclp_pci_event); if (ret) goto out_unlock; if (!(sclp_pci_event.sclp_receive_mask & EVTYP_ERRNOTIFY_MASK)) { ret = -EOPNOTSUPP; goto out_unregister; } sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!sccb) { ret = -ENOMEM; goto out_unregister; } memset(&req, 0, sizeof(req)); req.callback_data = &completion; req.callback = sclp_pci_callback; req.command = SCLP_CMDW_WRITE_EVENT_DATA; req.status = SCLP_REQ_FILLED; req.sccb = sccb; sccb->evbuf.header.length = sizeof(sccb->evbuf) + report->length; sccb->evbuf.header.type = EVTYP_ERRNOTIFY; sccb->header.length = sizeof(sccb->header) + sccb->evbuf.header.length; sccb->evbuf.action = report->action; sccb->evbuf.atype = SCLP_ATYPE_PCI; sccb->evbuf.fh = fh; sccb->evbuf.fid = fid; memcpy(sccb->evbuf.data, report->data, report->length); ret = sclp_add_request(&req); if (ret) goto out_free_req; wait_for_completion(&completion); if (req.status != SCLP_REQ_DONE) { pr_warn("request failed (status=0x%02x)\n", req.status); ret = -EIO; goto out_free_req; } if (sccb->header.response_code != 0x0020) { pr_warn("request failed with response code 0x%x\n", sccb->header.response_code); ret = -EIO; } out_free_req: free_page((unsigned long) sccb); out_unregister: sclp_unregister(&sclp_pci_event); out_unlock: mutex_unlock(&sclp_pci_mutex); return ret; }
static void sclp_writedata_callback(struct sclp_req *request, void *data) { int rc; struct sclp_buffer *buffer; struct write_sccb *sccb; buffer = (struct sclp_buffer *) data; sccb = buffer->sccb; if (request->status == SCLP_REQ_FAILED) { if (buffer->callback != NULL) buffer->callback(buffer, -EIO); return; } switch (sccb->header.response_code) { case 0x0020 : rc = 0; break; case 0x0340: if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) { rc = -EIO; break; } if (sclp_remove_processed((struct sccb_header *) sccb) > 0) { sccb->header.response_code = 0x0000; buffer->request.status = SCLP_REQ_FILLED; rc = sclp_add_request(request); if (rc == 0) return; } else rc = 0; break; case 0x0040: case 0x05f0: if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) { rc = -EIO; break; } sccb->header.response_code = 0x0000; buffer->request.status = SCLP_REQ_FILLED; rc = sclp_add_request(request); if (rc == 0) return; break; default: if (sccb->header.response_code == 0x71f0) rc = -ENOMEM; else rc = -EINVAL; break; } if (buffer->callback != NULL) buffer->callback(buffer, rc); }