diff options
| author | Mike Miller <mikem@beardog.cca.cpqcorp.net> | 2006-04-10 18:38:07 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-04-17 17:24:57 -0400 |
| commit | ca1e0484d9fe8a9048ac32b0f9894545f43704e8 (patch) | |
| tree | 60069aefd37077a86072020713b046203762ff5a /drivers | |
| parent | 75616cf9854b83eb83a968b1338ae0ee11c9673c (diff) | |
[PATCH] cciss: bug fix for crash when running hpacucli
Fix a crash when running hpacucli with multiple logical volumes on a cciss
controller. We were not properly initializing the disk->queue and causing
a fault.
Thanks to Hasso Tepper for reporting the problem. Thanks to Steve Cameron
for root causing the problem. Most of the patch just moves things around.
The fix is a one-liner.
Signed-off-by: Mike Miller <mike.miller@hp.com>
Signed-off-by: Stephen Cameron <steve.cameron@hp.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/block/cciss.c | 96 |
1 files changed, 49 insertions, 47 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 1b0fd31c57c3..1319d8f20640 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
| @@ -1180,6 +1180,53 @@ static int revalidate_allvol(ctlr_info_t *host) | |||
| 1180 | return 0; | 1180 | return 0; |
| 1181 | } | 1181 | } |
| 1182 | 1182 | ||
| 1183 | static inline void complete_buffers(struct bio *bio, int status) | ||
| 1184 | { | ||
| 1185 | while (bio) { | ||
| 1186 | struct bio *xbh = bio->bi_next; | ||
| 1187 | int nr_sectors = bio_sectors(bio); | ||
| 1188 | |||
| 1189 | bio->bi_next = NULL; | ||
| 1190 | blk_finished_io(len); | ||
| 1191 | bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); | ||
| 1192 | bio = xbh; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | } | ||
| 1196 | |||
| 1197 | static void cciss_softirq_done(struct request *rq) | ||
| 1198 | { | ||
| 1199 | CommandList_struct *cmd = rq->completion_data; | ||
| 1200 | ctlr_info_t *h = hba[cmd->ctlr]; | ||
| 1201 | unsigned long flags; | ||
| 1202 | u64bit temp64; | ||
| 1203 | int i, ddir; | ||
| 1204 | |||
| 1205 | if (cmd->Request.Type.Direction == XFER_READ) | ||
| 1206 | ddir = PCI_DMA_FROMDEVICE; | ||
| 1207 | else | ||
| 1208 | ddir = PCI_DMA_TODEVICE; | ||
| 1209 | |||
| 1210 | /* command did not need to be retried */ | ||
| 1211 | /* unmap the DMA mapping for all the scatter gather elements */ | ||
| 1212 | for(i=0; i<cmd->Header.SGList; i++) { | ||
| 1213 | temp64.val32.lower = cmd->SG[i].Addr.lower; | ||
| 1214 | temp64.val32.upper = cmd->SG[i].Addr.upper; | ||
| 1215 | pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | complete_buffers(rq->bio, rq->errors); | ||
| 1219 | |||
| 1220 | #ifdef CCISS_DEBUG | ||
| 1221 | printk("Done with %p\n", rq); | ||
| 1222 | #endif /* CCISS_DEBUG */ | ||
| 1223 | |||
| 1224 | spin_lock_irqsave(&h->lock, flags); | ||
| 1225 | end_that_request_last(rq, rq->errors); | ||
| 1226 | cmd_free(h, cmd,1); | ||
| 1227 | spin_unlock_irqrestore(&h->lock, flags); | ||
| 1228 | } | ||
| 1229 | |||
| 1183 | /* This function will check the usage_count of the drive to be updated/added. | 1230 | /* This function will check the usage_count of the drive to be updated/added. |
| 1184 | * If the usage_count is zero then the drive information will be updated and | 1231 | * If the usage_count is zero then the drive information will be updated and |
| 1185 | * the disk will be re-registered with the kernel. If not then it will be | 1232 | * the disk will be re-registered with the kernel. If not then it will be |
| @@ -1248,6 +1295,8 @@ static void cciss_update_drive_info(int ctlr, int drv_index) | |||
| 1248 | 1295 | ||
| 1249 | blk_queue_max_sectors(disk->queue, 512); | 1296 | blk_queue_max_sectors(disk->queue, 512); |
| 1250 | 1297 | ||
| 1298 | blk_queue_softirq_done(disk->queue, cciss_softirq_done); | ||
| 1299 | |||
| 1251 | disk->queue->queuedata = hba[ctlr]; | 1300 | disk->queue->queuedata = hba[ctlr]; |
| 1252 | 1301 | ||
| 1253 | blk_queue_hardsect_size(disk->queue, | 1302 | blk_queue_hardsect_size(disk->queue, |
| @@ -2147,20 +2196,6 @@ static void start_io( ctlr_info_t *h) | |||
| 2147 | addQ (&(h->cmpQ), c); | 2196 | addQ (&(h->cmpQ), c); |
| 2148 | } | 2197 | } |
| 2149 | } | 2198 | } |
| 2150 | |||
| 2151 | static inline void complete_buffers(struct bio *bio, int status) | ||
| 2152 | { | ||
| 2153 | while (bio) { | ||
| 2154 | struct bio *xbh = bio->bi_next; | ||
| 2155 | int nr_sectors = bio_sectors(bio); | ||
| 2156 | |||
| 2157 | bio->bi_next = NULL; | ||
| 2158 | blk_finished_io(len); | ||
| 2159 | bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); | ||
| 2160 | bio = xbh; | ||
| 2161 | } | ||
| 2162 | |||
| 2163 | } | ||
| 2164 | /* Assumes that CCISS_LOCK(h->ctlr) is held. */ | 2199 | /* Assumes that CCISS_LOCK(h->ctlr) is held. */ |
| 2165 | /* Zeros out the error record and then resends the command back */ | 2200 | /* Zeros out the error record and then resends the command back */ |
| 2166 | /* to the controller */ | 2201 | /* to the controller */ |
| @@ -2178,39 +2213,6 @@ static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c) | |||
| 2178 | start_io(h); | 2213 | start_io(h); |
| 2179 | } | 2214 | } |
| 2180 | 2215 | ||
| 2181 | static void cciss_softirq_done(struct request *rq) | ||
| 2182 | { | ||
| 2183 | CommandList_struct *cmd = rq->completion_data; | ||
| 2184 | ctlr_info_t *h = hba[cmd->ctlr]; | ||
| 2185 | unsigned long flags; | ||
| 2186 | u64bit temp64; | ||
| 2187 | int i, ddir; | ||
| 2188 | |||
| 2189 | if (cmd->Request.Type.Direction == XFER_READ) | ||
| 2190 | ddir = PCI_DMA_FROMDEVICE; | ||
| 2191 | else | ||
| 2192 | ddir = PCI_DMA_TODEVICE; | ||
| 2193 | |||
| 2194 | /* command did not need to be retried */ | ||
| 2195 | /* unmap the DMA mapping for all the scatter gather elements */ | ||
| 2196 | for(i=0; i<cmd->Header.SGList; i++) { | ||
| 2197 | temp64.val32.lower = cmd->SG[i].Addr.lower; | ||
| 2198 | temp64.val32.upper = cmd->SG[i].Addr.upper; | ||
| 2199 | pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); | ||
| 2200 | } | ||
| 2201 | |||
| 2202 | complete_buffers(rq->bio, rq->errors); | ||
| 2203 | |||
| 2204 | #ifdef CCISS_DEBUG | ||
| 2205 | printk("Done with %p\n", rq); | ||
| 2206 | #endif /* CCISS_DEBUG */ | ||
| 2207 | |||
| 2208 | spin_lock_irqsave(&h->lock, flags); | ||
| 2209 | end_that_request_last(rq, rq->errors); | ||
| 2210 | cmd_free(h, cmd,1); | ||
| 2211 | spin_unlock_irqrestore(&h->lock, flags); | ||
| 2212 | } | ||
| 2213 | |||
| 2214 | /* checks the status of the job and calls complete buffers to mark all | 2216 | /* checks the status of the job and calls complete buffers to mark all |
| 2215 | * buffers for the completed job. Note that this function does not need | 2217 | * buffers for the completed job. Note that this function does not need |
| 2216 | * to hold the hba/queue lock. | 2218 | * to hold the hba/queue lock. |
