Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'block-6.9-20240322' of git://git.kernel.dk/linux

Pull more block updates from Jens Axboe:

- NVMe pull request via Keith:
- Make an informative message less ominous (Keith)
- Enhanced trace decoding (Guixin)
- TCP updates (Hannes, Li)
- Fabrics connect deadlock fix (Chunguang)
- Platform API migration update (Uwe)
- A new device quirk (Jiawei)

- Remove dead assignment in fd (Yufeng)

* tag 'block-6.9-20240322' of git://git.kernel.dk/linux:
nvmet-rdma: remove NVMET_RDMA_REQ_INVALIDATE_RKEY flag
nvme: remove redundant BUILD_BUG_ON check
floppy: remove duplicated code in redo_fd_request()
nvme/tcp: Add wq_unbound modparam for nvme_tcp_wq
nvme-tcp: Export the nvme_tcp_wq to sysfs
drivers/nvme: Add quirks for device 126f:2262
nvme: parse format command's lbafu when tracing
nvme: add tracing of reservation commands
nvme: parse zns command's zsa and zrasf to string
nvme: use nvme_disk_is_ns_head helper
nvme: fix reconnection fail due to reserved tag allocation
nvmet: add tracing of zns commands
nvmet: add tracing of authentication commands
nvme-apple: Convert to platform remove callback returning void
nvmet-tcp: do not continue for invalid icreq
nvme: change shutdown timeout setting message

+233 -34
-1
drivers/block/floppy.c
··· 2787 2787 pending = set_next_request(); 2788 2788 spin_unlock_irq(&floppy_lock); 2789 2789 if (!pending) { 2790 - do_floppy = NULL; 2791 2790 unlock_fdc(); 2792 2791 return; 2793 2792 }
+2 -4
drivers/nvme/host/apple.c
··· 1532 1532 return ret; 1533 1533 } 1534 1534 1535 - static int apple_nvme_remove(struct platform_device *pdev) 1535 + static void apple_nvme_remove(struct platform_device *pdev) 1536 1536 { 1537 1537 struct apple_nvme *anv = platform_get_drvdata(pdev); 1538 1538 ··· 1547 1547 apple_rtkit_shutdown(anv->rtk); 1548 1548 1549 1549 apple_nvme_detach_genpd(anv); 1550 - 1551 - return 0; 1552 1550 } 1553 1551 1554 1552 static void apple_nvme_shutdown(struct platform_device *pdev) ··· 1596 1598 .pm = pm_sleep_ptr(&apple_nvme_pm_ops), 1597 1599 }, 1598 1600 .probe = apple_nvme_probe, 1599 - .remove = apple_nvme_remove, 1601 + .remove_new = apple_nvme_remove, 1600 1602 .shutdown = apple_nvme_shutdown, 1601 1603 }; 1602 1604 module_platform_driver(apple_nvme_driver);
+5 -6
drivers/nvme/host/core.c
··· 1807 1807 { 1808 1808 struct nvme_ctrl *ctrl = ns->ctrl; 1809 1809 1810 - BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) < 1811 - NVME_DSM_MAX_RANGES); 1812 - 1813 1810 if (ctrl->dmrsl && ctrl->dmrsl <= nvme_sect_to_lba(ns->head, UINT_MAX)) 1814 1811 lim->max_hw_discard_sectors = 1815 1812 nvme_lba_to_sect(ns->head, ctrl->dmrsl); ··· 3234 3237 3235 3238 if (ctrl->shutdown_timeout != shutdown_timeout) 3236 3239 dev_info(ctrl->device, 3237 - "Shutdown timeout set to %u seconds\n", 3240 + "D3 entry latency set to %u seconds\n", 3238 3241 ctrl->shutdown_timeout); 3239 3242 } else 3240 3243 ctrl->shutdown_timeout = shutdown_timeout; ··· 4388 4391 set->ops = ops; 4389 4392 set->queue_depth = NVME_AQ_MQ_TAG_DEPTH; 4390 4393 if (ctrl->ops->flags & NVME_F_FABRICS) 4391 - set->reserved_tags = NVMF_RESERVED_TAGS; 4394 + /* Reserved for fabric connect and keep alive */ 4395 + set->reserved_tags = 2; 4392 4396 set->numa_node = ctrl->numa_node; 4393 4397 set->flags = BLK_MQ_F_NO_SCHED; 4394 4398 if (ctrl->ops->flags & NVME_F_BLOCKING) ··· 4458 4460 if (ctrl->quirks & NVME_QUIRK_SHARED_TAGS) 4459 4461 set->reserved_tags = NVME_AQ_DEPTH; 4460 4462 else if (ctrl->ops->flags & NVME_F_FABRICS) 4461 - set->reserved_tags = NVMF_RESERVED_TAGS; 4463 + /* Reserved for fabric connect */ 4464 + set->reserved_tags = 1; 4462 4465 set->numa_node = ctrl->numa_node; 4463 4466 set->flags = BLK_MQ_F_SHOULD_MERGE; 4464 4467 if (ctrl->ops->flags & NVME_F_BLOCKING)
-7
drivers/nvme/host/fabrics.h
··· 19 19 #define NVMF_DEF_FAIL_FAST_TMO -1 20 20 21 21 /* 22 - * Reserved one command for internal usage. This command is used for sending 23 - * the connect command, as well as for the keep alive command on the admin 24 - * queue once live. 25 - */ 26 - #define NVMF_RESERVED_TAGS 1 27 - 28 - /* 29 22 * Define a host as seen by the target. We allocate one at boot, but also 30 23 * allow the override it when creating controllers. This is both to provide 31 24 * persistence of the Host NQN over multiple boots, and to allow using
+3
drivers/nvme/host/pci.c
··· 3363 3363 NVME_QUIRK_BOGUS_NID, }, 3364 3364 { PCI_VDEVICE(REDHAT, 0x0010), /* Qemu emulated controller */ 3365 3365 .driver_data = NVME_QUIRK_BOGUS_NID, }, 3366 + { PCI_DEVICE(0x126f, 0x2262), /* Silicon Motion generic */ 3367 + .driver_data = NVME_QUIRK_NO_DEEPEST_PS | 3368 + NVME_QUIRK_BOGUS_NID, }, 3366 3369 { PCI_DEVICE(0x126f, 0x2263), /* Silicon Motion unidentified */ 3367 3370 .driver_data = NVME_QUIRK_NO_NS_DESC_LIST | 3368 3371 NVME_QUIRK_BOGUS_NID, },
+1 -2
drivers/nvme/host/pr.c
··· 97 97 static int nvme_send_pr_command(struct block_device *bdev, 98 98 struct nvme_command *c, void *data, unsigned int data_len) 99 99 { 100 - if (IS_ENABLED(CONFIG_NVME_MULTIPATH) && 101 - nvme_disk_is_ns_head(bdev->bd_disk)) 100 + if (nvme_disk_is_ns_head(bdev->bd_disk)) 102 101 return nvme_send_ns_head_pr_command(bdev, c, data, data_len); 103 102 104 103 return nvme_send_ns_pr_command(bdev->bd_disk->private_data, c, data,
+1 -2
drivers/nvme/host/sysfs.c
··· 236 236 struct block_device *bdev = disk->part0; 237 237 int ret; 238 238 239 - if (IS_ENABLED(CONFIG_NVME_MULTIPATH) && 240 - bdev->bd_disk->fops == &nvme_ns_head_ops) 239 + if (nvme_disk_is_ns_head(bdev->bd_disk)) 241 240 ret = ns_head_update_nuse(head); 242 241 else 243 242 ret = ns_update_nuse(bdev->bd_disk->private_data);
+18 -3
drivers/nvme/host/tcp.c
··· 37 37 MODULE_PARM_DESC(so_priority, "nvme tcp socket optimize priority"); 38 38 39 39 /* 40 + * Use the unbound workqueue for nvme_tcp_wq, then we can set the cpu affinity 41 + * from sysfs. 42 + */ 43 + static bool wq_unbound; 44 + module_param(wq_unbound, bool, 0644); 45 + MODULE_PARM_DESC(wq_unbound, "Use unbound workqueue for nvme-tcp IO context (default false)"); 46 + 47 + /* 40 48 * TLS handshake timeout 41 49 */ 42 50 static int tls_handshake_timeout = 10; ··· 1554 1546 else if (nvme_tcp_poll_queue(queue)) 1555 1547 n = qid - ctrl->io_queues[HCTX_TYPE_DEFAULT] - 1556 1548 ctrl->io_queues[HCTX_TYPE_READ] - 1; 1557 - queue->io_cpu = cpumask_next_wrap(n - 1, cpu_online_mask, -1, false); 1549 + if (wq_unbound) 1550 + queue->io_cpu = WORK_CPU_UNBOUND; 1551 + else 1552 + queue->io_cpu = cpumask_next_wrap(n - 1, cpu_online_mask, -1, false); 1558 1553 } 1559 1554 1560 1555 static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid) ··· 2796 2785 2797 2786 static int __init nvme_tcp_init_module(void) 2798 2787 { 2788 + unsigned int wq_flags = WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_SYSFS; 2789 + 2799 2790 BUILD_BUG_ON(sizeof(struct nvme_tcp_hdr) != 8); 2800 2791 BUILD_BUG_ON(sizeof(struct nvme_tcp_cmd_pdu) != 72); 2801 2792 BUILD_BUG_ON(sizeof(struct nvme_tcp_data_pdu) != 24); ··· 2807 2794 BUILD_BUG_ON(sizeof(struct nvme_tcp_icresp_pdu) != 128); 2808 2795 BUILD_BUG_ON(sizeof(struct nvme_tcp_term_pdu) != 24); 2809 2796 2810 - nvme_tcp_wq = alloc_workqueue("nvme_tcp_wq", 2811 - WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); 2797 + if (wq_unbound) 2798 + wq_flags |= WQ_UNBOUND; 2799 + 2800 + nvme_tcp_wq = alloc_workqueue("nvme_tcp_wq", wq_flags, 0); 2812 2801 if (!nvme_tcp_wq) 2813 2802 return -ENOMEM; 2814 2803
+101 -4
drivers/nvme/host/trace.c
··· 119 119 static const char *nvme_trace_admin_format_nvm(struct trace_seq *p, u8 *cdw10) 120 120 { 121 121 const char *ret = trace_seq_buffer_ptr(p); 122 - u8 lbaf = cdw10[0] & 0xF; 122 + /* 123 + * lbafu(bit 13:12) is already in the upper 4 bits, lbafl: bit 03:00. 124 + */ 125 + u8 lbaf = (cdw10[1] & 0x30) | (cdw10[0] & 0xF); 123 126 u8 mset = (cdw10[0] >> 4) & 0x1; 124 127 u8 pi = (cdw10[0] >> 5) & 0x7; 125 128 u8 pil = cdw10[1] & 0x1; ··· 167 164 168 165 static const char *nvme_trace_zone_mgmt_send(struct trace_seq *p, u8 *cdw10) 169 166 { 167 + static const char * const zsa_strs[] = { 168 + [0x01] = "close zone", 169 + [0x02] = "finish zone", 170 + [0x03] = "open zone", 171 + [0x04] = "reset zone", 172 + [0x05] = "offline zone", 173 + [0x10] = "set zone descriptor extension" 174 + }; 170 175 const char *ret = trace_seq_buffer_ptr(p); 171 176 u64 slba = get_unaligned_le64(cdw10); 177 + const char *zsa_str; 172 178 u8 zsa = cdw10[12]; 173 179 u8 all = cdw10[13]; 174 180 175 - trace_seq_printf(p, "slba=%llu, zsa=%u, all=%u", slba, zsa, all); 181 + if (zsa < ARRAY_SIZE(zsa_strs) && zsa_strs[zsa]) 182 + zsa_str = zsa_strs[zsa]; 183 + else 184 + zsa_str = "reserved"; 185 + 186 + trace_seq_printf(p, "slba=%llu, zsa=%u:%s, all=%u", 187 + slba, zsa, zsa_str, all); 176 188 trace_seq_putc(p, 0); 177 189 178 190 return ret; ··· 195 177 196 178 static const char *nvme_trace_zone_mgmt_recv(struct trace_seq *p, u8 *cdw10) 197 179 { 180 + static const char * const zrasf_strs[] = { 181 + [0x00] = "list all zones", 182 + [0x01] = "list the zones in the ZSE: Empty state", 183 + [0x02] = "list the zones in the ZSIO: Implicitly Opened state", 184 + [0x03] = "list the zones in the ZSEO: Explicitly Opened state", 185 + [0x04] = "list the zones in the ZSC: Closed state", 186 + [0x05] = "list the zones in the ZSF: Full state", 187 + [0x06] = "list the zones in the ZSRO: Read Only state", 188 + [0x07] = "list the zones in the ZSO: Offline state", 189 + [0x09] = "list the zones that have the zone attribute" 190 + }; 198 191 const char *ret = trace_seq_buffer_ptr(p); 199 192 u64 slba = get_unaligned_le64(cdw10); 200 193 u32 numd = get_unaligned_le32(cdw10 + 8); 201 194 u8 zra = cdw10[12]; 202 195 u8 zrasf = cdw10[13]; 196 + const char *zrasf_str; 203 197 u8 pr = cdw10[14]; 204 198 205 - trace_seq_printf(p, "slba=%llu, numd=%u, zra=%u, zrasf=%u, pr=%u", 206 - slba, numd, zra, zrasf, pr); 199 + if (zrasf < ARRAY_SIZE(zrasf_strs) && zrasf_strs[zrasf]) 200 + zrasf_str = zrasf_strs[zrasf]; 201 + else 202 + zrasf_str = "reserved"; 203 + 204 + trace_seq_printf(p, "slba=%llu, numd=%u, zra=%u, zrasf=%u:%s, pr=%u", 205 + slba, numd, zra, zrasf, zrasf_str, pr); 206 + trace_seq_putc(p, 0); 207 + 208 + return ret; 209 + } 210 + 211 + static const char *nvme_trace_resv_reg(struct trace_seq *p, u8 *cdw10) 212 + { 213 + const char *ret = trace_seq_buffer_ptr(p); 214 + u8 rrega = cdw10[0] & 0x7; 215 + u8 iekey = (cdw10[0] >> 3) & 0x1; 216 + u8 ptpl = (cdw10[3] >> 6) & 0x3; 217 + 218 + trace_seq_printf(p, "rrega=%u, iekey=%u, ptpl=%u", 219 + rrega, iekey, ptpl); 220 + trace_seq_putc(p, 0); 221 + 222 + return ret; 223 + } 224 + 225 + static const char *nvme_trace_resv_acq(struct trace_seq *p, u8 *cdw10) 226 + { 227 + const char *ret = trace_seq_buffer_ptr(p); 228 + u8 racqa = cdw10[0] & 0x7; 229 + u8 iekey = (cdw10[0] >> 3) & 0x1; 230 + u8 rtype = cdw10[1]; 231 + 232 + trace_seq_printf(p, "racqa=%u, iekey=%u, rtype=%u", 233 + racqa, iekey, rtype); 234 + trace_seq_putc(p, 0); 235 + 236 + return ret; 237 + } 238 + 239 + static const char *nvme_trace_resv_rel(struct trace_seq *p, u8 *cdw10) 240 + { 241 + const char *ret = trace_seq_buffer_ptr(p); 242 + u8 rrela = cdw10[0] & 0x7; 243 + u8 iekey = (cdw10[0] >> 3) & 0x1; 244 + u8 rtype = cdw10[1]; 245 + 246 + trace_seq_printf(p, "rrela=%u, iekey=%u, rtype=%u", 247 + rrela, iekey, rtype); 248 + trace_seq_putc(p, 0); 249 + 250 + return ret; 251 + } 252 + 253 + static const char *nvme_trace_resv_report(struct trace_seq *p, u8 *cdw10) 254 + { 255 + const char *ret = trace_seq_buffer_ptr(p); 256 + u32 numd = get_unaligned_le32(cdw10); 257 + u8 eds = cdw10[4] & 0x1; 258 + 259 + trace_seq_printf(p, "numd=%u, eds=%u", numd, eds); 207 260 trace_seq_putc(p, 0); 208 261 209 262 return ret; ··· 332 243 return nvme_trace_zone_mgmt_send(p, cdw10); 333 244 case nvme_cmd_zone_mgmt_recv: 334 245 return nvme_trace_zone_mgmt_recv(p, cdw10); 246 + case nvme_cmd_resv_register: 247 + return nvme_trace_resv_reg(p, cdw10); 248 + case nvme_cmd_resv_acquire: 249 + return nvme_trace_resv_acq(p, cdw10); 250 + case nvme_cmd_resv_release: 251 + return nvme_trace_resv_rel(p, cdw10); 252 + case nvme_cmd_resv_report: 253 + return nvme_trace_resv_report(p, cdw10); 335 254 default: 336 255 return nvme_trace_common(p, cdw10); 337 256 }
+3 -5
drivers/nvme/target/rdma.c
··· 53 53 54 54 enum { 55 55 NVMET_RDMA_REQ_INLINE_DATA = (1 << 0), 56 - NVMET_RDMA_REQ_INVALIDATE_RKEY = (1 << 1), 57 56 }; 58 57 59 58 struct nvmet_rdma_rsp { ··· 721 722 struct rdma_cm_id *cm_id = rsp->queue->cm_id; 722 723 struct ib_send_wr *first_wr; 723 724 724 - if (rsp->flags & NVMET_RDMA_REQ_INVALIDATE_RKEY) { 725 + if (rsp->invalidate_rkey) { 725 726 rsp->send_wr.opcode = IB_WR_SEND_WITH_INV; 726 727 rsp->send_wr.ex.invalidate_rkey = rsp->invalidate_rkey; 727 728 } else { ··· 904 905 goto error_out; 905 906 rsp->n_rdma += ret; 906 907 907 - if (invalidate) { 908 + if (invalidate) 908 909 rsp->invalidate_rkey = key; 909 - rsp->flags |= NVMET_RDMA_REQ_INVALIDATE_RKEY; 910 - } 911 910 912 911 return 0; 913 912 ··· 1044 1047 rsp->req.cmd = cmd->nvme_cmd; 1045 1048 rsp->req.port = queue->port; 1046 1049 rsp->n_rdma = 0; 1050 + rsp->invalidate_rkey = 0; 1047 1051 1048 1052 if (unlikely(queue->state != NVMET_RDMA_Q_LIVE)) { 1049 1053 unsigned long flags;
+1
drivers/nvme/target/tcp.c
··· 898 898 pr_err("bad nvme-tcp pdu length (%d)\n", 899 899 le32_to_cpu(icreq->hdr.plen)); 900 900 nvmet_tcp_fatal_error(queue); 901 + return -EPROTO; 901 902 } 902 903 903 904 if (icreq->pfv != NVME_TCP_PFV_1_0) {
+98
drivers/nvme/target/trace.c
··· 119 119 } 120 120 } 121 121 122 + static const char *nvmet_trace_zone_mgmt_send(struct trace_seq *p, u8 *cdw10) 123 + { 124 + static const char * const zsa_strs[] = { 125 + [0x01] = "close zone", 126 + [0x02] = "finish zone", 127 + [0x03] = "open zone", 128 + [0x04] = "reset zone", 129 + [0x05] = "offline zone", 130 + [0x10] = "set zone descriptor extension" 131 + }; 132 + const char *ret = trace_seq_buffer_ptr(p); 133 + u64 slba = get_unaligned_le64(cdw10); 134 + const char *zsa_str; 135 + u8 zsa = cdw10[12]; 136 + u8 all = cdw10[13]; 137 + 138 + if (zsa < ARRAY_SIZE(zsa_strs) && zsa_strs[zsa]) 139 + zsa_str = zsa_strs[zsa]; 140 + else 141 + zsa_str = "reserved"; 142 + 143 + trace_seq_printf(p, "slba=%llu, zsa=%u:%s, all=%u", 144 + slba, zsa, zsa_str, all); 145 + trace_seq_putc(p, 0); 146 + 147 + return ret; 148 + } 149 + 150 + static const char *nvmet_trace_zone_mgmt_recv(struct trace_seq *p, u8 *cdw10) 151 + { 152 + static const char * const zrasf_strs[] = { 153 + [0x00] = "list all zones", 154 + [0x01] = "list the zones in the ZSE: Empty state", 155 + [0x02] = "list the zones in the ZSIO: Implicitly Opened state", 156 + [0x03] = "list the zones in the ZSEO: Explicitly Opened state", 157 + [0x04] = "list the zones in the ZSC: Closed state", 158 + [0x05] = "list the zones in the ZSF: Full state", 159 + [0x06] = "list the zones in the ZSRO: Read Only state", 160 + [0x07] = "list the zones in the ZSO: Offline state", 161 + [0x09] = "list the zones that have the zone attribute" 162 + }; 163 + const char *ret = trace_seq_buffer_ptr(p); 164 + u64 slba = get_unaligned_le64(cdw10); 165 + u32 numd = get_unaligned_le32(&cdw10[8]); 166 + u8 zra = cdw10[12]; 167 + u8 zrasf = cdw10[13]; 168 + const char *zrasf_str; 169 + u8 pr = cdw10[14]; 170 + 171 + if (zrasf < ARRAY_SIZE(zrasf_strs) && zrasf_strs[zrasf]) 172 + zrasf_str = zrasf_strs[zrasf]; 173 + else 174 + zrasf_str = "reserved"; 175 + 176 + trace_seq_printf(p, "slba=%llu, numd=%u, zra=%u, zrasf=%u:%s, pr=%u", 177 + slba, numd, zra, zrasf, zrasf_str, pr); 178 + trace_seq_putc(p, 0); 179 + 180 + return ret; 181 + } 182 + 122 183 const char *nvmet_trace_parse_nvm_cmd(struct trace_seq *p, 123 184 u8 opcode, u8 *cdw10) 124 185 { ··· 187 126 case nvme_cmd_read: 188 127 case nvme_cmd_write: 189 128 case nvme_cmd_write_zeroes: 129 + case nvme_cmd_zone_append: 190 130 return nvmet_trace_read_write(p, cdw10); 191 131 case nvme_cmd_dsm: 192 132 return nvmet_trace_dsm(p, cdw10); 133 + case nvme_cmd_zone_mgmt_send: 134 + return nvmet_trace_zone_mgmt_send(p, cdw10); 135 + case nvme_cmd_zone_mgmt_recv: 136 + return nvmet_trace_zone_mgmt_recv(p, cdw10); 193 137 default: 194 138 return nvmet_trace_common(p, cdw10); 195 139 } ··· 242 176 return ret; 243 177 } 244 178 179 + static const char *nvmet_trace_fabrics_auth_send(struct trace_seq *p, u8 *spc) 180 + { 181 + const char *ret = trace_seq_buffer_ptr(p); 182 + u8 spsp0 = spc[1]; 183 + u8 spsp1 = spc[2]; 184 + u8 secp = spc[3]; 185 + u32 tl = get_unaligned_le32(spc + 4); 186 + 187 + trace_seq_printf(p, "spsp0=%02x, spsp1=%02x, secp=%02x, tl=%u", 188 + spsp0, spsp1, secp, tl); 189 + trace_seq_putc(p, 0); 190 + return ret; 191 + } 192 + 193 + static const char *nvmet_trace_fabrics_auth_receive(struct trace_seq *p, u8 *spc) 194 + { 195 + const char *ret = trace_seq_buffer_ptr(p); 196 + u8 spsp0 = spc[1]; 197 + u8 spsp1 = spc[2]; 198 + u8 secp = spc[3]; 199 + u32 al = get_unaligned_le32(spc + 4); 200 + 201 + trace_seq_printf(p, "spsp0=%02x, spsp1=%02x, secp=%02x, al=%u", 202 + spsp0, spsp1, secp, al); 203 + trace_seq_putc(p, 0); 204 + return ret; 205 + } 206 + 245 207 static const char *nvmet_trace_fabrics_common(struct trace_seq *p, u8 *spc) 246 208 { 247 209 const char *ret = trace_seq_buffer_ptr(p); ··· 289 195 return nvmet_trace_fabrics_connect(p, spc); 290 196 case nvme_fabrics_type_property_get: 291 197 return nvmet_trace_fabrics_property_get(p, spc); 198 + case nvme_fabrics_type_auth_send: 199 + return nvmet_trace_fabrics_auth_send(p, spc); 200 + case nvme_fabrics_type_auth_receive: 201 + return nvmet_trace_fabrics_auth_receive(p, spc); 292 202 default: 293 203 return nvmet_trace_fabrics_common(p, spc); 294 204 }