X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fs390%2Fchar%2Fsclp.c;h=047d305ccbab6606db2b50177b0d601bcbd2b934;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=e36307dedf16bd296ee54efa2799e8acf6eb7818;hpb=db216c3d5e4c040e557a50f8f5d35d5c415e8c1c;p=linux-2.6.git diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index e36307ded..047d305cc 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -52,6 +52,9 @@ static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); /* Timer for init mask retries. */ static struct timer_list retry_timer; +/* Timer for busy retries. */ +static struct timer_list sclp_busy_timer; + static volatile unsigned long sclp_status = 0; /* some status flags */ #define SCLP_INIT 0 @@ -59,6 +62,7 @@ static volatile unsigned long sclp_status = 0; #define SCLP_READING 2 #define SCLP_INIT_POLL_INTERVAL 1 +#define SCLP_BUSY_POLL_INTERVAL 1 #define SCLP_COMMAND_INITIATED 0 #define SCLP_BUSY 2 @@ -93,45 +97,61 @@ __service_call(sclp_cmdw_t command, void *sccb) */ if (cc == SCLP_NOT_OPERATIONAL) return -EIO; - /* - * We set the SCLP_RUNNING bit for cc 2 as well because if - * service_call returns cc 2 some old request is running - * that has to complete first - */ - set_bit(SCLP_RUNNING, &sclp_status); if (cc == SCLP_BUSY) return -EBUSY; return 0; } -static int +static void sclp_start_request(void) { struct sclp_req *req; int rc; unsigned long flags; - /* quick exit if sclp is already in use */ - if (test_bit(SCLP_RUNNING, &sclp_status)) - return -EBUSY; spin_lock_irqsave(&sclp_lock, flags); - /* Get first request on queue if available */ - req = NULL; - if (!list_empty(&sclp_req_queue)) + /* quick exit if sclp is already in use */ + if (test_bit(SCLP_RUNNING, &sclp_status)) { + spin_unlock_irqrestore(&sclp_lock, flags); + return; + } + /* Try to start requests from the request queue. */ + while (!list_empty(&sclp_req_queue)) { req = list_entry(sclp_req_queue.next, struct sclp_req, list); - if (req) { rc = __service_call(req->command, req->sccb); - if (rc) { - req->status = SCLP_REQ_FAILED; - list_del(&req->list); - } else + if (rc == 0) { + /* Sucessfully started request. */ req->status = SCLP_REQ_RUNNING; - } else - rc = -EINVAL; + /* Request active. Set running indication. */ + set_bit(SCLP_RUNNING, &sclp_status); + break; + } + if (rc == -EBUSY) { + /** + * SCLP is busy but no request is running. + * Try again later. + */ + if (!timer_pending(&sclp_busy_timer) || + !mod_timer(&sclp_busy_timer, + jiffies + SCLP_BUSY_POLL_INTERVAL*HZ)) { + sclp_busy_timer.function = + (void *) sclp_start_request; + sclp_busy_timer.expires = + jiffies + SCLP_BUSY_POLL_INTERVAL*HZ; + add_timer(&sclp_busy_timer); + } + break; + } + /* Request failed. */ + req->status = SCLP_REQ_FAILED; + list_del(&req->list); + if (req->callback) { + spin_unlock_irqrestore(&sclp_lock, flags); + req->callback(req, req->callback_data); + spin_lock_irqsave(&sclp_lock, flags); + } + } spin_unlock_irqrestore(&sclp_lock, flags); - if (rc == -EIO && req->callback != NULL) - req->callback(req, req->callback_data); - return rc; } static int @@ -474,11 +494,12 @@ static struct sclp_register sclp_state_change_event = { static void do_load_quiesce_psw(void * __unused) { + static atomic_t cpuid = ATOMIC_INIT(-1); psw_t quiesce_psw; - unsigned long status; + __u32 status; int i; - if (smp_processor_id() != 0) + if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid)) signal_processor(smp_processor_id(), sigp_stop); /* Wait for all other cpus to enter stopped state */ i = 1; @@ -491,7 +512,7 @@ do_load_quiesce_psw(void * __unused) case sigp_order_code_accepted: case sigp_status_stored: /* Check for stopped and check stop state */ - if (test_bit(6, &status) || test_bit(4, &status)) + if (status & 0x50) i++; break; case sigp_busy: @@ -613,6 +634,8 @@ sclp_init_mask(void) */ do { rc = __service_call(req->command, req->sccb); + if (rc == 0) + set_bit(SCLP_RUNNING, &sclp_status); spin_unlock_irqrestore(&sclp_lock, flags); if (rc == -EIO) return -ENOSYS; @@ -685,6 +708,7 @@ sclp_init(void) ctl_set_bit(0, 9); init_timer(&retry_timer); + init_timer(&sclp_busy_timer); /* do the initial write event mask */ rc = sclp_init_mask(); if (rc == 0) {